{ inputs, ... }: { flake.modules.nixos.step-ca = { config, pkgs, lib, ... }: let cfg = config.step-ca; caAddress = "0.0.0.0"; caPort = 443; caPasswordPath = (lib.getAttr cfg.secrets.caPassword config.sops.secrets).path; intermediateKeyPath = (lib.getAttr cfg.secrets.intermediateKey config.sops.secrets).path; sshHostCaKeyPath = (lib.getAttr cfg.secrets.sshHostCaKey config.sops.secrets).path; sshUserCaKeyPath = (lib.getAttr cfg.secrets.sshUserCaKey config.sops.secrets).path; adminProvisionerEncryptedKeyValue = (lib.getAttr cfg.secrets.adminProvisionerEncryptedKey config.sops.placeholder); renderedStepCaConfig = builtins.toJSON { root = cfg.rootCertPath; crt = cfg.intermediateCertPath; key = intermediateKeyPath; address = "${caAddress}:${toString caPort}"; dnsNames = cfg.dnsNames; ssh = { hostKey = sshHostCaKeyPath; userKey = sshUserCaKeyPath; }; db = { type = "badgerv2"; dataSource = "/var/lib/step-ca/db"; }; authority = { backdate = "1m0s"; provisioners = [ { type = "ACME"; name = "acme"; } { type = "SSHPOP"; name = "sshpop"; claims.enableSSHCA = true; } { type = "JWK"; name = "admin"; key = { use = "sig"; kty = "EC"; kid = "xoxgOJFbveSLIL2gm1Yu5ZiRb9v8Jxe44F56i3v-Nf8"; crv = "P-256"; alg = "ES256"; x = "zFO8hPx_eH0Iyz7UJI-w8ODMusEKCZ28M76sGWmWYxA"; y = "XIWLLyKDzqxV9UH-2KeAkKPDrgLoPrxxW9-PzkXggME"; }; encryptedKey = adminProvisionerEncryptedKeyValue; claims = { enableSSHCA = true; disableRenewal = false; allowRenewalAfterExpiry = false; disableSmallstepExtensions = false; }; options = { x509 = { }; ssh = { }; }; } ]; }; tls = { cipherSuites = [ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" ]; minVersion = 1.2; maxVersion = 1.3; renegotiation = false; }; }; in { options.step-ca = { rootCertPath = lib.mkOption { description = "Path to the Step CA root certificate served by this host."; type = lib.types.path; }; intermediateCertPath = lib.mkOption { description = "Path to the Step CA intermediate certificate served by this host. This is public material and does not need to be stored in SOPS."; type = lib.types.path; }; dnsNames = lib.mkOption { description = "DNS names and IP SANs advertised by this Step CA instance."; type = with lib.types; listOf str; }; secrets = { sopsFile = lib.mkOption { description = "Host-local SOPS file that stores Step CA secret material."; type = lib.types.path; }; caPassword = lib.mkOption { description = "SOPS key for the Step CA intermediate password."; type = lib.types.str; }; intermediateKey = lib.mkOption { description = "SOPS key for the Step CA intermediate private key."; type = lib.types.str; }; sshHostCaKey = lib.mkOption { description = "SOPS key for the Step SSH host CA private key."; type = lib.types.str; }; sshUserCaKey = lib.mkOption { description = "SOPS key for the Step SSH user CA private key."; type = lib.types.str; }; adminProvisionerEncryptedKey = lib.mkOption { description = "SOPS key for the Step CA admin provisioner encrypted key."; type = lib.types.str; }; }; }; config = { # Placeholders are expected initially until real material is inserted into sops. sops.secrets."${cfg.secrets.caPassword}" = { sopsFile = cfg.secrets.sopsFile; owner = "step-ca"; group = "step-ca"; mode = "0400"; restartUnits = [ "step-ca.service" ]; }; sops.secrets."${cfg.secrets.intermediateKey}" = { sopsFile = cfg.secrets.sopsFile; owner = "step-ca"; group = "step-ca"; mode = "0400"; restartUnits = [ "step-ca.service" ]; }; sops.secrets."${cfg.secrets.sshHostCaKey}" = { sopsFile = cfg.secrets.sopsFile; owner = "step-ca"; group = "step-ca"; mode = "0400"; restartUnits = [ "step-ca.service" ]; }; sops.secrets."${cfg.secrets.sshUserCaKey}" = { sopsFile = cfg.secrets.sopsFile; owner = "step-ca"; group = "step-ca"; mode = "0400"; restartUnits = [ "step-ca.service" ]; }; sops.secrets."${cfg.secrets.adminProvisionerEncryptedKey}" = { sopsFile = cfg.secrets.sopsFile; owner = "step-ca"; group = "step-ca"; mode = "0400"; restartUnits = [ "step-ca.service" ]; }; sops.templates."step-ca-config" = { owner = "step-ca"; group = "step-ca"; mode = "0400"; content = renderedStepCaConfig; }; # https://github.com/NixOS/nixpkgs/blob/nixos-23.05/nixos/modules/services/security/step-ca.nix services.step-ca = { enable = true; openFirewall = true; address = caAddress; port = caPort; intermediatePasswordFile = caPasswordPath; }; environment.etc."smallstep/ca.json".source = lib.mkForce config.sops.templates."step-ca-config".path; systemd.services.step-ca.restartTriggers = lib.mkAfter [ config.sops.templates."step-ca-config".path ]; environment.systemPackages = with pkgs; [ step-ca step-cli ]; }; }; }