diff --git a/modules/home-manager/sops.nix b/modules/home-manager/sops.nix index be11f69..9661438 100644 --- a/modules/home-manager/sops.nix +++ b/modules/home-manager/sops.nix @@ -98,6 +98,8 @@ let gnupgHome = cfg.gnupg.home; sshKeyPaths = cfg.gnupg.sshKeyPaths; ageKeyFile = cfg.age.keyFile; + ageSshKeyFile = cfg.age.sshKeyFile; + ageSshKeyCmd = cfg.age.sshKeyCmd; ageSshKeyPaths = cfg.age.sshKeyPaths; placeholderBySecretName = cfg.placeholder; userMode = true; @@ -267,11 +269,36 @@ in ''; }; + sshKeyFile = lib.mkOption { + type = lib.types.nullOr pathNotInStore; + default = null; + example = "/home/someuser/.ssh/id_ed25519"; + description = '' + Path to ssh key file that will be used by age for sops decryption. + + Unlike {option}`config.sops.age.sshKeyPaths`, this option makes use of + the native ssh key support in age and requires no conversion. + ''; + }; + + sshKeyCmd = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = '' + Command that outputs a (non-password protected) ssh private key that will be used by age for sops decryption. + + Uses native ssh key support in age and requires no conversion. + ''; + }; + sshKeyPaths = lib.mkOption { type = lib.types.listOf lib.types.path; default = [ ]; description = '' Paths to ssh keys added as age keys during sops description. + + These ssh keys will be converted into age keys automatically using + ssh-to-age before they are fed to age. ''; }; }; @@ -327,6 +354,8 @@ in || cfg.gnupg.sshKeyPaths != [ ] || cfg.gnupg.qubes-split-gpg.enable == true || cfg.age.keyFile != null + || cfg.age.sshKeyFile != null + || cfg.age.sshKeyCmd != null || cfg.age.sshKeyPaths != [ ]; message = "No key source configured for sops. Either set services.openssh.enable or set sops.age.keyFile or sops.gnupg.home or sops.gnupg.qubes-split-gpg.enable"; } diff --git a/modules/nix-darwin/default.nix b/modules/nix-darwin/default.nix index 27331bc..3876d02 100644 --- a/modules/nix-darwin/default.nix +++ b/modules/nix-darwin/default.nix @@ -300,12 +300,37 @@ in ''; }; + sshKeyFile = lib.mkOption { + type = lib.types.nullOr pathNotInStore; + default = null; + example = "/etc/ssh/ssh_host_ed25519_key"; + description = '' + Path to ssh key file that will be used by age for sops decryption. + + Unlike {option}`config.sops.age.sshKeyPaths`, this option makes use of + the native ssh key support in age and requires no conversion. + ''; + }; + + sshKeyCmd = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = '' + Command that outputs a (non-password protected) ssh private key that will be used by age for sops decryption. + + Uses native ssh key support in age and requires no conversion. + ''; + }; + sshKeyPaths = lib.mkOption { type = lib.types.listOf lib.types.path; default = defaultImportKeys "ed25519"; defaultText = lib.literalMD "The ed25519 keys from {option}`config.services.openssh.hostKeys`"; description = '' Paths to ssh keys added as age keys during sops description. + + These ssh keys will be converted into age keys automatically using + ssh-to-age before they are fed to age. ''; }; @@ -362,6 +387,8 @@ in cfg.gnupg.home != null || cfg.gnupg.sshKeyPaths != [ ] || cfg.age.keyFile != null + || cfg.age.sshKeyFile != null + || cfg.age.sshKeyCmd != null || cfg.age.sshKeyPaths != [ ]; message = "No key source configured for sops. Either set services.openssh.enable or set sops.age.keyFile or sops.gnupg.home"; } diff --git a/modules/nix-darwin/manifest-for.nix b/modules/nix-darwin/manifest-for.nix index 5015659..f9c7733 100644 --- a/modules/nix-darwin/manifest-for.nix +++ b/modules/nix-darwin/manifest-for.nix @@ -15,6 +15,8 @@ writeTextFile { gnupgHome = cfg.gnupg.home; sshKeyPaths = cfg.gnupg.sshKeyPaths; ageKeyFile = cfg.age.keyFile; + ageSshKeyFile = cfg.age.sshKeyFile; + ageSshKeyCmd = cfg.age.sshKeyCmd; ageSshKeyPaths = cfg.age.sshKeyPaths; useTmpfs = false; placeholderBySecretName = cfg.placeholder; diff --git a/modules/sops/default.nix b/modules/sops/default.nix index 9f19ab6..ed1c939 100644 --- a/modules/sops/default.nix +++ b/modules/sops/default.nix @@ -361,12 +361,37 @@ in ''; }; + sshKeyFile = lib.mkOption { + type = lib.types.nullOr pathNotInStore; + default = null; + example = "/etc/ssh/ssh_host_ed25519_key"; + description = '' + Path to ssh key file that will be used by age for sops decryption. + + Unlike {option}`config.sops.age.sshKeyPaths`, this option makes use of + the native ssh key support in age and requires no conversion. + ''; + }; + + sshKeyCmd = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = '' + Command that outputs a (non-password protected) ssh private key that will be used by age for sops decryption. + + Uses native ssh key support in age and requires no conversion. + ''; + }; + sshKeyPaths = lib.mkOption { type = lib.types.listOf lib.types.path; default = defaultImportKeys "ed25519"; defaultText = lib.literalMD "The ed25519 keys from {option}`config.services.openssh.hostKeys`"; description = '' Paths to ssh keys added as age keys during sops description. + + These ssh keys will be converted into age keys automatically using + ssh-to-age before they are fed to age. ''; }; }; @@ -437,6 +462,8 @@ in cfg.gnupg.home != null || cfg.gnupg.sshKeyPaths != [ ] || cfg.age.keyFile != null + || cfg.age.sshKeyFile != null + || cfg.age.sshKeyCmd != null || cfg.age.sshKeyPaths != [ ]; message = "No key source configured for sops. Either set services.openssh.enable or set sops.age.keyFile or sops.gnupg.home"; } diff --git a/modules/sops/manifest-for.nix b/modules/sops/manifest-for.nix index 1824668..27e74ba 100644 --- a/modules/sops/manifest-for.nix +++ b/modules/sops/manifest-for.nix @@ -40,6 +40,8 @@ else gnupgHome = cfg.gnupg.home; sshKeyPaths = cfg.gnupg.sshKeyPaths; ageKeyFile = cfg.age.keyFile; + ageSshKeyFile = cfg.age.sshKeyFile; + ageSshKeyCmd = cfg.age.ageSshKeyCmd; ageSshKeyPaths = cfg.age.sshKeyPaths; useTmpfs = cfg.useTmpfs; placeholderBySecretName = cfg.placeholder; diff --git a/pkgs/sops-install-secrets/main.go b/pkgs/sops-install-secrets/main.go index 05e6cfc..6bd51f0 100644 --- a/pkgs/sops-install-secrets/main.go +++ b/pkgs/sops-install-secrets/main.go @@ -79,6 +79,8 @@ type manifest struct { SSHKeyPaths []string `json:"sshKeyPaths"` GnupgHome string `json:"gnupgHome"` AgeKeyFile string `json:"ageKeyFile"` + AgeSSHKeyFile string `json:"ageSshKeyFile"` + AgeSSHKeyCmd string `json:"ageSshKeyCmd"` AgeSSHKeyPaths []string `json:"ageSshKeyPaths"` UseTmpfs bool `json:"useTmpfs"` UserMode bool `json:"userMode"` @@ -1341,7 +1343,7 @@ func installSecrets(args []string) error { } // Import age keys - if len(manifest.AgeSSHKeyPaths) != 0 || manifest.AgeKeyFile != "" { + if (len(manifest.AgeSSHKeyPaths) != 0 || manifest.AgeKeyFile != "") && manifest.AgeSSHKeyFile == "" && manifest.AgeSSHKeyCmd == "" { keyfile := filepath.Join(manifest.SecretsMountPoint, "age-keys.txt") err = os.Setenv("SOPS_AGE_KEY_FILE", keyfile) if err != nil { @@ -1382,6 +1384,14 @@ func installSecrets(args []string) error { } } + if manifest.AgeSSHKeyFile != "" { + os.Setenv("SOPS_AGE_SSH_PRIVATE_KEY_FILE", manifest.AgeSSHKeyFile) + } + + if manifest.AgeSSHKeyCmd != "" { + os.Setenv("SOPS_AGE_SSH_PRIVATE_KEY_CMD", manifest.AgeSSHKeyCmd) + } + if err := decryptSecrets(manifest.Secrets); err != nil { return err }