Working flake check

This commit is contained in:
2021-09-30 08:40:47 -07:00
parent 4df4d2e7db
commit b690935dea
31 changed files with 246 additions and 209 deletions
+8 -6
View File
@@ -2,7 +2,9 @@
with lib;
let
sys = callPackage ../system.nix {};
sys = import ../system.nix { inherit config lib; };
hostname = config.instance.hostname;
site-cfg = config.fudo.sites.${sys.local-site};
@@ -13,9 +15,9 @@ let
enable-distributed-builds =
site-cfg.enable-distributed-builds && has-build-servers && build-keypair != null;
local-build-cfg =
mkIf (hasKey site-cfg.build-servers hostname)
site-cfg.build-servers.hostname;
local-build-cfg = if (hasAttr hostname site-cfg.build-servers) then
site-cfg.build-servers.${hostname}
else null;
in {
config = {
@@ -39,8 +41,8 @@ in {
${local-build-cfg.build-user} = {
isSystemUser = true;
openssh.authorizedKeys.keyFiles =
foldr (a: b: a ++ b) []
mapAttrsToList (host: hostOpts: hostOpts.build-pubkeys) sys.local-hosts;
concatLists
(mapAttrsToList (host: hostOpts: hostOpts.build-pubkeys) sys.local-hosts);
};
};
};
+1 -1
View File
@@ -139,7 +139,7 @@ in {
$TTL 12h
@ IN SOA ns1.${dom}. hostmaster.${dom}. (
${toString builtins.currentTime}
${toString config.instance.build-timestamp}
30m
2m
3w
+68 -32
View File
@@ -4,8 +4,28 @@ with lib;
let
mapOptional = f: val: if (val != null) then (f val) else null;
masterKeyOpts = { ... }: {
options = with types; {
key-path = mkOption {
type = str;
description = "Path of the host master key file, used to decrypt secrets.";
};
public-key = mkOption {
type = str;
description = "Public key used during deployment to decrypt secrets for the host.";
};
};
};
hostOpts = { hostname, ... }: {
options = with types; {
master-key = mkOption {
type = nullOr (submodule masterKeyOpts);
description = "Public key for the host master key, used by the host to decrypt secrets.";
default = null;
};
domain = mkOption {
type = str;
description =
@@ -109,9 +129,9 @@ let
};
ssh-pubkeys = mkOption {
type = listOf str;
type = listOf path;
description =
"SSH keys of the host. Find with `ssh-keyscan`. Skip the hostname, just type and key.";
"SSH key files of the host.";
default = [];
};
@@ -150,6 +170,12 @@ let
description = "System architecture of the system.";
};
machine-id = mkOption {
type = nullOr str;
description = "Machine id of the system. See: man machine-id.";
default = null;
};
android-dev = mkEnableOption "Enable ADB on the host.";
};
};
@@ -187,23 +213,35 @@ in {
enable = (length host-cfg.external-interfaces) > 0;
allowedTCPPorts = [ 22 ];
};
hostId = mkIf (host-cfg.machine-id != null)
(substring 0 8 host-cfg.machine-id);
};
# NixOS generates a stupid hosts file, just force it
environment.etc.hosts = let
host-entries = mapAttrsToList
(ip: hostnames: "${ip} ${concatStringsSep " " hostnames}")
config.fudo.system.hostfile-entries;
in mkForce {
text = ''
environment.etc = {
hosts = let
host-entries = mapAttrsToList
(ip: hostnames: "${ip} ${concatStringsSep " " hostnames}")
config.fudo.system.hostfile-entries;
in mkForce {
text = ''
127.0.0.1 ${hostname}.${domain-name} ${hostname} localhost
127.0.0.2 ${hostname} localhost
::1 ${hostname}.${domain-name} ${hostname} localhost
${concatStringsSep "\n" host-entries}
'';
user = "root";
group = "root";
mode = "0444";
user = "root";
group = "root";
mode = "0444";
};
machine-id = mkIf (host-cfg.machine-id != null) {
text = host-cfg.machine-id;
user = "root";
group = "root";
mode = "0444";
};
};
# fudo.hosts.${hostname}.build-pubkeys =
@@ -269,31 +307,29 @@ in {
members = system.local-admins;
};
programs.ssh.knownHosts = let
keyed-hosts =
filterAttrs (host: opts: opts.ssh-pubkey != null) config.fudo.hosts;
# programs.ssh.knownHosts = let
# keyed-hosts =
# filterAttrs (host: opts: opts.ssh-pubkeys != []) config.fudo.hosts;
traceOut = obj: builtins.trace obj obj;
# crossProduct = f: list0: list1:
# concatMap (el0: map (el1: f el0 el1) list1) list0;
crossProduct = f: list0: list1:
concatMap (el0: map (el1: f el0 el1) list1) list0;
# getHostnames = hostOpts:
# [ hostOpts.hostname ]
# ++ (crossProduct (host: domain: "${host}.${domain}")
# ([ hostOpts.hostname ] ++ hostOpts.aliases)
# ([ hostOpts.domain ] ++ hostOpts.extra-domains));
getHostnames = hostOpts:
[ hostOpts.hostname ]
++ (crossProduct (host: domain: "${host}.${domain}")
([ hostOpts.hostname ] ++ hostOpts.aliases)
([ hostOpts.domain ] ++ hostOpts.extra-domains));
# getHostEntryPairs = host:
# map (hostname: nameValuePair hostname { publicKey = host.ssh-pubkey; })
# (getHostnames host);
getHostEntryPairs = host:
map (hostname: nameValuePair hostname { publicKey = host.ssh-pubkey; })
(getHostnames host);
# hostAttrsToList = hostAttrs:
# mapAttrsToList (hostname: opts: { hostname = hostname; } // opts)
# hostAttrs;
hostAttrsToList = hostAttrs:
mapAttrsToList (hostname: opts: { hostname = hostname; } // opts)
hostAttrs;
getKnownHosts = hosts:
concatMap getHostEntryPairs (hostAttrsToList hosts);
in listToAttrs (getKnownHosts keyed-hosts);
# getKnownHosts = hosts:
# concatMap getHostEntryPairs (hostAttrsToList hosts);
# in listToAttrs (getKnownHosts keyed-hosts);
};
}
+2 -7
View File
@@ -83,11 +83,6 @@ in {
description = "Definition of network to be served by local server.";
default = { };
};
timestamp = mkOption {
type = int;
description = "Timestamp of build, to be used as a serial.";
};
};
config = mkIf cfg.enable {
@@ -149,7 +144,7 @@ in {
$TTL 1h
@ IN SOA ns1.${cfg.domain}. hostmaster.${cfg.domain}. (
${toString cfg.timestamp}
${toString config.instance.build-timestamp}
1800
900
604800
@@ -206,7 +201,7 @@ in {
name = cfg.domain;
file = pkgs.writeText "${cfg.domain}-zone" ''
@ IN SOA ns1.${cfg.domain}. hostmaster.${cfg.domain}. (
${toString cfg.timestamp}
${toString config.instance.build-timestamp}
5m
2m
6w
+13 -14
View File
@@ -4,32 +4,33 @@ with lib;
let
cfg = config.fudo.secrets;
encrypt-on-disk = { secret-name, target-host, source-file }:
encrypt-on-disk = { secret-name, target-host, target-pubkey, source-file }:
pkgs.stdenv.mkDerivation {
name = "${target-host}-${secret-name}-secret";
phases = "installPhase";
buildInputs = [ pkgs.age ];
installPhase = let key = config.fudo.hosts.${target-host}.ssh-pubkey;
in ''
age -a -r "${key}" -o $out ${source-file}
installPhase = ''
age -a -r "${target-pubkey}" -o $out ${source-file}
'';
};
decrypt-script = { secret-name, source-file, target-host, target-file
, decrypt-key, user, group, permissions }:
, host-master-key, user, group, permissions }:
pkgs.writeShellScript
"decrypt-fudo-secret-${target-host}-${secret-name}.sh" ''
rm -rf ${target-file}
age -d -i ${decrypt-key} -o ${target-file} ${
encrypt-on-disk { inherit secret-name source-file target-host; }
age -d -i ${host-master-key.key-path} -o ${target-file} ${
encrypt-on-disk {
inherit secret-name source-file target-host;
target-pubkey = host-master-key.public-key;
}
}
chown ${user}:${group} ${target-file}
chmod ${permissions} ${target-file}
'';
secret-service = target-host: secret-name:
{ source-file, target-file, user, group, permissions, key-type ? "ed25519"
}: {
{ source-file, target-file, user, group, permissions }: {
description = "decrypt secret ${secret-name} for ${target-host}.";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
@@ -42,11 +43,9 @@ let
fi
'';
ExecStart = let
decrypt-keys =
filter (key: key.type == key-type) config.services.openssh.hostKeys;
decrypt-key = head (map (key: key.path) decrypt-keys);
host-master-key = config.fudo.hosts.${target-host}.master-key;
in decrypt-script {
inherit secret-name source-file target-host target-file decrypt-key
inherit secret-name source-file target-host target-file host-master-key
user group permissions;
};
};
@@ -56,7 +55,7 @@ let
secretOpts = { ... }: {
options = with types; {
source-file = mkOption {
type = path; # CAREFUL: this will copy the file to nixstore...I think?
type = path; # CAREFUL: this will copy the file to nixstore...keep on deploy host
description = "File from which to load the secret.";
};
+13 -19
View File
@@ -129,12 +129,6 @@ let
};
};
build-user = mkOption {
type = str;
description = "User as which to run builds.";
default = "nix-site-builder";
};
local-networks = mkOption {
type = listOf str;
description = "List of networks to consider local at this site.";
@@ -163,7 +157,7 @@ let
};
};
buildServerOpts = { ... }: {
buildServerOpts = { hostname, ... }: {
options = with types; {
port = mkOption {
type = port;
@@ -199,7 +193,7 @@ let
build-user = mkOption {
type = str;
description = "User as which to run distributed builds.";
default = "site-builder";
default = "nix-site-builder";
};
};
};
@@ -212,17 +206,17 @@ in {
};
config = {
users.users = {
${site-cfg.build-user} = mkIf
(any (build-host: build-host == config.instance.hostname)
(attrNames site-cfg.build-servers)) {
isSystemUser = true;
openssh.authorizedKeys.keys =
concatMap (hostOpts: hostOpts.build-pubkeys)
(attrValues site-hosts);
shell = pkgs.bash;
};
};
# users.users = {
# ${site-cfg.build-user} = mkIf
# (any (build-host: build-host == config.instance.hostname)
# (attrNames site-cfg.build-servers)) {
# isSystemUser = true;
# openssh.authorizedKeys.keys =
# concatMap (hostOpts: hostOpts.build-pubkeys)
# (attrValues site-hosts);
# shell = pkgs.bash;
# };
# };
networking.firewall.allowedTCPPorts =
mkIf site-cfg.enable-ssh-backdoor [ site-cfg.dropbear-ssh-port ];
+27 -15
View File
@@ -14,15 +14,16 @@ let
dns-sshfp-records = host: keypair: let
filename = sshfp-filename host keypair;
in mkDerivation {
in pkgs.stdenv.mkDerivation {
name = "${host}-sshfp-record";
phases = [ "installPhase" ];
buildInputs = with pkgs; [ openssh ];
buildPhase = ''
ssh-keygen -r REMOVEME -f ${keypair.public-key} | sed 's/^REMOVEME IN SSHFP //' > ${filename}
'';
installPhase = ''
mv ${filename} $out/${filename}
mkdir $out
ssh-keygen -r REMOVEME -f "${keypair.public-key}" | sed 's/^REMOVEME IN SSHFP //' > $out/${filename}
'';
};
@@ -42,7 +43,7 @@ in {
ssh-pubkeys = map (keypair: keypair.public-key) keypairs;
ssh-fingerprints = map (keypair:
let
fingerprint-derivation = dns-sshfp-records hostname keypair.public-key;
fingerprint-derivation = dns-sshfp-records hostname keypair;
filename = sshfp-filename hostname keypair;
in builtins.readFile "${fingerprint-derivation}/${filename}") keypairs;
}) config.fudo.secrets.files.host-ssh-keypairs;
@@ -55,13 +56,24 @@ in {
type = keypair.key-type;
}) host-keypairs;
programs.ssh.knownHosts = mapAttrs (hostname: keypairs: {
publicKeyFile = keypairs.public-key;
hostNames = let
host-cfg = config.fudo.hosts.${hostname};
domains = [host-cfg.domain] ++ host-cfg.extra-domains;
in [ hostname ] ++
(map (domain: "${hostname}.${domain}") domains);
});
programs.ssh.knownHosts = let
keyed-hosts =
filterAttrs (h: o: o.ssh-pubkeys != [])
config.fudo.hosts;
crossProduct = f: list0: list1:
concatMap (el0: map (el1: f el0 el1) list1) list0;
all-hostnames = opts:
[ opts.hostname ] ++
(crossProduct (host: domain: "${host}.${domain}")
([ opts.hostname ] ++ opts.aliases)
([ opts.domain ] ++ opts.extra-domains));
in mapAttrs (hostname: hostOpts: {
publicKeyFile = builtins.head hostOpts.ssh-pubkeys;
hostNames = all-hostnames host-cfg;
}) keyed-hosts;
};
}
+8 -5
View File
@@ -2,12 +2,15 @@
with lib;
{
options.instance = {
options.instance = with types; {
hostname = mkOption {
type = types.str;
description = ''
Hostname of this specific host (without domain).
'';
type = str;
description = "Hostname of this specific host (without domain).";
};
build-timestamp = mkOption {
type = int;
description = "Timestamp associated with the build. Used for e.g. DNS serials.";
};
};
}