From 18651e75ef03880feb6a1c2ef33eda7563e77bbc Mon Sep 17 00:00:00 2001 From: Josh Drake Date: Mon, 27 Jul 2026 12:22:59 -0500 Subject: [PATCH 1/4] Document NixOS as a supported OS for the Smallstep Agent NixOS is now a supported OS for the agent, but the nixpkgs package ships only the binary. Everything the .deb/.rpm postinst does -- system user, systemd unit, tmpfiles, polkit, tss group, p11-kit module registration -- has to be declared by hand, because nixpkgs has no services.step-agent module yet (OFF-2). Add NixOS to the supported-OS list and a NixOS section under Manual install carrying the equivalent configuration, ported field-for-field from agent/extra/. Also note the NixOS deltas in Start the agent, the Chrome PKCS#11 example, Uninstall, and the troubleshooting reference. Two limitations stated plainly: the package is on nixos-unstable only (it missed the 26.05 branch-off), and hosts without a hardware TPM cannot enroll, since the swtpm helper scripts are not packaged. The Nix config was verified to evaluate against nixos-unstable and to render a step-agent.service matching agent/extra/step-agent.service. It has not been runtime-tested on a NixOS host. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01KSuffpV7e9tawW249FA7gN --- platform/smallstep-agent.mdx | 181 ++++++++++++++++++++++++++++- platform/troubleshooting-agent.mdx | 7 +- 2 files changed, 186 insertions(+), 2 deletions(-) diff --git a/platform/smallstep-agent.mdx b/platform/smallstep-agent.mdx index 284482fd..d8ae255a 100644 --- a/platform/smallstep-agent.mdx +++ b/platform/smallstep-agent.mdx @@ -1,5 +1,5 @@ --- -updated_at: June 9, 2026 +updated_at: July 27, 2026 title: Install the Smallstep Agent html_title: Install the Smallstep Agent on macOS, Windows, and Linux description: Install, configure, and deploy the Smallstep Agent on macOS, Windows, and Linux endpoints. Includes manual install, MDM integration, system requirements, and network endpoints. @@ -47,6 +47,7 @@ Running into trouble? See the [Smallstep Agent troubleshooting guide](./troubles - Ubuntu (Current Stable and LTS) - Debian (Current Releases) - Fedora (Current Releases) + - NixOS - `systemd`-based service manager - A TPM 2.0 module is required. Smallstep depends on TPMs to create a high-assurance device inventory. - `p11-kit`, `tpm-tss2` @@ -284,6 +285,177 @@ curl -fsSL https://packages.smallstep.com/scripts/smallstep-agent-install.sh | s ``` +### NixOS + +The [`step-agent`](https://search.nixos.org/packages?query=step-agent) package is in nixpkgs, on the `nixos-unstable` channel. +NixOS has no `services.step-agent` module yet, +so the system user, systemd service, and PKCS#11 wiring that the Debian and RPM packages install are declared in your own configuration instead. + + +
+The agent requires a hardware TPM 2.0 on NixOS. +The Debian and RPM packages fall back to a software TPM on hosts without one, +but the helper scripts that set that up are not part of the nixpkgs package, +so a host with no /dev/tpmrm0 cannot enroll yet. +
+
+ +1. If you track a stable NixOS channel, add an overlay so that `pkgs.step-agent` resolves. + Skip this step on `nixos-unstable`. + + ```nix + nixpkgs.overlays = [ + (final: prev: { + inherit + (import (builtins.fetchTarball "https://github.com/NixOS/nixpkgs/archive/nixos-unstable.tar.gz") { + system = prev.stdenv.hostPlatform.system; + config.allowUnfreePredicate = pkg: prev.lib.getName pkg == "step-agent"; + }) + step-agent + ; + }) + ]; + ``` + +2. Save the following as `step-agent.nix` alongside your `configuration.nix`, + and add `./step-agent.nix` to its `imports` list: + + ```nix + { config, lib, pkgs, ... }: + + { + # The step-agent package is unfree. + nixpkgs.config.allowUnfreePredicate = pkg: lib.getName pkg == "step-agent"; + + environment.systemPackages = [ pkgs.step-agent ]; + + # The agent talks to the TPM from user space, so it needs read/write access + # to the TPM resource manager. This creates the tss group and the udev rules + # that grant that group /dev/tpmrm0. + security.tpm2.enable = true; + + users.groups.step-agent = { }; + users.users.step-agent = { + isSystemUser = true; + group = "step-agent"; + home = "/var/lib/step-agent"; + extraGroups = [ "tss" ]; + }; + + # /run/step-agent holds the PKCS#11 and SSH sockets that other users connect + # to. Create it with tmpfiles rather than systemd's RuntimeDirectory=, which + # deletes the directory every time the service stops. + systemd.tmpfiles.rules = [ + "d /run/step-agent 0755 step-agent step-agent - -" + ]; + + systemd.services.step-agent = { + description = "Smallstep Agent"; + documentation = [ "https://u.step.sm/docs/agent" ]; + after = [ "network-online.target" ]; + requires = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + # The agent starts once the device is registered and agent.yaml exists. + unitConfig.ConditionPathIsReadWrite = "/etc/step-agent/agent.yaml"; + + environment = { + HOME = "/var/lib/step-agent"; + RUNTIME_DIRECTORY = "/run/step-agent"; + }; + + serviceConfig = { + Type = "notify"; + WatchdogSec = "60s"; + ExecStart = "${lib.getExe pkgs.step-agent} start"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + User = "step-agent"; + Group = "step-agent"; + ConfigurationDirectory = "step-agent"; + StateDirectory = "step-agent"; + Restart = "always"; + RestartSec = 10; + + ProtectSystem = true; + ProtectHome = "read-only"; + PrivateTmp = true; + SecureBits = "keep-caps"; + AmbientCapabilities = [ "CAP_IPC_LOCK" "CAP_CHOWN" "CAP_DAC_OVERRIDE" "CAP_FOWNER" ]; + CapabilityBoundingSet = [ "CAP_SYSLOG" "CAP_IPC_LOCK" "CAP_CHOWN" "CAP_DAC_OVERRIDE" "CAP_FOWNER" ]; + DeviceAllow = [ "/dev/tpmrm0 rw" ]; + ReadWritePaths = [ "-/dev/tpmrm0" ]; + + LimitNOFILE = 65536; + LimitMEMLOCK = "infinity"; + }; + }; + + # Restart the agent when its configuration changes, such as after registering. + systemd.paths.step-agent-restart = { + wantedBy = [ "multi-user.target" ]; + pathConfig.PathChanged = "/etc/step-agent/agent.yaml"; + }; + + systemd.services.step-agent-restart.serviceConfig = { + Type = "oneshot"; + ExecStart = "${config.systemd.package}/bin/systemctl restart step-agent.service"; + }; + + # Let the agent restart units and manage NetworkManager connections. + security.polkit.enable = true; + security.polkit.extraConfig = '' + polkit.addRule(function(action, subject) { + if (subject.user == "step-agent") { + if (action.id == "org.freedesktop.systemd1.manage-units") { + return polkit.Result.YES; + } + if (action.id.indexOf("org.freedesktop.NetworkManager.") == 0) { + return polkit.Result.YES; + } + } + }); + ''; + + # Publish the agent's PKCS#11 server to p11-kit clients. The module path has + # to be explicit: the agent searches FHS locations that do not exist on NixOS. + environment.etc."pkcs11/modules/step-agent.module".text = '' + module: ${pkgs.p11-kit}/lib/pkcs11/p11-kit-client.so + server-address: unix:path=/run/step-agent/step-agent-pkcs11.sock + ''; + } + ``` + +3. Rebuild your system: + + ```bash + sudo nixos-rebuild switch + ``` + +4. Register the device with your team: + + ```bash + sudo step-agent register [team name] + ``` + + Registration writes `agent.yaml` into `/etc/step-agent`, + which systemd creates and keeps writable through `ConfigurationDirectory=`. + Do not manage `agent.yaml` with `environment.etc`: + that produces a read-only symlink into the Nix store, and the service refuses to start. + +5. Check that it was installed correctly: + + ```bash + step-agent version + ``` + + Output: + + ```bash + step-agent/0.67.3 (linux/amd64) + Release Date: 2026-05-19 15:50 UTC + ``` + + ## Registering and approving endpoints ### Self-registration @@ -327,6 +499,8 @@ sudo systemctl enable --now step-agent sudo systemctl enable --now step-agent-restart.path ``` +On NixOS, `nixos-rebuild switch` enables and starts both units, so skip this step. + If you get any errors, check the agent’s status: ```bash @@ -355,6 +529,9 @@ modutil -dbdir ~/.pki/nssdb -add step-agent \ export P11_KIT_SERVER_ADDRESS=unix:path=$XDG_RUNTIME_DIR/step-agent/step-agent-pkcs11.sock ``` +On NixOS, `p11-kit-client.so` lives in the Nix store rather than under `/usr/lib`. +Point `modutil` at it with `-libfile $(nix eval --raw nixpkgs#p11-kit)/lib/pkcs11/p11-kit-client.so`. + Next, start Chrome from the command line. In Chrome, you should now have access to certificates managed by Smallstep. @@ -379,6 +556,8 @@ To uninstall the Smallstep Agent from a Linux system: sudo apt-get remove step-agent ``` + **For NixOS:** remove `./step-agent.nix` from your `imports` list, then run `sudo nixos-rebuild switch`. + 2. Optionally, remove configuration and certificate files: ```bash diff --git a/platform/troubleshooting-agent.mdx b/platform/troubleshooting-agent.mdx index e4688699..59d598a3 100644 --- a/platform/troubleshooting-agent.mdx +++ b/platform/troubleshooting-agent.mdx @@ -1,5 +1,5 @@ --- -updated_at: February 03, 2026 +updated_at: July 27, 2026 title: Troubleshooting Guide html_title: Smallstep Troubleshooting Guide description: Troubleshoot Smallstep Device Identity issues. Diagnose platform, MDM, and endpoint problems with step-by-step guidance. @@ -560,6 +560,11 @@ Quick reference for platform-specific commands and file locations. | Collect logs | `step-agent logs collect --log-dir /var/lib/step-agent/logs` | | Agent configuration | `/etc/step-agent/agent.yaml` | +On NixOS these paths are the same, with two differences. +There is no `/usr/bin/step-agent`: the binary is a Nix store path on your `PATH`. +And `step-agent doctor` reports p11-kit as missing unless the client module is registered by its store path, +as shown in [the NixOS install instructions](./smallstep-agent.mdx#nixos). + If the agent won't start, check for this message in the logs: ``` From ab7613038ea32a6f54e9448b9e15a5585cae6f01 Mon Sep 17 00:00:00 2001 From: Josh Drake Date: Mon, 27 Jul 2026 12:23:18 -0500 Subject: [PATCH 2/4] Drop the dead channel pin from the step-cli NixOS link The search.nixos.org link pinned channel=20.09, which has been unsupported for years, so the page showed no results. Without the param it resolves against the current channel, matching how the step-ca installation page already links NixOS packages. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01KSuffpV7e9tawW249FA7gN --- step-cli/installation.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/step-cli/installation.mdx b/step-cli/installation.mdx index a5fdf013..701af9db 100644 --- a/step-cli/installation.mdx +++ b/step-cli/installation.mdx @@ -124,7 +124,7 @@ Big shout out to the maintainers of these packages! We appreciate you. #### NixOS -Install the [`step-cli`](https://search.nixos.org/packages?channel=20.09&show=step-cli&from=0&size=50&sort=relevance&query=step-cli) package on NixOS. +Install the [`step-cli`](https://search.nixos.org/packages?show=step-cli&from=0&size=50&sort=relevance&query=step-cli) package on NixOS. #### FreeBSD From d9c0b464db1100461162cd95d870b28b6390a5c1 Mon Sep 17 00:00:00 2001 From: Carl Tashian Date: Thu, 30 Jul 2026 10:31:33 -0700 Subject: [PATCH 3/4] Link to hosted step-agent.nix instead of inlining it The NixOS install section carried a 100-line Nix module inline, which buried the four actual install steps. Point at the hosted copy at files.smallstep.com and summarize what the module declares, so readers can curl it directly instead of copying out of a code block. Co-Authored-By: Claude Opus 5 (1M context) --- platform/smallstep-agent.mdx | 111 ++--------------------------------- 1 file changed, 6 insertions(+), 105 deletions(-) diff --git a/platform/smallstep-agent.mdx b/platform/smallstep-agent.mdx index 401fbd92..4027405c 100644 --- a/platform/smallstep-agent.mdx +++ b/platform/smallstep-agent.mdx @@ -317,112 +317,13 @@ so a host with no /dev/tpmrm0 cannot enroll yet. ]; ``` -2. Save the following as `step-agent.nix` alongside your `configuration.nix`, - and add `./step-agent.nix` to its `imports` list: +2. Download [`step-agent.nix`](https://files.smallstep.com/step-agent.nix) alongside your `configuration.nix`, + and add `./step-agent.nix` to its `imports` list. + It declares the `step-agent` system user, the systemd service and its restart path unit, + the `polkit` rules the agent needs, and the `p11-kit` module that publishes its PKCS#11 server. - ```nix - { config, lib, pkgs, ... }: - - { - # The step-agent package is unfree. - nixpkgs.config.allowUnfreePredicate = pkg: lib.getName pkg == "step-agent"; - - environment.systemPackages = [ pkgs.step-agent ]; - - # The agent talks to the TPM from user space, so it needs read/write access - # to the TPM resource manager. This creates the tss group and the udev rules - # that grant that group /dev/tpmrm0. - security.tpm2.enable = true; - - users.groups.step-agent = { }; - users.users.step-agent = { - isSystemUser = true; - group = "step-agent"; - home = "/var/lib/step-agent"; - extraGroups = [ "tss" ]; - }; - - # /run/step-agent holds the PKCS#11 and SSH sockets that other users connect - # to. Create it with tmpfiles rather than systemd's RuntimeDirectory=, which - # deletes the directory every time the service stops. - systemd.tmpfiles.rules = [ - "d /run/step-agent 0755 step-agent step-agent - -" - ]; - - systemd.services.step-agent = { - description = "Smallstep Agent"; - documentation = [ "https://u.step.sm/docs/agent" ]; - after = [ "network-online.target" ]; - requires = [ "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - - # The agent starts once the device is registered and agent.yaml exists. - unitConfig.ConditionPathIsReadWrite = "/etc/step-agent/agent.yaml"; - - environment = { - HOME = "/var/lib/step-agent"; - RUNTIME_DIRECTORY = "/run/step-agent"; - }; - - serviceConfig = { - Type = "notify"; - WatchdogSec = "60s"; - ExecStart = "${lib.getExe pkgs.step-agent} start"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - User = "step-agent"; - Group = "step-agent"; - ConfigurationDirectory = "step-agent"; - StateDirectory = "step-agent"; - Restart = "always"; - RestartSec = 10; - - ProtectSystem = true; - ProtectHome = "read-only"; - PrivateTmp = true; - SecureBits = "keep-caps"; - AmbientCapabilities = [ "CAP_IPC_LOCK" "CAP_CHOWN" "CAP_DAC_OVERRIDE" "CAP_FOWNER" ]; - CapabilityBoundingSet = [ "CAP_SYSLOG" "CAP_IPC_LOCK" "CAP_CHOWN" "CAP_DAC_OVERRIDE" "CAP_FOWNER" ]; - DeviceAllow = [ "/dev/tpmrm0 rw" ]; - ReadWritePaths = [ "-/dev/tpmrm0" ]; - - LimitNOFILE = 65536; - LimitMEMLOCK = "infinity"; - }; - }; - - # Restart the agent when its configuration changes, such as after registering. - systemd.paths.step-agent-restart = { - wantedBy = [ "multi-user.target" ]; - pathConfig.PathChanged = "/etc/step-agent/agent.yaml"; - }; - - systemd.services.step-agent-restart.serviceConfig = { - Type = "oneshot"; - ExecStart = "${config.systemd.package}/bin/systemctl restart step-agent.service"; - }; - - # Let the agent restart units and manage NetworkManager connections. - security.polkit.enable = true; - security.polkit.extraConfig = '' - polkit.addRule(function(action, subject) { - if (subject.user == "step-agent") { - if (action.id == "org.freedesktop.systemd1.manage-units") { - return polkit.Result.YES; - } - if (action.id.indexOf("org.freedesktop.NetworkManager.") == 0) { - return polkit.Result.YES; - } - } - }); - ''; - - # Publish the agent's PKCS#11 server to p11-kit clients. The module path has - # to be explicit: the agent searches FHS locations that do not exist on NixOS. - environment.etc."pkcs11/modules/step-agent.module".text = '' - module: ${pkgs.p11-kit}/lib/pkcs11/p11-kit-client.so - server-address: unix:path=/run/step-agent/step-agent-pkcs11.sock - ''; - } + ```bash + curl -fsSLO https://files.smallstep.com/step-agent.nix ``` 3. Rebuild your system: From e6ad7be96a7d24e592c91756ed702d32b56abcd9 Mon Sep 17 00:00:00 2001 From: Carl Tashian Date: Thu, 30 Jul 2026 13:36:36 -0700 Subject: [PATCH 4/4] Typo fixes --- platform/smallstep-agent.mdx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/platform/smallstep-agent.mdx b/platform/smallstep-agent.mdx index 4027405c..1696f79c 100644 --- a/platform/smallstep-agent.mdx +++ b/platform/smallstep-agent.mdx @@ -317,10 +317,8 @@ so a host with no /dev/tpmrm0 cannot enroll yet. ]; ``` -2. Download [`step-agent.nix`](https://files.smallstep.com/step-agent.nix) alongside your `configuration.nix`, - and add `./step-agent.nix` to its `imports` list. - It declares the `step-agent` system user, the systemd service and its restart path unit, - the `polkit` rules the agent needs, and the `p11-kit` module that publishes its PKCS#11 server. +2. Download [`step-agent.nix`](https://files.smallstep.com/step-agent.nix), place it alongside your `configuration.nix`, and add `./step-agent.nix` to your `imports` list. + The `.nix` file declares the `step-agent` system user, the systemd service and its restart path unit, the `polkit` rules the agent needs, and the `p11-kit` module that publishes our PKCS#11 server. ```bash curl -fsSLO https://files.smallstep.com/step-agent.nix