From e72b27e59daca91473360c180d495351d7049244 Mon Sep 17 00:00:00 2001 From: John Lancaster <32917998+jsl12@users.noreply.github.com> Date: Sun, 15 Mar 2026 21:27:44 -0500 Subject: [PATCH] mtls home manager module --- modules/hosts/john-pc-ubuntu.nix | 28 ++--- modules/services/step-ca/mtls.nix | 172 ++++++++++++++++++------------ 2 files changed, 117 insertions(+), 83 deletions(-) diff --git a/modules/hosts/john-pc-ubuntu.nix b/modules/hosts/john-pc-ubuntu.nix index 27cf73a..6d2c9aa 100644 --- a/modules/hosts/john-pc-ubuntu.nix +++ b/modules/hosts/john-pc-ubuntu.nix @@ -23,6 +23,7 @@ in docker desktop step-ssh-user + mtls ]; targets.genericLinux.enable = true; @@ -36,21 +37,20 @@ in (writeShellScriptBin "test-push" '' nixos-rebuild switch --flake ${flakeDir}#janus --target-host root@${testTarget} '') - (writeShellScriptBin "mtls-generate" '' - ${lib.getExe pkgs.step-cli} ca certificate \ - john-pc-ubuntu ${tlsCert} ${tlsKey} \ - --provisioner admin \ - --san 192.168.1.85 \ - --san spiffe://john-stream.com/ubuntu - cat ${tlsCert} ${tlsKey} > ${mtlsCert} - '') - (writeShellScriptBin "mtls-check" '' - ${lib.getExe pkgs.openssl} x509 \ - -noout -subject -issuer \ - -ext subjectAltName,extendedKeyUsage \ - -enddate -in ${mtlsCert} - '') ]; + + mtls = { + enable = true; + subject = hostname; + caURL = "https://janus.john-stream.com/"; + provisioner = "admin"; + san = [ + "${hostname}" + "192.168.1.85" + "spiffe://john-stream.com/ubuntu" + ]; + }; + # TODO: Add host-specific settings here: # - sops secret for `restic_password/john_ubuntu` # - resticprofile profile definition diff --git a/modules/services/step-ca/mtls.nix b/modules/services/step-ca/mtls.nix index 9fb5ee6..b6c5ca0 100644 --- a/modules/services/step-ca/mtls.nix +++ b/modules/services/step-ca/mtls.nix @@ -1,4 +1,73 @@ -{ inputs, ... }: +{ inputs, lib, ... }: +let + opts = { + enable = lib.mkEnableOption "Enable mTLS"; + caURL = lib.mkOption { + description = "URL to the certificate authority"; + type = lib.types.str; + }; + subject = lib.mkOption { + description = "The Common Name, DNS Name, or IP address that will be set as the Subject Common Name for the certificate. If no Subject Alternative Names (SANs) are configured (via the --san flag) then the subject will be set as the only SAN."; + type = lib.types.str; + }; + certDir = lib.mkOption { + description = "String path to where the mtls certs will be stored."; + type = lib.types.str; + default = "/etc/step"; + }; + keyFilename = lib.mkOption { + description = "String filename for the private key"; + type = lib.types.str; + default = "key.pem"; + }; + certFilename = lib.mkOption { + description = "String filename for the public certificate"; + type = lib.types.str; + default = "cert.pem"; + }; + bundleFilename = lib.mkOption { + description = "String filename for the mTLS key bundle"; + type = lib.types.str; + default = "mtls.pem"; + }; + san = lib.mkOption { + description = "List of SAN to give the mTLS cert"; + type = lib.types.listOf lib.types.str; + default = [ ]; + }; + provisioner = lib.mkOption { + type = lib.types.str; + default = "admin"; + }; + renew = { + enable = lib.mkOption { + description = "Enable automatic mTLS certificate renewal using a systemd timer."; + type = lib.types.bool; + default = true; + }; + onCalendar = lib.mkOption { + description = "systemd OnCalendar schedule for mTLS certificate renewal checks."; + type = lib.types.str; + default = "*:1/15"; + }; + randomizedDelaySec = lib.mkOption { + description = "Randomized delay added to renewal timer runs to avoid synchronized renewals."; + type = lib.types.str; + default = "5m"; + }; + reloadUnits = lib.mkOption { + description = "systemd units to try-reload-or-restart after a successful certificate renewal."; + type = lib.types.listOf lib.types.str; + default = [ ]; + }; + postCommands = lib.mkOption { + description = "Shell commands to run after a successful certificate renewal."; + type = lib.types.listOf lib.types.lines; + default = [ ]; + }; + }; + }; +in { flake.modules.nixos.mtls = { config, lib, pkgs, ... }: let @@ -17,74 +86,7 @@ renewPostCommands = lib.concatStringsSep "\n" cfg.renew.postCommands; in { - options.mtls = { - enable = lib.mkEnableOption "Enable mTLS"; - caURL = lib.mkOption { - description = "URL to the certificate authority"; - type = lib.types.str; - }; - subject = lib.mkOption { - description = "The Common Name, DNS Name, or IP address that will be set as the Subject Common Name for the certificate. If no Subject Alternative Names (SANs) are configured (via the --san flag) then the subject will be set as the only SAN."; - type = lib.types.str; - }; - certDir = lib.mkOption { - description = "String path to where the mtls certs will be stored."; - type = lib.types.str; - default = "/etc/step"; - }; - keyFilename = lib.mkOption { - description = "String filename for the private key"; - type = lib.types.str; - default = "key.pem"; - }; - certFilename = lib.mkOption { - description = "String filename for the public certificate"; - type = lib.types.str; - default = "cert.pem"; - }; - bundleFilename = lib.mkOption { - description = "String filename for the mTLS key bundle"; - type = lib.types.str; - default = "mtls.pem"; - }; - san = lib.mkOption { - description = "List of SAN to give the mTLS cert"; - type = lib.types.listOf lib.types.str; - default = [ ]; - }; - provisioner = lib.mkOption { - type = lib.types.str; - default = "admin"; - }; - renew = { - enable = lib.mkOption { - description = "Enable automatic mTLS certificate renewal using a systemd timer."; - type = lib.types.bool; - default = true; - }; - onCalendar = lib.mkOption { - description = "systemd OnCalendar schedule for mTLS certificate renewal checks."; - type = lib.types.str; - default = "*:1/15"; - }; - randomizedDelaySec = lib.mkOption { - description = "Randomized delay added to renewal timer runs to avoid synchronized renewals."; - type = lib.types.str; - default = "5m"; - }; - reloadUnits = lib.mkOption { - description = "systemd units to try-reload-or-restart after a successful certificate renewal."; - type = lib.types.listOf lib.types.str; - default = [ ]; - }; - postCommands = lib.mkOption { - description = "Shell commands to run after a successful certificate renewal."; - type = lib.types.listOf lib.types.lines; - default = [ ]; - }; - }; - }; - + options.mtls = opts; config = lib.mkIf cfg.enable { environment.systemPackages = with pkgs; lib.optionals cfg.enable [ (writeShellScriptBin "mtls-generate" '' @@ -160,4 +162,36 @@ }; }; }; + + flake.modules.homeManager.mtls = { config, lib, pkgs, ... }: + let + cfg = config.mtls; + certDir = cfg.certDir; + tlsKey = "${certDir}/${cfg.keyFilename}"; + tlsCert = "${certDir}/${cfg.certFilename}"; + mtlsBundle = "${certDir}/${cfg.bundleFilename}"; + in + { + options.mtls = opts; + + config = { + home.packages = with pkgs; [ + step-cli + (writeShellScriptBin "mtls-generate" '' + ${lib.getExe pkgs.step-cli} ca certificate \ + john-pc-ubuntu ${tlsCert} ${tlsKey} \ + --provisioner admin \ + --san 192.168.1.85 \ + --san spiffe://john-stream.com/ubuntu + cat ${tlsCert} ${tlsKey} > ${mtlsBundle} + '') + (writeShellScriptBin "mtls-check" '' + ${lib.getExe pkgs.openssl} x509 \ + -noout -subject -issuer \ + -ext subjectAltName,extendedKeyUsage \ + -enddate -in ${mtlsBundle} + '') + ]; + }; + }; } \ No newline at end of file