Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions named-hosts/matic/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ inputs.nixpkgs.lib.nixosSystem {
# Hardware configuration
./hardware-configuration.nix

# Security/endpoint monitoring
./falcon.nix # CrowdStrike Falcon sensor
./kolide.nix # Kolide launcher with dpkg shim

# Base system configuration
(
{ config, lib, ... }:
Expand Down
96 changes: 96 additions & 0 deletions named-hosts/matic/falcon.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# CrowdStrike Falcon sensor configuration for NixOS
#
# Prerequisites (manual steps):
# 1. Obtain the Falcon sensor .deb from IT
# 2. Create /etc/falcon-sensor.env with: FALCON_CID=<your-cid>
# 3. Extract and place sensor files (see README for details)
#
# Based on: https://gist.github.com/klDen/c90d9798828e31fecbb603f85e27f4f1
{
config,
lib,
pkgs,
...
}:

let
# FHS environment for CrowdStrike Falcon
# NixOS doesn't have standard /opt paths, so we create an FHS-compatible environment
falconFhs = pkgs.buildFHSEnv {
name = "falcon-sensor-fhs";
targetPkgs =
pkgs: with pkgs; [
# Runtime dependencies for Falcon sensor
bash
coreutils
curl
glibc
gnugrep
libnl
openssl
zlib
];
runScript = "/opt/CrowdStrike/falcond";
};
in
{
# Create necessary directories and symlinks for CrowdStrike
systemd.tmpfiles.rules = [
# Create /opt/CrowdStrike directory
"d /opt/CrowdStrike 0770 root root -"
];

# CrowdStrike Falcon sensor service
systemd.services.falcon-sensor = {
description = "CrowdStrike Falcon Sensor";
wantedBy = [ "multi-user.target" ];
after = [
"network.target"
"local-fs.target"
];

# Load the CID from environment file
serviceConfig = {
Type = "forking";
ExecStartPre = pkgs.writeShellScript "falcon-sensor-pre" ''
# Ensure CID is configured
if [ ! -f /etc/falcon-sensor.env ]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

This configuration requires manual management of secrets in /etc/falcon-sensor.env, but this repository already has agenix/sops-nix infrastructure (see named-hosts/SECRETS.md and multiple .age files in named-hosts/). Consider integrating with the existing secrets management system using age.secrets to provide the FALCON_CID, which would be more consistent with the repository's security patterns and enable declarative secret deployment.

Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#724
File: named-hosts/matic/falcon.nix#L48
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
This configuration requires manual management of secrets in /etc/falcon-sensor.env, but this repository already has agenix/sops-nix infrastructure (see named-hosts/SECRETS.md and multiple .age files in named-hosts/). Consider integrating with the existing secrets management system using age.secrets to provide the FALCON_CID, which would be more consistent with the repository's security patterns and enable declarative secret deployment.

echo "ERROR: /etc/falcon-sensor.env not found. Create it with FALCON_CID=<your-cid>"
exit 1
fi

# Source the CID
source /etc/falcon-sensor.env
if [ -z "$FALCON_CID" ]; then
echo "ERROR: FALCON_CID not set in /etc/falcon-sensor.env"
exit 1
fi

# Set the CID if not already set
if ! /opt/CrowdStrike/falconctl -g --cid | grep -q "$FALCON_CID"; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ExecStartPre script uses grep, but gnugrep is not guaranteed to be in the PATH for scripts created with pkgs.writeShellScript. The environment.PATH setting applies to ExecStart, not ExecStartPre. This could cause the service to fail to start if grep is not found. To make the script more robust, you should use an absolute path to the grep binary.

        if ! /opt/CrowdStrike/falconctl -g --cid | ${pkgs.gnugrep}/bin/grep -q "$FALCON_CID"; then

/opt/CrowdStrike/falconctl -s --cid="$FALCON_CID"
fi
'';
ExecStart = "${falconFhs}/bin/falcon-sensor-fhs";
ExecStop = "/bin/kill -TERM $MAINPID";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The ExecStop command kill -TERM $MAINPID is incorrect for a service with Type=forking. When a service forks, the original process that systemd starts ($MAINPID) typically exits, and systemd loses track of the main daemon process unless a PIDFile is specified. The correct way to stop the Falcon sensor is usually via its control utility.

      ExecStop = "/opt/CrowdStrike/falconctl -d";

Copilot AI Feb 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExecStop = "/bin/kill ..." is not portable on NixOS (the repo typically references binaries via ${pkgs.<pkg>}/bin/..., e.g. home-manager/modules/tailscale/default.nix:198). This will likely fail at stop time. Consider removing ExecStop entirely (systemd will SIGTERM the main process by default) or reference a Nix-provided kill implementation explicitly.

Suggested change
ExecStop = "/bin/kill -TERM $MAINPID";
ExecStop = "${pkgs.coreutils}/bin/kill -TERM $MAINPID";

Copilot uses AI. Check for mistakes.
Restart = "on-failure";
Comment on lines +74 to +76

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the falcon.nix file to understand the context
find . -type f -name "falcon.nix" | head -5

Repository: shunkakinoki/dotfiles

Length of output: 95


🏁 Script executed:

# Search for how /bin/kill is typically handled in NixOS repositories
rg "/bin/kill" --type nix -B 2 -A 2 | head -30

Repository: shunkakinoki/dotfiles

Length of output: 737


🏁 Script executed:

# Look for ExecStop patterns in the repository
rg "ExecStop" --type nix -B 1 -A 1 | head -40

Repository: shunkakinoki/dotfiles

Length of output: 909


🌐 Web query:

NixOS systemd ExecStop /bin/kill best practices

💡 Result:

Best practice: don’t use ExecStop=/bin/kill … in most cases

  • If you omit ExecStop=, systemd will stop the service by sending KillSignal= (default SIGTERM) to the service, wait up to TimeoutStopSec=, then (by default) send SIGKILL if it’s still running. This is the normal/expected model. [1][2][3]
  • Instead of running kill yourself, prefer configuring systemd’s native knobs:
    • KillSignal= (e.g. SIGINT if that’s what your daemon expects) [4]
    • TimeoutStopSec= (increase/decrease graceful shutdown time) [2]
    • KillMode= (defaults to control-group, typically what you want so child processes are handled too) [4]
    • SendSIGKILL= / FinalKillSignal= (only if you really need to change the final “hard kill” behavior) [4]

When ExecStop= is appropriate

Use ExecStop= only when the service cannot be stopped correctly by signals alone (e.g., it needs a CLI “shutdown” command, socket command, etc.). Even then, you usually still let systemd do the actual killing if the stop command doesn’t complete in time (via TimeoutStopSec= + default kill behavior). [2][4]

NixOS-specific recommendations

  • Avoid /bin/kill: on NixOS it may not exist or may not be what you expect; prefer either:
    • No ExecStop at all (recommended), plus serviceConfig.KillSignal = ...;, or
    • an explicit store path like ${pkgs.coreutils}/bin/kill / ${pkgs.procps}/bin/pkill if you truly must run a kill command.
  • Prefer systemd options inside systemd.services.<name>.serviceConfig = { ... }; (NixOS passes these through to systemd). The NixOS wiki examples show configuring ExecStart/ExecStop via serviceConfig. [5]

Good NixOS patterns (examples)

1) Typical long-running service: no ExecStop, tune signal/timeout

systemd.services.myDaemon = {
  wantedBy = [ "multi-user.target" ];
  serviceConfig = {
    ExecStart = "${pkgs.myDaemon}/bin/my-daemon";  # should not daemonize
    Type = "simple";
    KillSignal = "SIGTERM";     # or "SIGINT" if that’s what it expects
    TimeoutStopSec = "30s";
    KillMode = "control-group";
  };
};

2) If you truly need a custom stop command

systemd.services.myDaemon = {
  wantedBy = [ "multi-user.target" ];
  serviceConfig = {
    ExecStart = "${pkgs.myDaemon}/bin/my-daemon";
    ExecStop  = "${pkgs.myDaemon}/bin/my-daemon --shutdown";
    TimeoutStopSec = "60s";  # if shutdown is slow
  };
};

Rule of thumb: if you’re reaching for ExecStop=… kill …, first try KillSignal= (and ensure the daemon runs in the foreground so systemd can track it). That’s the “systemd-native” approach. [1][4]

Sources

[1] https://unix.stackexchange.com/questions/737186/how-can-a-service-daemon-shut-down-normally-without-an-execstop-syntax
[2] https://man7.org/linux/man-pages/man5/systemd.service.5%40%40systemd.html
[3] https://unix.stackexchange.com/questions/255438/making-systemctl-to-shutdown-process-gracefully
[4] https://man7.org/linux/man-pages/man5/systemd.kill.5.html
[5] https://wiki.nixos.org/wiki/Systemd/Hardening/en


🏁 Script executed:

# Let's see the full systemd service configuration in falcon.nix
cat -n named-hosts/matic/falcon.nix | sed -n '50,80p'

Repository: shunkakinoki/dotfiles

Length of output: 1143


🏁 Script executed:

# Check if there's any Type configuration that affects how the service stops
rg -A 15 "ExecStart.*falcon-sensor" named-hosts/matic/falcon.nix

Repository: shunkakinoki/dotfiles

Length of output: 1093


Avoid hard‑coding /bin/kill in ExecStop on NixOS.

Line 66 assumes /bin/kill exists, which isn't guaranteed on NixOS. Since the service already has KillMode = "process" configured, omit ExecStop entirely to let systemd handle the graceful SIGTERM shutdown natively (default behavior). If a custom stop command is truly required, use an explicit store path like ${pkgs.coreutils}/bin/kill.

✅ Minimal fix (remove ExecStop)
-      ExecStop = "/bin/kill -TERM $MAINPID";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ExecStart = "${falconFhs}/bin/falcon-sensor-fhs";
ExecStop = "/bin/kill -TERM $MAINPID";
Restart = "on-failure";
ExecStart = "${falconFhs}/bin/falcon-sensor-fhs";
Restart = "on-failure";
🤖 Prompt for AI Agents
In `@named-hosts/matic/falcon.nix` around lines 65 - 67, Remove the hard-coded
ExecStop entry that calls "/bin/kill" and let systemd handle termination via the
existing KillMode = "process" (i.e. delete the ExecStop = "/bin/kill -TERM
$MAINPID"; line), or if you truly need a custom stop command, replace it with
the explicit Nix store path for kill (e.g. use ${pkgs.coreutils}/bin/kill) so
ExecStop references a store path instead of /bin/kill; update the unit block
containing ExecStart = "${falconFhs}/bin/falcon-sensor-fhs"; Restart =
"on-failure"; and KillMode accordingly.

RestartSec = "10s";
KillMode = "process";

# Security hardening

Copilot AI Feb 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment # Security hardening is followed by settings that explicitly disable hardening (ProtectHome = false, ProtectSystem = false, PrivateTmp = false). Either update the comment to reflect that these are compatibility overrides, or adjust the settings so the label matches the configuration.

Suggested change
# Security hardening
# Security hardening compatibility overrides (disabled for sensor requirements)

Copilot uses AI. Check for mistakes.
ProtectHome = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

Disabling all systemd security hardening (ProtectHome, ProtectSystem, PrivateTmp) should be justified with comments explaining why each protection must be disabled. CrowdStrike likely needs system access for EDR functionality, but blanket disabling all protections without documentation makes it difficult to assess if these are truly necessary or could be scoped more narrowly (e.g., ProtectSystem = "strict" with specific writable paths).

Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#724
File: named-hosts/matic/falcon.nix#L72
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
Disabling all systemd security hardening (ProtectHome, ProtectSystem, PrivateTmp) should be justified with comments explaining why each protection must be disabled. CrowdStrike likely needs system access for EDR functionality, but blanket disabling all protections without documentation makes it difficult to assess if these are truly necessary or could be scoped more narrowly (e.g., ProtectSystem = "strict" with specific writable paths).

ProtectSystem = false;
PrivateTmp = false;
Comment on lines +81 to +83

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Disabling systemd's security hardening features (ProtectHome, ProtectSystem, PrivateTmp) significantly weakens the service's sandbox and increases the system's attack surface. While an endpoint security tool might require this level of access, it's a major security trade-off. The comment on line 71, "Security hardening", is also misleading since these settings disable it. The comment should be updated to reflect this, and if possible, more granular permissions should be investigated instead of disabling these protections entirely.

};

# Add required tools to PATH
path = [
pkgs.bash
pkgs.coreutils
pkgs.gnugrep
];
};

# Required kernel modules for Falcon sensor
boot.kernelModules = [ "falcon" ];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High

Loading a custom kernel module 'falcon' without any source, verification, or error handling is a significant security and stability risk. This module isn't defined anywhere in this configuration and must be manually compiled/installed from the CrowdStrike .deb. Consider: 1) Adding a check in ExecStartPre that fails gracefully if the module isn't available, 2) Documenting where this module comes from and how to install it, 3) Adding a commented-out boot.extraModulePackages if there's a way to package it declaratively.

Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#724
File: named-hosts/matic/falcon.nix#L84
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
Loading a custom kernel module 'falcon' without any source, verification, or error handling is a significant security and stability risk. This module isn't defined anywhere in this configuration and must be manually compiled/installed from the CrowdStrike .deb. Consider: 1) Adding a check in ExecStartPre that fails gracefully if the module isn't available, 2) Documenting where this module comes from and how to install it, 3) Adding a commented-out boot.extraModulePackages if there's a way to package it declaratively.

}
120 changes: 120 additions & 0 deletions named-hosts/matic/kolide.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Kolide Launcher configuration for NixOS
#
# Prerequisites (manual steps):
# 1. Obtain the Kolide launcher .deb from IT
# 2. Extract the enrollment secret:
# nix-shell -p dpkg --run 'dpkg-deb -x ~/Downloads/kolide-launcher.deb /tmp/kolide-deb'
# cat /tmp/kolide-deb/etc/kolide-k2/secret
# 3. Install secret to /etc/kolide-k2/secret (root:root, 0600)
#
# The dpkg status shim below satisfies Kolide's osquery deb_packages check
# for CrowdStrike compliance on NixOS (which has no dpkg database).
{
config,
lib,
pkgs,
...
}:

let
# Kolide launcher package (download from company portal)
# This is a placeholder - the actual binary needs to be extracted from the .deb
kolideLauncher = pkgs.stdenv.mkDerivation {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

This creates a non-functional package that just wraps a manually-installed binary. This approach bypasses NixOS's declarative package management and prevents reproducible deployments. Consider: 1) Fetching the .deb file from a private source using fetchurl with a hash, 2) Extracting and patching the binary in the derivation using autoPatchelfHook, or 3) Creating an overlay that properly packages the launcher binary. This would align with NixOS principles and enable 'nixos-rebuild' to fully manage the installation.

Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#724
File: named-hosts/matic/kolide.nix#L17
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
This creates a non-functional package that just wraps a manually-installed binary. This approach bypasses NixOS's declarative package management and prevents reproducible deployments. Consider: 1) Fetching the .deb file from a private source using fetchurl with a hash, 2) Extracting and patching the binary in the derivation using autoPatchelfHook, or 3) Creating an overlay that properly packages the launcher binary. This would align with NixOS principles and enable 'nixos-rebuild' to fully manage the installation.

pname = "kolide-launcher";
version = "1.0.0";

Comment on lines +20 to +25

Copilot AI Feb 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kolideLauncher is defined but never used (the service starts ${kolideFhs} directly and doesn't reference the derivation). This unused derivation adds noise and may mislead readers into thinking it is part of the runtime setup; consider removing it or wiring the service to use the wrapper it produces.

Copilot uses AI. Check for mistakes.
# No source - we expect the binary to be manually installed to /opt/kolide-k2
dontUnpack = true;
dontBuild = true;

installPhase = ''
mkdir -p $out/bin
# Create a wrapper that points to the manually installed binary
cat > $out/bin/kolide-launcher << 'EOF'
#!/bin/sh
exec /opt/kolide-k2/bin/launcher "$@"
EOF
chmod +x $out/bin/kolide-launcher
'';
};
Comment on lines +22 to +39

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The kolideLauncher derivation is defined but never used in this module. The systemd service directly uses the FHS environment created in kolideFhs. This unused code should be removed to improve clarity and maintainability.


# FHS environment for Kolide launcher
kolideFhs = pkgs.buildFHSEnv {
name = "kolide-launcher-fhs";
targetPkgs =
pkgs: with pkgs; [
bash
coreutils
glibc
gnugrep
nodejs
openssl
zlib
];
runScript = "/opt/kolide-k2/bin/launcher";
};
in
{
# dpkg status shim for Kolide/osquery compliance
# NixOS has no dpkg database, so Kolide's osquery deb_packages check fails.
# This shim reports falcon-sensor as "installed" to satisfy the CrowdStrike check.
systemd.tmpfiles.rules = [
# Create dpkg directory
"d /var/lib/dpkg 0755 root root -"
# Create dpkg status file with falcon-sensor entry
"f /var/lib/dpkg/status 0644 root root - Package: falcon-sensor\nStatus: install ok installed\nPriority: optional\nSection: misc\nInstalled-Size: 0\nMaintainer: CrowdStrike\nArchitecture: amd64\nVersion: 7.31.0-18410\nDescription: CrowdStrike Falcon Sensor (shim for Kolide/osquery on NixOS)\n"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The dpkg status shim has a hardcoded version (7.31.0-18410) for the falcon-sensor package. This will become outdated when the Falcon sensor is updated, which could lead to compliance check failures and requires manual intervention to fix. It would be more maintainable to define this version as a variable at the top of the file to make it easier to update.

Comment on lines +61 to +65

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

systemd-tmpfiles "f" rule file content newline escape sequences documentation

💡 Result:

In tmpfiles.d rules, the file “content” for an f / f+ line is the 7th field (Argument), and you cannot put a literal newline in it, because each tmpfiles rule is one line. Newlines must be encoded. (freedesktop.org)

Newlines / escapes in f content

  • tmpfiles.d fields (including the argument text) may contain C-style escape sequences, so you can embed newlines with \n (or \x0a). (freedesktop.org)
  • For current systemd docs, f/F/w argument text is documented as being written as a short string (with a newline behavior described in the man page you’re on), but for multi-line content you should rely on escapes or one of the alternatives below. (freedesktop.org)

Example (two lines of content in one f+ rule):

f+ /etc/myapp/banner.txt 0644 root root - Line1\nLine2\n

If you need arbitrary bytes (including real newlines/NULs): use ~ (Base64)

If you add the ~ modifier, the argument column is Base64-decoded before writing, which is explicitly intended for arbitrary binary data “including newlines and NUL bytes”. (freedesktop.org)

Example:

f~ /etc/myapp/blob.bin 0644 root root - SGVsbG8K V29ybGQK

Alternative for multi-line text: multiple w+ lines

w/w+ write the argument to an existing file; w+ appends, so you can build a file line-by-line. (Docs note w writes without a trailing newline; use explicit \n if you want one.) (mankier.com)

Citations:


Fix newline escaping in the tmpfiles rule for /var/lib/dpkg/status.

Line 58 uses Nix's \n escape sequence, which evaluates to literal newline characters. When systemd-tmpfiles parses the rule, these actual newlines will break the single-line rule format and prevent file creation. According to systemd-tmpfiles documentation, file content must use C-style escape sequences (e.g., \n as two characters) which systemd then interprets. Use \\n in Nix to produce the escape sequences systemd expects.

🛠️ Suggested fix
-    "f /var/lib/dpkg/status 0644 root root - Package: falcon-sensor\nStatus: install ok installed\nPriority: optional\nSection: misc\nInstalled-Size: 0\nMaintainer: CrowdStrike\nArchitecture: amd64\nVersion: 7.31.0-18410\nDescription: CrowdStrike Falcon Sensor (shim for Kolide/osquery on NixOS)\n"
+    "f /var/lib/dpkg/status 0644 root root - ${
+      lib.concatStringsSep "\\n" [
+        "Package: falcon-sensor"
+        "Status: install ok installed"
+        "Priority: optional"
+        "Section: misc"
+        "Installed-Size: 0"
+        "Maintainer: CrowdStrike"
+        "Architecture: amd64"
+        "Version: 7.31.0-18410"
+        "Description: CrowdStrike Falcon Sensor (shim for Kolide/osquery on NixOS)"
+        ""
+      ]
+    }"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
systemd.tmpfiles.rules = [
# Create dpkg directory
"d /var/lib/dpkg 0755 root root -"
# Create dpkg status file with falcon-sensor entry
"f /var/lib/dpkg/status 0644 root root - Package: falcon-sensor\nStatus: install ok installed\nPriority: optional\nSection: misc\nInstalled-Size: 0\nMaintainer: CrowdStrike\nArchitecture: amd64\nVersion: 7.31.0-18410\nDescription: CrowdStrike Falcon Sensor (shim for Kolide/osquery on NixOS)\n"
systemd.tmpfiles.rules = [
# Create dpkg directory
"d /var/lib/dpkg 0755 root root -"
# Create dpkg status file with falcon-sensor entry
"f /var/lib/dpkg/status 0644 root root - ${
lib.concatStringsSep "\\n" [
"Package: falcon-sensor"
"Status: install ok installed"
"Priority: optional"
"Section: misc"
"Installed-Size: 0"
"Maintainer: CrowdStrike"
"Architecture: amd64"
"Version: 7.31.0-18410"
"Description: CrowdStrike Falcon Sensor (shim for Kolide/osquery on NixOS)"
""
]
}"
🤖 Prompt for AI Agents
In `@named-hosts/matic/kolide.nix` around lines 54 - 58, The
systemd.tmpfiles.rules entry that creates "/var/lib/dpkg/status" uses Nix "\n"
which becomes real newlines and will break tmpfiles' single-line rule format;
update the string in systemd.tmpfiles.rules (the rule that starts with "f
/var/lib/dpkg/status") to escape backslashes so C-style escape sequences are
preserved (replace each "\n" with "\\n") so systemd sees literal "\n" characters
in the rule.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

This dpkg status shim hardcodes version '7.31.0-18410' which will immediately become stale. When the actual Falcon sensor is updated (either manually or via the service), this shim will report an incorrect version to Kolide's compliance checks, potentially causing false positives/negatives. Consider: 1) Reading the version dynamically from the actual Falcon installation, 2) Using a variable that can be kept in sync, or 3) Documenting that this needs manual updates when Falcon is upgraded.

Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#724
File: named-hosts/matic/kolide.nix#L58
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
This dpkg status shim hardcodes version '7.31.0-18410' which will immediately become stale. When the actual Falcon sensor is updated (either manually or via the service), this shim will report an incorrect version to Kolide's compliance checks, potentially causing false positives/negatives. Consider: 1) Reading the version dynamically from the actual Falcon installation, 2) Using a variable that can be kept in sync, or 3) Documenting that this needs manual updates when Falcon is upgraded.


Comment on lines +62 to +66

Copilot AI Feb 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tmpfiles rule for /var/lib/dpkg/status embeds literal newlines (via \n) inside a single rule string. When Nix writes the tmpfiles.d file, this becomes multiple lines; only the first line starts with a tmpfiles directive, and the following lines (e.g. Status: ...) will be parsed as invalid tmpfiles entries, likely causing systemd-tmpfiles failures at boot/activation. Write the status file via a tmpfiles C (copy) rule from a pkgs.writeText file, or generate the file in an activation/script step, so the tmpfiles rules remain single-line entries.

Copilot uses AI. Check for mistakes.
# Create Kolide directories
"d /etc/kolide-k2 0755 root root -"
"d /opt/kolide-k2 0755 root root -"
"d /var/kolide-k2 0755 root root -"
];

# Kolide Launcher service
systemd.services.kolide-launcher = {
description = "Kolide Launcher";
wantedBy = [ "multi-user.target" ];
after = [
"network.target"
"local-fs.target"
];

serviceConfig = {
Type = "simple";
ExecStartPre = pkgs.writeShellScript "kolide-launcher-pre" ''
# Ensure enrollment secret exists
if [ ! -f /etc/kolide-k2/secret ]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

The Kolide enrollment secret should be managed via the repository's existing agenix/sops-nix secrets infrastructure rather than requiring manual file placement. This would: 1) Enable declarative secret management, 2) Provide proper encryption at rest in the git repository, 3) Follow the established pattern used elsewhere in this dotfiles repo (see named-hosts/SECRETS.md). Consider using age.secrets.kolide-enrollment-secret similar to how other secrets are managed.

Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#724
File: named-hosts/matic/kolide.nix#L76
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
The Kolide enrollment secret should be managed via the repository's existing agenix/sops-nix secrets infrastructure rather than requiring manual file placement. This would: 1) Enable declarative secret management, 2) Provide proper encryption at rest in the git repository, 3) Follow the established pattern used elsewhere in this dotfiles repo (see named-hosts/SECRETS.md). Consider using age.secrets.kolide-enrollment-secret similar to how other secrets are managed.

echo "ERROR: /etc/kolide-k2/secret not found."
echo "Extract from company .deb and install with:"
echo " sudo install -d -m 755 /etc/kolide-k2"
echo " sudo sh -c 'cat <secret> > /etc/kolide-k2/secret'"
echo " sudo chown root:root /etc/kolide-k2/secret"
echo " sudo chmod 600 /etc/kolide-k2/secret"
exit 1
Comment on lines +84 to +93

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Enforce secure permissions for the enrollment secret before starting.
Line 75‑83 only checks for existence; if the secret is world-readable, the service still starts. Fail fast unless owner is root and mode is 0600.

🔐 Suggested fix
         if [ ! -f /etc/kolide-k2/secret ]; then
           echo "ERROR: /etc/kolide-k2/secret not found."
           echo "Extract from company .deb and install with:"
           echo "  sudo install -d -m 755 /etc/kolide-k2"
           echo "  sudo sh -c 'cat <secret> > /etc/kolide-k2/secret'"
           echo "  sudo chown root:root /etc/kolide-k2/secret"
           echo "  sudo chmod 600 /etc/kolide-k2/secret"
           exit 1
         fi
+
+        # Enforce secure permissions on enrollment secret
+        if [ "$(stat -c '%a' /etc/kolide-k2/secret)" != "600" ] || \
+           [ "$(stat -c '%U:%G' /etc/kolide-k2/secret)" != "root:root" ]; then
+          echo "ERROR: /etc/kolide-k2/secret must be root:root with 0600 permissions."
+          exit 1
+        fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ExecStartPre = pkgs.writeShellScript "kolide-launcher-pre" ''
# Ensure enrollment secret exists
if [ ! -f /etc/kolide-k2/secret ]; then
echo "ERROR: /etc/kolide-k2/secret not found."
echo "Extract from company .deb and install with:"
echo " sudo install -d -m 755 /etc/kolide-k2"
echo " sudo sh -c 'cat <secret> > /etc/kolide-k2/secret'"
echo " sudo chown root:root /etc/kolide-k2/secret"
echo " sudo chmod 600 /etc/kolide-k2/secret"
exit 1
ExecStartPre = pkgs.writeShellScript "kolide-launcher-pre" ''
# Ensure enrollment secret exists
if [ ! -f /etc/kolide-k2/secret ]; then
echo "ERROR: /etc/kolide-k2/secret not found."
echo "Extract from company .deb and install with:"
echo " sudo install -d -m 755 /etc/kolide-k2"
echo " sudo sh -c 'cat <secret> > /etc/kolide-k2/secret'"
echo " sudo chown root:root /etc/kolide-k2/secret"
echo " sudo chmod 600 /etc/kolide-k2/secret"
exit 1
fi
# Enforce secure permissions on enrollment secret
if [ "$(stat -c '%a' /etc/kolide-k2/secret)" != "600" ] || \
[ "$(stat -c '%U:%G' /etc/kolide-k2/secret)" != "root:root" ]; then
echo "ERROR: /etc/kolide-k2/secret must be root:root with 0600 permissions."
exit 1
fi
🤖 Prompt for AI Agents
In `@named-hosts/matic/kolide.nix` around lines 74 - 83, The pre-start script
currently only checks for existence of /etc/kolide-k2/secret; update
ExecStartPre (kolide-launcher-pre) to also verify the file is owned by root (UID
0) and has mode 0600, and fail if not. Specifically, after the existence check,
call stat to read the file owner UID and permission bits and if owner != 0 or
permissions != 600, print a clear error explaining the required owner/mode and
exit 1; keep the message referencing /etc/kolide-k2/secret and the script name
kolide-launcher-pre so the check is easy to locate.

fi

# Ensure launcher binary exists
if [ ! -x /opt/kolide-k2/bin/launcher ]; then
echo "ERROR: /opt/kolide-k2/bin/launcher not found."
echo "Extract from company .deb and install to /opt/kolide-k2/"
exit 1
fi
'';
ExecStart = "${kolideFhs}/bin/kolide-launcher-fhs --enroll_secret_path=/etc/kolide-k2/secret --root_directory=/var/kolide-k2";
Restart = "on-failure";
RestartSec = "10s";

# Kolide needs access to system information
ProtectHome = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Medium

Similar to Falcon, all systemd security hardening is disabled without justification. Add comments explaining why Kolide requires each of these protections to be disabled, or scope them more narrowly if possible. For example, if Kolide only needs read access to /home, consider 'ProtectHome = "read-only"' instead of false.

Fix in Cursor • Fix in Claude

Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: shunkakinoki/dotfiles#724
File: named-hosts/matic/kolide.nix#L98
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.

Feedback:
Similar to Falcon, all systemd security hardening is disabled without justification. Add comments explaining why Kolide requires each of these protections to be disabled, or scope them more narrowly if possible. For example, if Kolide only needs read access to /home, consider 'ProtectHome = "read-only"' instead of false.

ProtectSystem = false;
PrivateTmp = false;
Comment on lines +107 to +110

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to the Falcon service, systemd's security hardening features (ProtectHome, ProtectSystem, PrivateTmp) are disabled here. While the comment provides a reason, this still represents a significant security risk by weakening the service's sandbox. If possible, consider using more granular permissions (e.g., ReadWritePaths with ProtectSystem=strict) instead of disabling these protections entirely to limit the service's access to only what is necessary.

};

# Add required tools to PATH
path = [
pkgs.bash
pkgs.coreutils
pkgs.gnugrep
];
};
}
Loading