diff --git a/.sops.yaml b/.sops.yaml index 703c675..3c548ce 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -4,6 +4,18 @@ keys: - &test-nix age1gvplss0ddmyf6vpjy363wu3n057vhm0j6n7tc94cxd8kadapypws5mtaj0 - &soteria age1h0prahyukq4l564yqwgcpg3g6gdrjflk0suklussjjrjstxd9uesws8633 creation_rules: + - path_regex: modules/hosts/janus/secrets\.yaml$ + key_groups: + - age: + - *john-pc + - *test-nix + - path_regex: keys/secrets\.yaml$ + key_groups: + - age: + - *john-p14s + - *john-pc + - *test-nix + - *soteria - path_regex: soteria/secrets\.yaml$ key_groups: - age: diff --git a/keys/secrets.yaml b/keys/secrets.yaml index 3343e71..a7232ce 100644 --- a/keys/secrets.yaml +++ b/keys/secrets.yaml @@ -9,33 +9,42 @@ api: gmail_client_secret: ENC[AES256_GCM,data:du2gEY5TQIwpUEvJKDWKY3noLRGeiKek4IMwPUusVx8NMys=,iv:hIYi1xQYf6+hDhK0pNprBYu6wXwRH2yOTwQg6pzQa0A=,tag:sqmQ5GCkKbHpIy2R+Y5G/A==,type:str] sops: age: - - recipient: age1f6drjusg866yscj8029tk4yfpgecklrvezldm02ankm6h8nnwu5s2u6ahy - enc: | + - enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0UEpja2kxdThZVWZhOGVP - S0NtSi84MjhnN0RORkh2NjZ4YlYvWS9kZDBNClFzYnVxWnhmQkpCRkRFVUx1RDdX - ZHFqYXRqYXM0cWJzcU5EeEtSR1BUVzAKLS0tIDdEY2pnVTJqWlNZVkZldXVYVmFH - dVNBRUVodU5sRnpVcG1GZ1RiZzhjTXMKefqBvvD/qZwcSHmFjUnleukVRLueG36Y - Q81KlwQweF2F8kHl7Bqsi+3hH1dZZbVm3vjuGpWFOoti7fowUV55Kw== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhbmduOWR1ZloxWjRjTjFp + ZFpvUFA2cStzYllUa1BhSmJBYWVUSmNGblZ3Cmw3TnVBSGtwaDV4ZlRRT2h6OWw0 + bGd6dUQ2eE1QVWNTTitSSG80NVhraU0KLS0tIHRVMXFFRGh5cjlwNXpIb0F4TnF3 + Ykplcm1DWm04RExHYnRjQjdCOVhLaE0K/VGQ/58QWOAWPToQt22W4iBX7rrh/lxL + Via5/T25c64Eh6FXzar+z9zdHjS4s7PLsf6iJIY84xpKCpSAkcaquw== -----END AGE ENCRYPTED FILE----- - - recipient: age1ykcs39e62pz3xu6cedg8ea685kv5d5qsrhgkndygzm8rx30xd5ys5t3qxt - enc: | + recipient: age1f6drjusg866yscj8029tk4yfpgecklrvezldm02ankm6h8nnwu5s2u6ahy + - enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqZFZxbDhVUWFEUGhPMlZI - SFdBYkpxSnAxTUZXbjVwQnlZQ3l1SWtuZGg0CmVBdnVHbTNUcmwvK01iMnZKZTJh - ajFla3kzYUl4ZWY3czA0WUdNM2lpVFUKLS0tIHo5Uk1pV296MXdnUTZGQ25haWZG - QWZDWGRaRDBhY1ZkZk5oTHY0ZVV2RXMKanv+WWRhf5nl+aw/T6QZFVQQmhV1DZfB - jkSzOAKOgPx7toYFmpq9E8fAH+zrMzDbxI2z2uyrOFI6v+QE0Ul/iQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkdEVYYzR2M1hDSmR6aVZO + WCtBUTBVUU96SitsTFlBT2IzQjk2Q21LV2tvCkRxVEVESVFsWlczdU5CT2V1a0cw + MUxXNFJFa1BvRFdGbVpkdDRTYVhROUkKLS0tIHBMaGFTRmgrYnkraGt3YkRCMXhw + Rk9GMUhXcWhYL3NXdmRZN0FtQjR2bU0Kql1oAOuJDJ2jcR+WcibBiFiVcMEBbXVS + cxydfdl3/la1tqiMd6rnDh/iB5hwjeeULwrgE/5Qjc7w23hMN9AF1g== -----END AGE ENCRYPTED FILE----- - - recipient: age1gvplss0ddmyf6vpjy363wu3n057vhm0j6n7tc94cxd8kadapypws5mtaj0 - enc: | + recipient: age1ykcs39e62pz3xu6cedg8ea685kv5d5qsrhgkndygzm8rx30xd5ys5t3qxt + - enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZcGtMNi9RSG5aTVV5cWdT - NittUXN0Qnpld1YvOU50OUh3Z3ZiSzhHOHdNCnc4TmdYbS9QQnBLbldHSytIdkJl - R0psQWxkZTgyZTRzckkrTGpyNCsvR2sKLS0tIEdLb05aT2I2S3BKcFRrVmtvTGw5 - Z1orRCtkTDVXSktuck5pTmV4K05qZHMKZlHHu07q+GnyDDgdwW2Ic3P23PmoSPwn - WuNLZdlZQleROaRb+zpD+9P1HGGJ3mWAlNlnmjGrRk453k1PbBQ5Og== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArTnc1ZEorSDlZSW1qY3Zu + NExrYXgyQjRIQUNRYlFXZCt4bXcxRndzWW40CjNCM3p0VDcwbENoTGxFNGZRR3lM + R0pnSlluTUpiNk91d0hlci9sOUtBYjQKLS0tIGp2eWpReExSNTdCS0RBQ1F5dDNt + eWhuak00dTFZV0k1WEREQkRPWUFmc00KQ13ormwGmzwPxvId8WXe1PY4FG3g1Juw + KnBf20sSRkJ/oj3iEhfd8ZmXeoK1Xc44aeCcVe7NEzVtMhjIdzcNqg== -----END AGE ENCRYPTED FILE----- + recipient: age1gvplss0ddmyf6vpjy363wu3n057vhm0j6n7tc94cxd8kadapypws5mtaj0 + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWTHN6TDBHdFU1L1lEQzg4 + TW1vT08vYnp3bzBzSFlxbGpDSFNycFYycFJRCnYvcjVQOC9rZTFXb0lHQWFUVVhZ + ZFVtM09zWW9GZzNMRnBHdHNFNnZHdTgKLS0tIFh1b1pnKzJQUWg4YkRIWVFnRDNz + bXRzY1piak43N0dMZFQ1WWdSZjBBT2cKujwWnuf7LFZe1TIu0R+Vc+HGCYqaeRkD + jBuPRyN7cqCZ5cK9492BVLg48toU/djCSs1w33aLeTF5Ug/Swduqkg== + -----END AGE ENCRYPTED FILE----- + recipient: age1h0prahyukq4l564yqwgcpg3g6gdrjflk0suklussjjrjstxd9uesws8633 lastmodified: "2026-03-15T15:06:29Z" mac: ENC[AES256_GCM,data:cF/TJ8VkzrHRUrO5iGdRdlFtqV/5EQ15JwQKIywJvsh0NERK67T21czSP7923MiL0u5QTVPn/rO8R5E/8gBu3r8+fLq+CFl9PDQHEX2JhnYOD5WZR412WMZq3MVR94IMTOrQANMVpS4uhMyvnrqOe4AenxLDyzrYhkwf1KQh4w0=,iv:Qwy8z4uXGMlf+kTMNiE42M9l8LtSJ+O7diknRrsSeYI=,tag:qlCY9r8HnEDmq/jw59C/sg==,type:str] unencrypted_suffix: _unencrypted diff --git a/modules/features/step-client.nix b/modules/features/step-client.nix index 6a35a55..cb4626f 100644 --- a/modules/features/step-client.nix +++ b/modules/features/step-client.nix @@ -1,29 +1,145 @@ -{ self, inputs, ... }: { - flake.modules.homeManager.step-client = { config, pkgs, lib, ... }: { - home.file.".step/config/defaults.json".text = builtins.toJSON { - ca-url = "https://janus.john-stream.com/"; - fingerprint = "2036c44f7b5901566ff7611ea6c927291ecc6d2dd00779c0eead70ec77fa10d6"; - root = ../hosts/janus/root_ca.crt; - }; - home.packages = [ - inputs.self.packages.${pkgs.stdenv.hostPlatform.system}.step-bootstrap - ]; - # sops.secrets."step-ca-defaults" = { - # sopsFile = ../hosts/janus/defaults.json; - # format = "json"; - # key = ""; # This causes it to decode the whole file - # path = "${config.home.homeDirectory}/defaults.json"; - # mode = "0400"; - # }; +{ self, inputs, ... }: +let + defaultCaUrl = "https://janus.john-stream.com/"; + defaultFingerprint = "2036c44f7b5901566ff7611ea6c927291ecc6d2dd00779c0eead70ec77fa10d6"; + defaultRoot = ../hosts/janus/root_ca.crt; + + mkStepBootstrap = { pkgs, caUrl, fingerprint, install ? false }: + (inputs.self.wrappers.stepBootstrap.apply { + inherit pkgs install; + ca-url = caUrl; + inherit fingerprint; + }).wrapper; + + mkDefaultsText = cfg: builtins.toJSON { + ca-url = cfg.caUrl; + fingerprint = cfg.fingerprint; + root = cfg.root; }; +in +{ + flake.modules.nixos.step-client = { config, pkgs, lib, ... }: + let + cfg = config."step-client"; + in + { + options."step-client" = { + enable = lib.mkOption { + description = "Enable step-ca client bootstrap"; + type = lib.types.bool; + default = true; + }; + + caUrl = lib.mkOption { + description = "The step-ca URL used for bootstrap and renewal."; + type = lib.types.str; + default = defaultCaUrl; + }; + + fingerprint = lib.mkOption { + description = "The SHA256 fingerprint of the step-ca root certificate."; + type = lib.types.str; + default = defaultFingerprint; + }; + + root = lib.mkOption { + description = "The step-ca root certificate used for bootstrap."; + type = lib.types.path; + default = defaultRoot; + }; + + certDir = lib.mkOption { + description = "Directory used to store root CA material for mTLS and step bootstrap."; + type = lib.types.str; + default = "/etc/step-ca/certs"; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ + (mkStepBootstrap { + inherit pkgs; + caUrl = cfg.caUrl; + fingerprint = cfg.fingerprint; + }) + ]; + + environment.etc."step-ca/defaults.json".text = mkDefaultsText cfg; + + systemd.tmpfiles.rules = [ + "d ${cfg.certDir} 0750 root root -" + "d /root/.step 0700 root root -" + "d /root/.step/config 0700 root root -" + "d /root/.step/certs 0700 root root -" + "L+ /root/.step/config/defaults.json - - - - /etc/step-ca/defaults.json" + "L+ /root/.step/certs/root_ca.crt - - - - ${cfg.certDir}/root_ca.crt" + ]; + }; + }; + + flake.modules.homeManager.step-client = { config, pkgs, lib, ... }: + let + cfg = config."step-client"; + in + { + options."step-client" = { + enable = lib.mkOption { + description = "Enable step-ca client bootstrap"; + type = lib.types.bool; + default = true; + }; + + caUrl = lib.mkOption { + description = "The step-ca URL used for bootstrap and renewal."; + type = lib.types.str; + default = defaultCaUrl; + }; + + fingerprint = lib.mkOption { + description = "The SHA256 fingerprint of the step-ca root certificate."; + type = lib.types.str; + default = defaultFingerprint; + }; + + root = lib.mkOption { + description = "The step-ca root certificate used for bootstrap."; + type = lib.types.path; + default = defaultRoot; + }; + + certDir = lib.mkOption { + description = "Directory used to store root CA material for mTLS and step bootstrap."; + type = lib.types.str; + default = "${config.home.homeDirectory}/.step/certs"; + }; + }; + + config = lib.mkIf cfg.enable ( + let + certDirPath = lib.removePrefix "${config.home.homeDirectory}/" cfg.certDir; + in + { + home.packages = [ + (mkStepBootstrap { + inherit pkgs; + caUrl = cfg.caUrl; + fingerprint = cfg.fingerprint; + }) + ]; + + home.file.".step/config/defaults.json".text = mkDefaultsText cfg; + home.file."${certDirPath}/root_ca.crt".source = cfg.root; + } + ); + }; perSystem = { system, pkgs, lib, ... }: { - packages.step-bootstrap = (inputs.self.wrappers.stepBootstrap.apply { + packages.step-bootstrap = mkStepBootstrap { inherit pkgs; - ca-url = "https://janus.john-stream.com"; - fingerprint = "2036c44f7b5901566ff7611ea6c927291ecc6d2dd00779c0eead70ec77fa10d6"; + caUrl = defaultCaUrl; + fingerprint = defaultFingerprint; install = true; - }).wrapper; + }; }; flake.wrappers.stepBootstrap = inputs.wrappers.lib.wrapModule ({config, lib, wlib, ... }: { diff --git a/modules/hosts/janus/README.md b/modules/hosts/janus/README.md new file mode 100644 index 0000000..eb5c36b --- /dev/null +++ b/modules/hosts/janus/README.md @@ -0,0 +1,37 @@ +# Janus + +Generate passwords: +```shell +mkdir -p /tmp/janus-step-ca-bootstrap && chmod 700 /tmp/janus-step-ca-bootstrap && cd /tmp/janus-step-ca-bootstrap && umask 077 && openssl rand -base64 48 > ca_password.txt && openssl rand -base64 48 > admin_jwk_password.txt +``` + +Bootstrap CA materials with SSH enabled: +```shell +STEPPATH=/tmp/janus-step-ca-bootstrap/step step ca init --name Janus --dns janus.john-stream.com --dns 192.168.1.244 --address :443 --provisioner admin --password-file /tmp/janus-step-ca-bootstrap/ca_password.txt --provisioner-password-file /tmp/janus-step-ca-bootstrap/admin_jwk_password.txt --ssh --deployment-type standalone --with-ca-url https://janus.john-stream.com +``` + +Insert generated runtime CA material into `modules/hosts/janus/secrets.yaml` under `janus`: + +- `/tmp/janus-step-ca-bootstrap/ca_password.txt` -> `ca_password` +- `/tmp/janus-step-ca-bootstrap/step/certs/intermediate_ca.crt` -> `intermediate_ca_crt` +- `/tmp/janus-step-ca-bootstrap/step/secrets/intermediate_ca_key` -> `intermediate_ca_key` +- `/tmp/janus-step-ca-bootstrap/step/secrets/ssh_host_ca_key` -> `ssh_host_ca_key` +- `/tmp/janus-step-ca-bootstrap/step/secrets/ssh_user_ca_key` -> `ssh_user_ca_key` + +If rotating provisioner password, also set: + +- `/tmp/janus-step-ca-bootstrap/admin_jwk_password.txt` -> `janus.admin_jwk` in `keys/secrets.yaml` + +Secret source-of-truth after this split: + +- `modules/hosts/janus/secrets.yaml`: Janus runtime CA secrets only (`ca_password`, `intermediate_ca_crt`, `intermediate_ca_key`, `ssh_host_ca_key`, `ssh_user_ca_key`) +- `keys/secrets.yaml`: shared Janus provisioner secret (`janus.admin_jwk`) consumed by `step-ssh-host` across hosts + +Then update public artifacts in repo from generated output: + +- `modules/hosts/janus/root_ca.crt` from `/tmp/janus-step-ca-bootstrap/step/certs/root_ca.crt` +- `modules/hosts/janus/fingerprint` from: + ```shell + step certificate fingerprint /tmp/janus-step-ca-bootstrap/step/certs/root_ca.crt + ``` +- `modules/hosts/janus/ssh_user_ca.pub` from `/tmp/janus-step-ca-bootstrap/step/certs/ssh_user_ca_key.pub` \ No newline at end of file diff --git a/modules/hosts/janus/default.nix b/modules/hosts/janus/default.nix index 3731c76..e2a7a0f 100644 --- a/modules/hosts/janus/default.nix +++ b/modules/hosts/janus/default.nix @@ -4,55 +4,13 @@ let hostname = "janus"; in { - flake.modules.nixos.janus-ca = - { config, pkgs, lib, ... }: - let - cfg = config.janus-ca; - johnHome = lib.attrByPath [ "users" "users" username "home" ] "/home/${username}" config; - johnGroup = lib.attrByPath [ "users" "users" username "group" ] username config; - cfgInEtc = lib.hasPrefix "/etc/" cfg.certDir; - certDirEtcPath = - if cfgInEtc then - lib.removePrefix "/etc/" cfg.certDir - else - cfg.certDir; - mkStepRules = home: user: group: [ - "d ${home}/.step 0700 ${user} ${group} -" - "d ${home}/.step/config 0700 ${user} ${group} -" - "d ${home}/.step/certs 0700 ${user} ${group} -" - "L+ ${home}/.step/config/defaults.json - - - - /etc/step-ca/defaults.json" - "L+ ${home}/.step/certs/root_ca.crt - - - - ${cfg.certDir}/root_ca.crt" - ]; - in - { - options.janus-ca = { - certDir = lib.mkOption { - description = "String path to where the mtls certs will be stored."; - type = lib.types.str; - default = "/etc/step-ca/certs"; - }; - }; - - config = { - environment.etc = lib.mkIf cfgInEtc { - "step-ca/defaults.json".text = builtins.toJSON { - ca-url = "https://janus.john-stream.com/"; - fingerprint = "2036c44f7b5901566ff7611ea6c927291ecc6d2dd00779c0eead70ec77fa10d6"; - root = ./root_ca.crt; - }; - }; - systemd.tmpfiles.rules = - mkStepRules johnHome username johnGroup - ++ mkStepRules "/root" "root" "root"; - }; - }; - flake.nixosConfigurations."${hostname}" = inputs.nixpkgs.lib.nixosSystem { modules = with inputs.self.modules; [ nixos.lxc nixos.mysops nixos.step-ssh-host - nixos.janus-ca + nixos.step-client + nixos.step-ca inputs.home-manager.nixosModules.home-manager nixos."${username}" nixos.docker @@ -60,7 +18,7 @@ in nixos.mtls ({ lib, pkgs, ... }: { networking.hostName = hostname; - sops.defaultSopsFile = ../../../keys/secrets.yaml; + sops.defaultSopsFile = ./secrets.yaml; step-ssh-host = { hostname = hostname; extraPrincipals = [ @@ -90,6 +48,7 @@ in home-manager.users."${username}" = { imports = with inputs.self.modules.homeManager; [ mysops + step-client ]; docker.enable = true; }; diff --git a/modules/hosts/janus/secrets.yaml b/modules/hosts/janus/secrets.yaml new file mode 100644 index 0000000..6c6a053 --- /dev/null +++ b/modules/hosts/janus/secrets.yaml @@ -0,0 +1,30 @@ +janus: + ca_password: ENC[AES256_GCM,data:GmuqoePDJd5Cn7+sWbvXPlGoUf3SVgYnHOoq9mnPWNWj,iv:VY/8olA+yu66wW+RbhD58GtA0YUWuAtm1HUXtNIIuLk=,tag:fCz3x6B4UPw+XpJE0F3t/g==,type:str] + intermediate_ca_crt: ENC[AES256_GCM,data:9W6QXGlcPdfas1ea6S3w1OYI/SeF6YDIdF5J7Hv4ype3,iv:H8oVfbMLBRvU0ywovVSB84g0q1wPhHEdzfpIVAY0Bkg=,tag:7/pU0N1SlfC1i8H2IgPGVA==,type:str] + intermediate_ca_key: ENC[AES256_GCM,data:wrzE8pgSZrtMA2jyLuVhMFxr47ICDBUkqOFyFJex9h3g,iv:I3Sz07e+cFDOUunCu7ZGcAjckRJDy3NmTXoB0vtA0HI=,tag:inANSVzyAzWlX4J5pheY8A==,type:str] + ssh_host_ca_key: ENC[AES256_GCM,data:IT3PcnbrexRDvxoVEyyxYBx7+Brm3SzVP3Yr2UGkFjeH,iv:edfMiRR+EVx9veTH+mEAFtEdC/rlW8uU5jMD8UX2Ylo=,tag:KKS/2GQE8V6obbjfMLspug==,type:str] + ssh_user_ca_key: ENC[AES256_GCM,data:w3gc97CYUODNxk0gIyghd9PCksDVvrdvl8j/NQe/tCtw,iv:WbWlVCPV7niVHEJ9sVcO9SAcLSfquE/bvcR5KClxszk=,tag:08uj+lv9MflYOtQh28K6pw==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCTEFTSy96QTluaWo0bURH + YlpFSWx3VnYvSHpDYU1PNmZrb0FuVHVTcG00CmJnT09OZEJad01OZk8zUzlPT1Ft + bVpHeW9UMXZYN1JJQVgrTk9OamhZeXcKLS0tIFhXMVNDQjhVcUp2aHhjenlGVW9z + cTNPalJOQVJNQWxzMnVMT1lYQS9SNW8KWapdX8dwxEvcqhKI8RJmCWRrV7sRmS72 + sUt6HaUGpQfUQ97MtS01DYaSZjbAvj8t//mXhLubZddDTtTuhbpjAg== + -----END AGE ENCRYPTED FILE----- + recipient: age1ykcs39e62pz3xu6cedg8ea685kv5d5qsrhgkndygzm8rx30xd5ys5t3qxt + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWcnVWS2lpMDM5VWxLWDIx + R0xWQ3ZOaEVFNTR5bXArNTc4MzFOM2xCQWhjCnBZeUtJQ3RvWDdZeVRpRzBPbTl2 + M3FOTlRnTDhIaGg2VzM3MFVEc1FVUmcKLS0tIDAzeDlaZGt5Q2dJbzNWRVB4Qmwr + SWpxcytNdEFBQ2o0Q3lWSHZSNEdCUUEKgHE0j678WIhcQQsZQ5RcQNkQcP++ibvr + ZT3ScL4PAYhH+lxciJK4tit53taevbp5o0jFibaup4ByDvgj7HPclw== + -----END AGE ENCRYPTED FILE----- + recipient: age1gvplss0ddmyf6vpjy363wu3n057vhm0j6n7tc94cxd8kadapypws5mtaj0 + lastmodified: "2026-07-04T03:42:39Z" + mac: ENC[AES256_GCM,data:qBuVJo9F5IiQGDqji0ZfNH6MYYLgaVuEoHGsvejw1ffFjYeqGI5LrZmez8xTx8dymQADCDYINZNYlKxgXaXdGqrlKaU8GzuWeF7M0Ad43+S/8DbP2OGPXERHAH+IWVjvzlurXs4tWE4ULw4PbsVpWqOBaSk603N7cuy7Ztwfk8M=,iv:lceVJAeZi8FwKo8DAET1hgUi54Bu+0kjWcGEZxs5wCA=,tag:mFkqan9BHtI6NkxqbjkIcQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.13.1 diff --git a/modules/hosts/john-p14s/configuration.nix b/modules/hosts/john-p14s/configuration.nix index d12cbb0..ed3c481 100644 --- a/modules/hosts/john-p14s/configuration.nix +++ b/modules/hosts/john-p14s/configuration.nix @@ -56,6 +56,7 @@ gnome desktop mysops + step-client rebuild { my-vscode.enable = true; diff --git a/modules/hosts/john-p14s/default.nix b/modules/hosts/john-p14s/default.nix index e2d7673..e2a8791 100644 --- a/modules/hosts/john-p14s/default.nix +++ b/modules/hosts/john-p14s/default.nix @@ -12,7 +12,6 @@ "${inputs.nixos-hardware}/lenovo/thinkpad/p14s/amd/gen4" ] ++ (with self.modules.nixos; [ p14sConfiguration - janus-ca rebuild sudo john @@ -20,6 +19,7 @@ steam wireguard mtls + step-client # greetd # niri ]); diff --git a/modules/hosts/soteria/default.nix b/modules/hosts/soteria/default.nix index 1ebbc78..a7b4e47 100644 --- a/modules/hosts/soteria/default.nix +++ b/modules/hosts/soteria/default.nix @@ -8,19 +8,18 @@ in flake.nixosConfigurations."${hostname}" = inputs.nixpkgs.lib.nixosSystem { modules = with inputs.self.modules; [ nixos.lxc - nixos."${username}" nixos.mysops + nixos."${username}" nixos.step-ssh-host nixos.login-text nixos.docker nixos.mtls - nixos.janus-ca + nixos.step-client nixos.forgejo nixos.restic-server # nixos.restic-envoy ({ config, pkgs, ... }: { networking.hostName = hostname; - time.timeZone = "America/Chicago"; # Removes password for sudo security.sudo-rs.extraRules = lib.mkAfter [ @@ -38,7 +37,6 @@ in users.users."${username}".extraGroups = [ "mtls" ]; mtls = { enable = true; - certDir = config.janus-ca.certDir; subject = hostname; san = [ "${hostname}.john-stream.com" @@ -98,6 +96,7 @@ in imports = [ inputs.self.modules.homeManager.rebuild inputs.self.modules.homeManager.mysops + inputs.self.modules.homeManager.step-client ({ config, pkgs, lib, ... }: { homeManagerFlakeDir = "${config.xdg.configHome}/home-manager"; docker.enable = true; diff --git a/modules/hosts/soteria/secrets.yaml b/modules/hosts/soteria/secrets.yaml index 388ea9d..5507c3c 100644 --- a/modules/hosts/soteria/secrets.yaml +++ b/modules/hosts/soteria/secrets.yaml @@ -1,5 +1,3 @@ -janus: - admin_jwk: ENC[AES256_GCM,data:2XcN5X77wTQ+OUXa4C9xAErGvrwJKseHjCcgoj6jt+c=,iv:9x+M1wM0dYND1JYkJjM4N8pSOok2OF+P9vmm9NCumTI=,tag:dTCfh+KB1iRJBVoNsGqvuw==,type:str] forgejo: #ENC[AES256_GCM,data:/wtm0uXbiWFoGNWtlTzVuNxBR7CPm2FMB98t3AxSj5V5rltLvzF9BjgWoJCiX3ltzmU=,iv:xaZXbUIGJHxPrLRQzEQI7hgRgc0y061jIhoE3zlcMaA=,tag:fQGheCIdBKm6wE+vtj7g6A==,type:comment] secret_key: ENC[AES256_GCM,data:/jcyeDcsryLqu9Q3VnNaENb71/Tl5JUr0zDzxt8L5UCtnJ/YHA6MKItrQ9ZHFv1XROtnSfZl9D5kKomeM8EVqA==,iv:HxMKAMVQ08gkq6SWENj0/d8i9PhcgPCp5eqbztj9bSg=,tag:nO2dFWT/vfgGc/9JIDZrGw==,type:str] diff --git a/modules/services/step-ca/ssh-host.nix b/modules/services/step-ca/ssh-host.nix index df67972..7829ce4 100644 --- a/modules/services/step-ca/ssh-host.nix +++ b/modules/services/step-ca/ssh-host.nix @@ -37,6 +37,8 @@ config = { ssh.certificates.enable = true; sops.secrets."janus/admin_jwk" = { + # Shared provisioner credential is intentionally centralized. + sopsFile = ../../../keys/secrets.yaml; owner = "root"; group = "root"; mode = "0400"; diff --git a/modules/services/step-ca/step-ca.nix b/modules/services/step-ca/step-ca.nix index 7b79a11..931a361 100644 --- a/modules/services/step-ca/step-ca.nix +++ b/modules/services/step-ca/step-ca.nix @@ -1,22 +1,127 @@ { inputs, ... }: -let - ipAddress = "0.0.0.0"; -in { - flake.modules.nixos.step-ca = { pkgs, ... }: { + flake.modules.nixos.step-ca = { config, pkgs, ... }: + let + # Keep host-specific trust anchor in repo; secret/private keys come from sops. + rootCertPath = ../../hosts/janus/root_ca.crt; + caPasswordPath = config.sops.secrets."janus/ca_password".path; + intermediateCrtPath = config.sops.secrets."janus/intermediate_ca_crt".path; + intermediateKeyPath = config.sops.secrets."janus/intermediate_ca_key".path; + sshHostCaKeyPath = config.sops.secrets."janus/ssh_host_ca_key".path; + sshUserCaKeyPath = config.sops.secrets."janus/ssh_user_ca_key".path; + in + { + # Placeholders are expected initially until real material is inserted into sops. + sops.secrets."janus/ca_password" = { + sopsFile = ../../hosts/janus/secrets.yaml; + owner = "step-ca"; + group = "step-ca"; + mode = "0400"; + }; + sops.secrets."janus/intermediate_ca_crt" = { + sopsFile = ../../hosts/janus/secrets.yaml; + owner = "step-ca"; + group = "step-ca"; + mode = "0400"; + }; + sops.secrets."janus/intermediate_ca_key" = { + sopsFile = ../../hosts/janus/secrets.yaml; + owner = "step-ca"; + group = "step-ca"; + mode = "0400"; + }; + sops.secrets."janus/ssh_host_ca_key" = { + sopsFile = ../../hosts/janus/secrets.yaml; + owner = "step-ca"; + group = "step-ca"; + mode = "0400"; + }; + sops.secrets."janus/ssh_user_ca_key" = { + sopsFile = ../../hosts/janus/secrets.yaml; + owner = "step-ca"; + group = "step-ca"; + mode = "0400"; + }; + # https://github.com/NixOS/nixpkgs/blob/nixos-23.05/nixos/modules/services/security/step-ca.nix services.step-ca = { enable = true; openFirewall = true; - address = ipAddress; - port = 8443; + address = "0.0.0.0"; + port = 443; + intermediatePasswordFile = caPasswordPath; # https://smallstep.com/docs/step-ca/configuration/#configuration-options settings = { - root = ""; - crt = ""; + root = rootCertPath; + crt = intermediateCrtPath; + key = intermediateKeyPath; + dnsNames = [ + "janus.john-stream.com" + "192.168.1.244" + ]; + + 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 = "eyJhbGciOiJQQkVTMi1IUzI1NitBMTI4S1ciLCJjdHkiOiJqd2sranNvbiIsImVuYyI6IkEyNTZHQ00iLCJwMmMiOjYwMDAwMCwicDJzIjoiUVJnTnJVTF9KcmxJYkJMVTlGNVRPZyJ9.DMu7xBNCq5pr-_--YTxNr5Hrcqy6ZmSVHsWurfVXL7Hk0Q3vyYRxiw.h-CnFiYc-DhxThI3.plx3_Qa_0kU-2TwnqFNfAfGnCpfQ2e0iiCMLruNHbLMnHeXQ1BysHBqps45_02zZXIRdHoDgYGtXRSfcdUYYoS0pLoPzC6m301ZFNSAFdRVlSZ3Q6VmWdixPXXnEB4EgSKTT_wxR33L8t9OpFzD85KfY-b_Un1l99ufjCnfg-EYkcICTn_G4-8bcW3eFIvJ6setzu-l0jHMhLQdIweqncn9on9xBXBD-ANhZfP95P2BJt-APqCi8eqiAvn_vClovdg0PxzRwOVDvWREz66FDw-HTU7xDtGO9hACopT5tfZOXDoykgZw1mJsq9NEq9ZzvKG2hvyk1UXtExxrNtFo.5q1OfGU4Amo4Si-vpeI42g"; + 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; + }; }; }; + environment.systemPackages = with pkgs; [ step-ca step-cli