Files
nix-stuff/common/ssh.nix
2025-02-21 16:10:34 -08:00

146 lines
5.3 KiB
Nix

{ lib, config, ... }:
let
inherit (lib)
mkOption
types
flip
concatMapStringsSep
optionalString
concatStringsSep
readFile
literalExpression
;
inherit (builtins) attrValues;
cfg = config.vacu;
knownHosts = attrValues cfg.ssh.knownHosts;
knownHostsText =
(flip (concatMapStringsSep "\n") knownHosts (
h:
assert h.hostNames != [ ];
optionalString h.certAuthority "@cert-authority "
+ concatStringsSep "," h.hostNames
+ " "
+ (if h.publicKey != null then h.publicKey else readFile h.publicKeyFile)
))
+ "\n";
in
{
options = {
vacu.ssh.knownHostsText = mkOption {
type = types.str;
readOnly = true;
default = knownHostsText;
};
#vacu.ssh.authorizedKeys = mkOption { type = types.listOf types.str; };
vacu.ssh.authorizedKeys = mkOption {
type = types.attrsOf types.str;
default = { };
};
vacu.ssh.config = mkOption { type = types.lines; };
# Straight copied from nixpkgs
# https://github.com/NixOS/nixpkgs/blob/46397778ef1f73414b03ed553a3368f0e7e33c2f/nixos/modules/programs/ssh.nix
vacu.ssh.knownHosts = mkOption {
default = { };
type = types.attrsOf (
types.submodule (
{
name,
config,
options,
...
}:
{
options = {
certAuthority = mkOption {
type = types.bool;
default = false;
description = ''
This public key is an SSH certificate authority, rather than an
individual host's key.
'';
};
hostNames = mkOption {
type = types.listOf types.str;
default = [ name ] ++ config.extraHostNames;
defaultText = literalExpression "[ ${name} ] ++ config.${options.extraHostNames}";
description = ''
A list of host names and/or IP numbers used for accessing
the host's ssh service. This list includes the name of the
containing `knownHosts` attribute by default
for convenience. If you wish to configure multiple host keys
for the same host use multiple `knownHosts`
entries with different attribute names and the same
`hostNames` list.
'';
};
extraHostNames = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
A list of additional host names and/or IP numbers used for
accessing the host's ssh service. This list is ignored if
`hostNames` is set explicitly.
'';
};
publicKey = mkOption {
default = null;
type = types.nullOr types.str;
example = "ecdsa-sha2-nistp521 AAAAE2VjZHN...UEPg==";
description = ''
The public key data for the host. You can fetch a public key
from a running SSH server with the {command}`ssh-keyscan`
command. The public key should not include any host names, only
the key type and the key itself.
'';
};
publicKeyFile = mkOption {
default = null;
type = types.nullOr types.path;
description = ''
The path to the public key file for the host. The public
key file is read at build time and saved in the Nix store.
You can fetch a public key file from a running SSH server
with the {command}`ssh-keyscan` command. The content
of the file should follow the same format as described for
the `publicKey` option. Only a single key
is supported. If a host has multiple keys, use
{option}`programs.ssh.knownHostsFiles` instead.
'';
};
};
}
)
);
description = ''
The set of system-wide known SSH hosts. To make simple setups more
convenient the name of an attribute in this set is used as a host name
for the entry. This behaviour can be disabled by setting
`hostNames` explicitly. You can use
`extraHostNames` to add additional host names without
disabling this default.
'';
example = literalExpression ''
{
myhost = {
extraHostNames = [ "myhost.mydomain.com" "10.10.1.4" ];
publicKeyFile = ./pubkeys/myhost_ssh_host_dsa_key.pub;
};
"myhost2.net".publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILIRuJ8p1Fi+m6WkHV0KWnRfpM1WxoW8XAS+XvsSKsTK";
"myhost2.net/dsa" = {
hostNames = [ "myhost2.net" ];
publicKeyFile = ./pubkeys/myhost2_ssh_host_dsa_key.pub;
};
}
'';
};
};
config.vacu.assertions = lib.flip lib.mapAttrsToList config.vacu.ssh.knownHosts (
name: data: {
assertion =
(data.publicKey == null && data.publicKeyFile != null)
|| (data.publicKey != null && data.publicKeyFile == null);
message = "knownHost ${name} must contain either a publicKey or publicKeyFile";
}
);
}