feat(security): add CrowdStrike Falcon and Kolide to matic host - #724
Conversation
Summary of ChangesHello @shunkakinoki, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the security posture of the Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
📝 WalkthroughWalkthroughAdded two NixOS modules to the matic host: Changes
Sequence Diagram(s)sequenceDiagram
participant system as Systemd
participant tmp as Filesystem/tmpfiles
participant env as /etc/falcon-sensor.env
participant falconctl as falconctl
participant sensor as falcon-sensor-fhs
system->>tmp: Ensure /opt/CrowdStrike exists (tmpfiles)
system->>env: Read /etc/falcon-sensor.env
alt FALCON_CID missing
system->>falconctl: falconctl -s --cid=<FALCON_CID>
falconctl-->>system: initialize CID
end
system->>sensor: ExecStart -> run FHS sensor binary
sensor-->>system: service running
sequenceDiagram
participant system as Systemd
participant tmp as Filesystem/tmpfiles
participant secret as /etc/kolide-k2/secret
participant launcher as /opt/kolide-k2/bin/launcher
participant kolide as kolide-launcher-fhs
system->>tmp: Create /etc/kolide-k2, /opt/kolide-k2, fake dpkg/status
system->>secret: Check secret exists
alt secret or launcher missing
system-->>system: ExecStartPre fails -> error message guiding manual install
else
system->>launcher: Check launcher binary exists
system->>kolide: ExecStart -> run kolide-launcher-fhs with secret
kolide-->>system: service running
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Mesa DescriptionTL;DRAdded CrowdStrike Falcon and Kolide Launcher to the What changed?
Description generated by Mesa. Update settings |
There was a problem hiding this comment.
Code Review
This pull request introduces configurations for CrowdStrike Falcon and Kolide to enhance endpoint security on the NixOS host. The use of FHS environments is a suitable approach for integrating this type of proprietary software into NixOS. However, the current implementation has several critical and high-severity issues. The Falcon service's stop command is likely incorrect, which could prevent it from shutting down gracefully. Both new services disable fundamental systemd security hardening features, creating significant security risks that need to be acknowledged and justified. I've also identified some medium-severity maintainability concerns, including a potential script failure due to a missing dependency path, unused code, and a hardcoded version number that will require manual updates in the future. My review includes specific suggestions to address these points.
| fi | ||
| ''; | ||
| ExecStart = "${falconFhs}/bin/falcon-sensor-fhs"; | ||
| ExecStop = "/bin/kill -TERM $MAINPID"; |
There was a problem hiding this comment.
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";
| ProtectHome = false; | ||
| ProtectSystem = false; | ||
| PrivateTmp = false; |
There was a problem hiding this comment.
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.
| # Kolide needs access to system information | ||
| ProtectHome = false; | ||
| ProtectSystem = false; | ||
| PrivateTmp = false; |
There was a problem hiding this comment.
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.
| fi | ||
|
|
||
| # Set the CID if not already set | ||
| if ! /opt/CrowdStrike/falconctl -g --cid | grep -q "$FALCON_CID"; then |
There was a problem hiding this comment.
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
| kolideLauncher = pkgs.stdenv.mkDerivation { | ||
| pname = "kolide-launcher"; | ||
| version = "1.0.0"; | ||
|
|
||
| # 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 | ||
| ''; | ||
| }; |
| # 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" |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Pull request overview
Adds endpoint security/monitoring configuration to the matic NixOS host by introducing CrowdStrike Falcon sensor and Kolide Launcher modules and importing them into the host’s module list.
Changes:
- Added
falcon.nixto run CrowdStrike Falcon sensor via an FHS environment and systemd service. - Added
kolide.nixto run Kolide Launcher via an FHS environment and systemd service, plus a dpkg status shim. - Imported both modules into
named-hosts/matic/default.nix.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| named-hosts/matic/kolide.nix | Adds Kolide launcher service and tmpfiles rules (including dpkg status shim). |
| named-hosts/matic/falcon.nix | Adds Falcon sensor service and tmpfiles rule for /opt/CrowdStrike. |
| named-hosts/matic/default.nix | Imports the new Falcon and Kolide modules into the matic host. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # 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" | ||
|
|
There was a problem hiding this comment.
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.
| # 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 { | ||
| pname = "kolide-launcher"; | ||
| version = "1.0.0"; | ||
|
|
There was a problem hiding this comment.
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.
| fi | ||
| ''; | ||
| ExecStart = "${falconFhs}/bin/falcon-sensor-fhs"; | ||
| ExecStop = "/bin/kill -TERM $MAINPID"; |
There was a problem hiding this comment.
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.
| ExecStop = "/bin/kill -TERM $MAINPID"; | |
| ExecStop = "${pkgs.coreutils}/bin/kill -TERM $MAINPID"; |
| RestartSec = "10s"; | ||
| KillMode = "process"; | ||
|
|
||
| # Security hardening |
There was a problem hiding this comment.
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.
| # Security hardening | |
| # Security hardening compatibility overrides (disabled for sensor requirements) |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@named-hosts/matic/falcon.nix`:
- Around line 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.
In `@named-hosts/matic/kolide.nix`:
- Around line 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.
- Around line 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.
| ExecStart = "${falconFhs}/bin/falcon-sensor-fhs"; | ||
| ExecStop = "/bin/kill -TERM $MAINPID"; | ||
| Restart = "on-failure"; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the falcon.nix file to understand the context
find . -type f -name "falcon.nix" | head -5Repository: 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 -30Repository: shunkakinoki/dotfiles
Length of output: 737
🏁 Script executed:
# Look for ExecStop patterns in the repository
rg "ExecStop" --type nix -B 1 -A 1 | head -40Repository: 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 sendingKillSignal=(defaultSIGTERM) to the service, wait up toTimeoutStopSec=, then (by default) sendSIGKILLif it’s still running. This is the normal/expected model. [1][2][3] - Instead of running
killyourself, prefer configuring systemd’s native knobs:KillSignal=(e.g.SIGINTif that’s what your daemon expects) [4]TimeoutStopSec=(increase/decrease graceful shutdown time) [2]KillMode=(defaults tocontrol-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
ExecStopat all (recommended), plusserviceConfig.KillSignal = ...;, or - an explicit store path like
${pkgs.coreutils}/bin/kill/${pkgs.procps}/bin/pkillif you truly must run a kill command.
- No
- Prefer systemd options inside
systemd.services.<name>.serviceConfig = { ... };(NixOS passes these through to systemd). The NixOS wiki examples show configuringExecStart/ExecStopviaserviceConfig. [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.nixRepository: 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.
| 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.
| 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" |
There was a problem hiding this comment.
🧩 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.dfields (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/wargument 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\nIf 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 V29ybGQKAlternative 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:
- 1: https://www.freedesktop.org/software/systemd/man/249/tmpfiles.d.html?utm_source=openai
- 2: https://www.freedesktop.org/software/systemd/man/249/tmpfiles.d.html?utm_source=openai
- 3: https://www.freedesktop.org/software/systemd/man/252/tmpfiles.d.html?utm_source=openai
- 4: https://www.freedesktop.org/software/systemd/man/devel/tmpfiles.d.html?utm_source=openai
- 5: https://www.mankier.com/5/tmpfiles.d?utm_source=openai
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.
| 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.
| 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 |
There was a problem hiding this comment.
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.
| 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.
There was a problem hiding this comment.
Performed full review of 8b931d0...bfcc59a
Analysis
-
Manual Installation Anti-Pattern - Both security modules require manual binary extraction to
/opt, contradicting NixOS's declarative philosophy and creating configuration drift potential, lack of reproducibility, and deployment complexity. -
Insecure Secrets Management - Secrets are stored in plaintext files without integration into the repository's existing secrets management (agenix/sops-nix), bypassing established security patterns.
-
Security Hardening Disabled - Both services disable multiple systemd security features (
ProtectHome,ProtectSystem,PrivateTmp) without proper justification, creating potential security vulnerabilities. -
Kernel Module Risk - The falcon.nix requires loading a custom kernel module without verification or source, posing significant security and stability risks.
-
dpkg Status Shim as Technical Debt - The fake dpkg database in kolide.nix creates misleading system state, may break with updates, and establishes a poor precedent for shimming system state rather than proper integration.
Tip
Help
Slash Commands:
/review- Request a full code review/review latest- Review only changes since the last review/describe- Generate PR description. This will update the PR body or issue comment depending on your configuration/help- Get help with Mesa commands and configuration options
0 files reviewed | 7 comments | Edit Agent Settings • Read Docs
| }; | ||
|
|
||
| # Required kernel modules for Falcon sensor | ||
| boot.kernelModules = [ "falcon" ]; |
There was a problem hiding this comment.
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.
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.
| KillMode = "process"; | ||
|
|
||
| # Security hardening | ||
| ProtectHome = false; |
There was a problem hiding this comment.
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).
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).
| Type = "forking"; | ||
| ExecStartPre = pkgs.writeShellScript "falcon-sensor-pre" '' | ||
| # Ensure CID is configured | ||
| if [ ! -f /etc/falcon-sensor.env ]; then |
There was a problem hiding this comment.
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.
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.
| # 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" |
There was a problem hiding this comment.
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.
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.
| RestartSec = "10s"; | ||
|
|
||
| # Kolide needs access to system information | ||
| ProtectHome = false; |
There was a problem hiding this comment.
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.
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.
| Type = "simple"; | ||
| ExecStartPre = pkgs.writeShellScript "kolide-launcher-pre" '' | ||
| # Ensure enrollment secret exists | ||
| if [ ! -f /etc/kolide-k2/secret ]; then |
There was a problem hiding this comment.
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.
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.
| 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 { |
There was a problem hiding this comment.
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.
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.
Changes
falcon.nix) for endpoint detection and responsekolide.nix) with dpkg shim for NixOS compatibilityTechnical Details
/var/lib/dpkg/statusshim to satisfy CrowdStrike compliance checks on NixOSTesting
Generated with OpenCode by Claude
Summary by cubic
Add CrowdStrike Falcon and Kolide Launcher to the matic NixOS host to enable endpoint detection and compliance monitoring. Uses FHS environments and a dpkg status shim for NixOS compatibility.
Written for commit 94939cb. Summary will update on new commits.