1
1
mirror of https://github.com/LnL7/nix-darwin.git synced 2024-08-17 00:20:44 +03:00

Merge pull request #654 from shivaraj-bh/authorized-keys

Manage SSH authorized keys for users
This commit is contained in:
Domen Kožar 2023-05-15 11:59:31 +01:00 committed by GitHub
commit 0dbf1c2fb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 7 deletions

View File

@ -45,6 +45,14 @@ in
'';
};
copy = mkOption {
type = types.bool;
default = false;
description = ''
Whether this file should be copied instead of symlinking.
'';
};
knownSha256Hashes = mkOption {
internal = true;
type = types.listOf types.str;

View File

@ -47,10 +47,65 @@ let
hostNames = mkDefault [ name ];
};
};
# Taken from: https://github.com/NixOS/nixpkgs/blob/f4aa6afa5f934ece2d1eb3157e392d056be01617/nixos/modules/services/networking/ssh/sshd.nix#L46-L93
userOptions = {
options.openssh.authorizedKeys = {
keys = mkOption {
type = types.listOf types.str;
default = [];
description = ''
A list of verbatim OpenSSH public keys that should be added to the
user's authorized keys. The keys are added to a file that the SSH
daemon reads in addition to the the user's authorized_keys file.
You can combine the <literal>keys</literal> and
<literal>keyFiles</literal> options.
Warning: If you are using <literal>NixOps</literal> then don't use this
option since it will replace the key required for deployment via ssh.
'';
};
keyFiles = mkOption {
type = types.listOf types.path;
default = [];
description = ''
A list of files each containing one OpenSSH public key that should be
added to the user's authorized keys. The contents of the files are
read at build time and added to a file that the SSH daemon reads in
addition to the the user's authorized_keys file. You can combine the
<literal>keyFiles</literal> and <literal>keys</literal> options.
'';
};
};
};
authKeysFiles = let
mkAuthKeyFile = u: nameValuePair "ssh/authorized_keys.d/${u.name}" {
copy = true;
text = ''
${concatStringsSep "\n" u.openssh.authorizedKeys.keys}
${concatMapStrings (f: readFile f + "\n") u.openssh.authorizedKeys.keyFiles}
'';
};
usersWithKeys = attrValues (flip filterAttrs config.users.users (n: u:
length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0
));
in listToAttrs (map mkAuthKeyFile usersWithKeys);
authKeysConfiguration =
{
"ssh/sshd_config.d/101-authorized-keys.conf" = {
copy = true;
text = "AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u\n";
};
};
in
{
options = {
users.users = mkOption {
type = with types; attrsOf (submodule userOptions);
};
programs.ssh.knownHosts = mkOption {
default = {};
@ -80,12 +135,13 @@ in
(data.publicKey != null && data.publicKeyFile == null);
message = "knownHost ${name} must contain either a publicKey or publicKeyFile";
});
environment.etc."ssh/ssh_known_hosts".text = (flip (concatMapStringsSep "\n") knownHosts
(h: assert h.hostNames != [];
concatStringsSep "," h.hostNames + " "
+ (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile)
)) + "\n";
environment.etc = authKeysFiles // authKeysConfiguration //
{ "ssh/ssh_known_hosts".text = (flip (concatMapStringsSep "\n") knownHosts
(h: assert h.hostNames != [];
concatStringsSep "," h.hostNames + " "
+ (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile)
)) + "\n";
};
};
}

View File

@ -12,6 +12,7 @@ let
hasDir = path: length (splitString "/" path) > 1;
etc = filter (f: f.enable) (attrValues config.environment.etc);
etcCopy = filter (f: f.copy) (attrValues config.environment.etc);
etcDirs = filter (attr: hasDir attr.target) (attrValues config.environment.etc);
in
@ -38,6 +39,7 @@ in
cd $out/etc
${concatMapStringsSep "\n" (attr: "mkdir -p $(dirname '${attr.target}')") etc}
${concatMapStringsSep "\n" (attr: "ln -s '${attr.source}' '${attr.target}'") etc}
${concatMapStringsSep "\n" (attr: "touch '${attr.target}'.copy") etcCopy}
'';
system.activationScripts.etc.text = ''
@ -55,6 +57,10 @@ in
if [ ! -e "$d" ]; then
mkdir -p "$d"
fi
if [ -e "$f".copy ]; then
cp "$f" "$l"
continue
fi
if [ -e "$l" ]; then
if [ "$(readlink "$l")" != "$f" ]; then
if ! grep -q /etc/static "$l"; then

View File

@ -6,9 +6,15 @@
publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==";
};
};
users.users.foo.openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAA..." ];
test = ''
echo >&2 "checking for github.com in /etc/ssh/ssh_known_hosts"
grep 'github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' ${config.out}/etc/ssh/ssh_known_hosts
echo >&2 "checking for authorized keys for foo in /etc/ssh/authorized_keys.d/foo"
grep 'ssh-ed25519 AAAA...' ${config.out}/etc/ssh/authorized_keys.d/foo
echo >&2 "checking for authorized keys' path in /etc/ssh/sshd_config.d/101-authorized-keys.conf"
grep 'AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u' ${config.out}/etc/ssh/sshd_config.d/101-authorized-keys.conf
'';
}