From 679c3f43543e462c1cd4d2cf2a899aa11852de1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Motiejus=20Jak=C5=A1tys?= Date: Mon, 17 Nov 2025 09:26:08 +0000 Subject: [PATCH] s1 Thanks to https://github.com/devusb/sentinelone-nix --- flake.nix | 10 +- modules/services/default.nix | 1 + modules/services/sentinelone/default.nix | 184 +++++++++++++++++++++++ pkgs/sentinelone/default.nix | 58 +++++++ 4 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 modules/services/sentinelone/default.nix create mode 100644 pkgs/sentinelone/default.nix diff --git a/flake.nix b/flake.nix index be9818f..5006b4d 100644 --- a/flake.nix +++ b/flake.nix @@ -104,8 +104,9 @@ weather = super.callPackage ./pkgs/weather { }; nicer = super.callPackage ./pkgs/nicer.nix { }; tmuxbash = super.callPackage ./pkgs/tmuxbash.nix { }; - vanta-agent = super.callPackage ./pkgs/vanta-agent.nix { }; + sentinelone = super.callPackage ./pkgs/sentinelone { }; chronoctl = super.callPackage ./pkgs/chronoctl.nix { }; + vanta-agent = super.callPackage ./pkgs/vanta-agent.nix { }; gcloud-wrapped = super.callPackage ./pkgs/gcloud-wrapped { }; go-raceless = super.callPackage ./pkgs/go-raceless { }; @@ -359,7 +360,12 @@ in { packages.x86_64-linux = { - inherit (pkgs) weather gamja chronoctl; + inherit (pkgs) + weather + gamja + chronoctl + sentinelone + ; }; } ); diff --git a/modules/services/default.nix b/modules/services/default.nix index a2c2472..0b89be0 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -19,6 +19,7 @@ ./ping_exporter ./postfix ./printing + ./sentinelone ./ssh8022 ./syncthing ./syncthing-relay diff --git a/modules/services/sentinelone/default.nix b/modules/services/sentinelone/default.nix new file mode 100644 index 0000000..7ae79bc --- /dev/null +++ b/modules/services/sentinelone/default.nix @@ -0,0 +1,184 @@ +{ + lib, + pkgs, + config, + ... +}: +with lib; +let + cfg = config.services.sentinelone; + customerId = + cfg.customerId or ( + if cfg.email != null && cfg.serialNumber != null then "${cfg.email}-${cfg.serialNumber}" else null + ); + hasCustomerId = customerId != null; + initScript = pkgs.writeShellScriptBin "sentinelone-init.sh" '' + #!/bin/bash + + mkdir -p ${cfg.dataDir} + + # initialize the data directory + if [ -z "$(ls -A ${cfg.dataDir} 2>/dev/null)" ]; then + find "${cfg.package}/opt/sentinelone/" -mindepth 1 -maxdepth 1 ! -name "bin" ! -name "ebpfs" ! -name "lib" ! -name "ranger" -exec cp -r {} "${cfg.dataDir}/" \; + + cat << EOF > ${cfg.dataDir}/configuration/install_config + S1_AGENT_MANAGEMENT_TOKEN=$(cat ${cfg.sentinelOneManagementTokenPath}) + S1_AGENT_DEVICE_TYPE=desktop + S1_AGENT_AUTO_START=true + ${optionalString hasCustomerId "S1_AGENT_CUSTOMER_ID=${customerId}"} + EOF + + cat << EOF > ${cfg.dataDir}/configuration/installation_params.json + { + "PACKAGE_TYPE": "deb", + "SERVICE_TYPE": "systemd" + } + EOF + siteKey=$(cat ${cfg.sentinelOneManagementTokenPath} | base64 -d | ${getExe pkgs.jq} .site_key) + mgmtUrl=$(cat ${cfg.sentinelOneManagementTokenPath} | base64 -d | ${getExe pkgs.jq} .url) + cat << EOF > ${cfg.dataDir}/configuration/basic.conf + { + "mgmt_device-type": 1, + "mgmt_site-key": $siteKey, + "mgmt_url": $mgmtUrl + } + EOF + + chown -R sentinelone:sentinelone ${cfg.dataDir} + chmod -R 0755 $(find ${cfg.dataDir} -group sentinelone) + fi + ''; +in +{ + options = { + services = { + sentinelone = { + enable = mkEnableOption "SentinelOne Service"; + package = mkPackageOption pkgs "sentinelone" { }; + + customerId = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Set a customer specific identifier for the host. It is common practice to set this as your email and serial number separated by a hyphen. + ''; + example = "me@gmail.com-FTXYZWW"; + }; + email = mkOption { + type = types.nullOr types.str; + default = null; + example = "me@gmail.com"; + }; + serialNumber = mkOption { + type = types.nullOr types.str; + default = null; + example = "FTXYZWW"; + }; + sentinelOneManagementTokenPath = mkOption { + type = types.path; + example = "/run/secrets/s1_mgmt_token"; + }; + dataDir = mkOption { + type = types.path; + default = "/var/lib/sentinelone"; + }; + }; + }; + }; + + config = mkIf cfg.enable { + warnings = + optional (cfg.email != null) "services.sentinelone.email is deprecated in favour of customerId." + ++ optional ( + cfg.serialNumber != null + ) "services.sentinelone.serialNumber is deprecated in favour of customerId."; + + assertions = [ + { + assertion = (cfg.customerId != null) -> (cfg.email == null && cfg.serialNumber == null); + message = '' + You cannot use services.sentinelone.customerId with the deprecated services.sentinelone.email and services.sentinelone.serialNumber options. + ''; + } + { + assertion = (cfg.email != null) -> (cfg.serialNumber != null); + message = '' + services.sentinelone.email requires services.sentinelone.serialNumber to also be set. + ''; + } + { + assertion = (cfg.serialNumber != null) -> (cfg.email != null); + message = '' + services.sentinelone.serialNumber requires services.sentinelone.email to also be set. + ''; + } + ]; + + users.users.sentinelone = { + isSystemUser = true; + createHome = true; + shell = "${pkgs.shadow}/bin/nologin"; + group = "sentinelone"; + }; + users.groups.sentinelone = { }; + + systemd.services.sentinelone-init = { + wantedBy = [ "sentinelone.service" ]; + before = [ "sentinelone.service" ]; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${getExe initScript}"; + }; + }; + + environment.systemPackages = [ + cfg.package + ]; + + systemd.services.sentinelone = { + enable = true; + description = "SentinelOne"; + path = [ + pkgs.coreutils-full + pkgs.gawk + pkgs.zlib + pkgs.libelf + pkgs.bash + ]; + unitConfig = { + Description = "SentinelOne"; + After = [ + "uptrack-prefetch.service" + "uptrack.service" + ]; + StartLimitInterval = "90"; + StartLimitBurst = "4"; + }; + serviceConfig = { + Type = "forking"; + ExecStart = "${cfg.package}/bin/sentinelctl control run"; + WorkingDirectory = "/opt/sentinelone/bin"; + SyslogIdentifier = "${cfg.dataDir}/log"; + WatchdogSec = "5s"; + Restart = "always"; + RestartSec = "4"; + RefuseManualStop = "yes"; + MemoryMax = "18446744073709543424"; + ExecStop = "${cfg.package}/bin/sentinelctl control shutdown"; + NotifyAccess = "all"; + KillMode = "process"; + TasksMax = "infinity"; + BindPaths = [ + "${cfg.dataDir}:/opt/sentinelone" + ]; + BindReadOnlyPaths = [ + "${cfg.package}/opt/sentinelone/bin:/opt/sentinelone/bin" + "${cfg.package}/opt/sentinelone/ebpfs:/opt/sentinelone/ebpfs" + "${cfg.package}/opt/sentinelone/lib:/opt/sentinelone/lib" + "${cfg.package}/opt/sentinelone/ranger:/opt/sentinelone/ranger" + ]; + }; + wantedBy = [ "multi-user.target" ]; + }; + }; +} diff --git a/pkgs/sentinelone/default.nix b/pkgs/sentinelone/default.nix new file mode 100644 index 0000000..862a539 --- /dev/null +++ b/pkgs/sentinelone/default.nix @@ -0,0 +1,58 @@ +{ + stdenv, + fetchurl, + dpkg, + autoPatchelfHook, + zlib, + elfutils, + dmidecode, + jq, + gcc-unwrapped, +}: +let + sentinelOnePackage = "SentinelAgent_linux_x86_64_v25_2_2_14.deb"; +in +stdenv.mkDerivation { + pname = "sentinelone"; + version = "25.2.2.14"; + + src = fetchurl { + url = "http://hdd.jakstys.lt/Motiejaus/${sentinelOnePackage}"; + hash = "sha256-ZWtuJ/ua2roIz2I/4CicnVXlc1Sj5w/r412pS5KfmOA="; + }; + + unpackPhase = '' + runHook preUnpack + + dpkg-deb -x $src . + + runHook postUnpack + ''; + + nativeBuildInputs = [ + dpkg + autoPatchelfHook + zlib + elfutils + dmidecode + jq + gcc-unwrapped + ]; + + installPhase = '' + mkdir -p $out/opt/ + mkdir -p $out/cfg/ + mkdir -p $out/bin/ + + cp -r opt/* $out/opt + + ln -s $out/opt/sentinelone/bin/sentinelctl $out/bin/sentinelctl + ln -s $out/opt/sentinelone/bin/sentinelone-agent $out/bin/sentinelone-agent + ln -s $out/opt/sentinelone/bin/sentinelone-watchdog $out/bin/sentinelone-watchdog + ln -s $out/opt/sentinelone/lib $out/lib + ''; + + preFixup = '' + patchelf --replace-needed libelf.so.0 libelf.so $out/opt/sentinelone/lib/libbpf.so + ''; +}