add native support for ssh keys for age

This commit is contained in:
musjj 2025-04-22 06:16:55 +07:00
parent 61154300d9
commit 4fb1eef0c0
6 changed files with 90 additions and 4 deletions

View file

@ -98,6 +98,7 @@ let
gnupgHome = cfg.gnupg.home;
sshKeyPaths = cfg.gnupg.sshKeyPaths;
ageKeyFile = cfg.age.keyFile;
ageSshKeyFile = cfg.age.sshKeyFile;
ageSshKeyPaths = cfg.age.sshKeyPaths;
placeholderBySecretName = cfg.placeholder;
userMode = true;
@ -250,11 +251,23 @@ 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.
'';
};
sshKeyPaths = lib.mkOption {
type = lib.types.listOf lib.types.path;
default = [ ];
description = ''
Paths to ssh keys added as age keys during sops description.
Paths to ssh keys added as age keys during sops description. The ssh
keys will be converted into age keys manually using ssh-to-age.
This option is deprecated and will be removed in the future. Use sops.age.sshKeyFile instead.
'';
};
};
@ -301,6 +314,7 @@ in
|| cfg.gnupg.sshKeyPaths != [ ]
|| cfg.gnupg.qubes-split-gpg.enable == true
|| cfg.age.keyFile != null
|| cfg.age.sshKeyFile != 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";
}
@ -323,6 +337,19 @@ in
}
];
warnings = [
(lib.mkIf
(
cfg.age.sshKeyPaths != [ ]
&& cfg.gnupg.sshKeyPaths == [ ]
&& cfg.gnupg.home == null
&& cfg.age.keyFile == null
&& cfg.age.sshKeyFile == null
)
"The option sops.age.sshKeyPaths has been deprecated, since age now has native SSH support. Use option sops.age.sshKeyFile instead."
)
];
home.sessionVariables = lib.mkIf cfg.gnupg.qubes-split-gpg.enable {
# TODO: Add this package to nixpkgs and use it from the store
# https://github.com/QubesOS/qubes-app-linux-split-gpg

View file

@ -300,12 +300,24 @@ 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.
'';
};
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.
Paths to ssh keys added as age keys during sops description. The ssh
keys will be converted into age keys manually using ssh-to-age.
This option is deprecated and will be removed in the future. Use sops.age.sshKeyFile instead.
'';
};
};
@ -345,6 +357,7 @@ in
cfg.gnupg.home != null
|| cfg.gnupg.sshKeyPaths != [ ]
|| cfg.age.keyFile != null
|| cfg.age.sshKeyFile != 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";
}
@ -383,6 +396,19 @@ in
})
{
warnings = [
(lib.mkIf
(
cfg.age.sshKeyPaths != [ ]
&& cfg.gnupg.sshKeyPaths == [ ]
&& cfg.gnupg.home == null
&& cfg.age.keyFile == null
&& cfg.age.sshKeyFile == null
)
"The option sops.age.sshKeyPaths has been deprecated, since age now has native SSH support. Use option sops.age.sshKeyFile instead."
)
];
sops.environment.SOPS_GPG_EXEC = lib.mkIf (cfg.gnupg.home != null || cfg.gnupg.sshKeyPaths != [ ]) (
lib.mkDefault "${pkgs.gnupg}/bin/gpg"
);

View file

@ -15,6 +15,7 @@ writeTextFile {
gnupgHome = cfg.gnupg.home;
sshKeyPaths = cfg.gnupg.sshKeyPaths;
ageKeyFile = cfg.age.keyFile;
ageSshKeyFile = cfg.age.sshKeyFile;
ageSshKeyPaths = cfg.age.sshKeyPaths;
useTmpfs = false;
placeholderBySecretName = cfg.placeholder;

View file

@ -339,12 +339,24 @@ 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.
'';
};
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.
Paths to ssh keys added as age keys during sops description. The ssh
keys will be converted into age keys manually using ssh-to-age.
This option is deprecated and will be removed in the future. Use sops.age.sshKeyFile instead.
'';
};
};
@ -405,6 +417,7 @@ in
cfg.gnupg.home != null
|| cfg.gnupg.sshKeyPaths != [ ]
|| cfg.age.keyFile != null
|| cfg.age.sshKeyFile != 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";
}
@ -483,6 +496,19 @@ in
};
})
{
warnings = [
(lib.mkIf
(
cfg.age.sshKeyPaths != [ ]
&& cfg.gnupg.sshKeyPaths == [ ]
&& cfg.gnupg.home == null
&& cfg.age.keyFile == null
&& cfg.age.sshKeyFile == null
)
"The option sops.age.sshKeyPaths has been deprecated, since age now has native SSH support. Use option sops.age.sshKeyFile instead."
)
];
system.build.sops-nix-manifest = manifest;
}
];

View file

@ -40,6 +40,7 @@ else
gnupgHome = cfg.gnupg.home;
sshKeyPaths = cfg.gnupg.sshKeyPaths;
ageKeyFile = cfg.age.keyFile;
ageSshKeyFile = cfg.age.sshKeyFile;
ageSshKeyPaths = cfg.age.sshKeyPaths;
useTmpfs = cfg.useTmpfs;
placeholderBySecretName = cfg.placeholder;

View file

@ -79,6 +79,7 @@ type manifest struct {
SSHKeyPaths []string `json:"sshKeyPaths"`
GnupgHome string `json:"gnupgHome"`
AgeKeyFile string `json:"ageKeyFile"`
AgeSSHKeyFile string `json:"ageSshKeyFile"`
AgeSSHKeyPaths []string `json:"ageSshKeyPaths"`
UseTmpfs bool `json:"useTmpfs"`
UserMode bool `json:"userMode"`
@ -1325,7 +1326,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 == "" {
keyfile := filepath.Join(manifest.SecretsMountPoint, "age-keys.txt")
os.Setenv("SOPS_AGE_KEY_FILE", keyfile)
// Create the keyfile
@ -1360,6 +1361,10 @@ func installSecrets(args []string) error {
}
}
if manifest.AgeSSHKeyFile != "" {
os.Setenv("SOPS_AGE_SSH_PRIVATE_KEY_FILE", manifest.AgeSSHKeyFile)
}
if err := decryptSecrets(manifest.Secrets); err != nil {
return err
}