2023-01-08 08:51:06 +00:00
|
|
|
{ config, lib, ... }:
|
2023-01-08 03:07:20 +00:00
|
|
|
|
|
|
|
with lib;
|
|
|
|
let
|
|
|
|
key = types.submodule ({ name, config, ...}: {
|
|
|
|
options = {
|
|
|
|
typedPubkey = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
the pubkey with type attached.
|
|
|
|
e.g. "ssh-ed25519 <base64>"
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
# type = mkOption {
|
|
|
|
# type = types.str;
|
|
|
|
# description = ''
|
|
|
|
# the type of the key, e.g. "id_ed25519"
|
|
|
|
# '';
|
|
|
|
# };
|
|
|
|
host = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
the hostname of a key
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
user = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
the username of a key
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
asUserKey = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
append the "user@host" value to the pubkey to make it usable for ~/.ssh/id_<x>.pub or authorized_keys
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
asHostKey = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
prepend the "host" value to the pubkey to make it usable for ~/.ssh/known_hosts
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
config = rec {
|
|
|
|
user = head (lib.splitString "@" name);
|
|
|
|
host = last (lib.splitString "@" name);
|
|
|
|
asUserKey = "${config.typedPubkey} ${name}";
|
|
|
|
asHostKey = "${host} ${config.typedPubkey}";
|
|
|
|
};
|
|
|
|
});
|
|
|
|
coercedToKey = types.coercedTo types.str (typedPubkey: {
|
|
|
|
inherit typedPubkey;
|
|
|
|
}) key;
|
|
|
|
in
|
|
|
|
{
|
|
|
|
options = {
|
|
|
|
sane.ssh.pubkeys = mkOption {
|
|
|
|
type = types.attrsOf coercedToKey;
|
2023-01-19 23:23:41 +00:00
|
|
|
default = {};
|
2023-01-08 03:07:20 +00:00
|
|
|
description = ''
|
|
|
|
mapping from "user@host" to pubkey.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
2023-01-08 08:43:23 +00:00
|
|
|
|
|
|
|
config = {
|
|
|
|
# persist the host key
|
|
|
|
# prefer specifying it via environment.etc since although it is generated per-host,
|
|
|
|
# it's made to be immutable after generation. hence, a `persist`-style mount wouldn't be as great.
|
|
|
|
environment.etc."ssh/host_keys".source = "/nix/persist/etc/ssh/host_keys";
|
2023-11-08 15:32:50 +00:00
|
|
|
# sane.persist.sys.byStore.plaintext = [ "/etc/ssh/host_keys" ];
|
2023-01-08 08:43:23 +00:00
|
|
|
|
|
|
|
# let openssh find our host keys
|
|
|
|
services.openssh.hostKeys = [
|
|
|
|
{ type = "rsa"; bits = 4096; path = "/etc/ssh/host_keys/ssh_host_rsa_key"; }
|
|
|
|
{ type = "ed25519"; path = "/etc/ssh/host_keys/ssh_host_ed25519_key"; }
|
|
|
|
];
|
2023-01-08 08:51:06 +00:00
|
|
|
|
|
|
|
services.openssh.knownHosts =
|
|
|
|
let
|
|
|
|
host-keys = filter (k: k.user == "root") (attrValues config.sane.ssh.pubkeys);
|
|
|
|
in lib.mkMerge (builtins.map (key: {
|
|
|
|
"${key.host}".publicKey = key.typedPubkey;
|
|
|
|
}) host-keys);
|
2023-01-08 08:43:23 +00:00
|
|
|
};
|
2023-01-08 03:07:20 +00:00
|
|
|
}
|