Working flake check
This commit is contained in:
@@ -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
@@ -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
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user