From 962abd52e7127ad400c49ada7a3600e8ebbf59a7 Mon Sep 17 00:00:00 2001 From: Niten Date: Thu, 22 Apr 2021 11:38:52 -0700 Subject: [PATCH] Working on secrets --- config/host-config/limina.nix | 12 ++---- config/host-config/plato.nix | 53 ++++++++++++++++++------- config/host-config/procul.nix | 28 ++++++++++---- lib/fudo/secrets.nix | 73 +++++++++++++++++------------------ 4 files changed, 98 insertions(+), 68 deletions(-) diff --git a/config/host-config/limina.nix b/config/host-config/limina.nix index 1e9986c..be242ed 100644 --- a/config/host-config/limina.nix +++ b/config/host-config/limina.nix @@ -15,11 +15,6 @@ let in { config = { - # TODO: remove? - nixpkgs.config.permittedInsecurePackages = [ - "openssh-with-gssapi-8.4p1" # CVE-2021-28041 - ]; - networking = { interfaces = { enp1s0 = { useDHCP = true; }; @@ -64,11 +59,10 @@ in { network-definition = config.fudo.networks.${domain-name}; }; - secrets = { - backplane-client-limina-passwd = { + secrets.limina = { + backplane-client-passwd = { source-file = /srv/secrets/backplane-client/limina.passwd; target-file = "/srv/backplane/dns/client.passwd"; - target-host = "limina"; user = config.fudo.client.dns.user; }; }; @@ -80,7 +74,7 @@ in { user = "fudo-client"; external-interface = "enp1s0"; password-file = - config.fudo.secrets.backplane-client-limina-passwd.target-file; + config.fudo.secrets.limina.backplane-client-passwd.target-file; }; garbage-collector = { diff --git a/config/host-config/plato.nix b/config/host-config/plato.nix index 9ac5c7e..b5b2aed 100644 --- a/config/host-config/plato.nix +++ b/config/host-config/plato.nix @@ -1,14 +1,47 @@ { config, lib, pkgs, ... }: with lib; -let primary-ip = "10.0.0.21"; +let + primary-ip = "10.0.0.21"; + deploy-group = "nixops-deploy"; + secrets-path = /srv/secrets; + in { config = { + users.groups = { ${deploy-group} = { members = [ "niten" ]; }; }; - # TODO: remove? - nixpkgs.config.permittedInsecurePackages = [ - "openssh-with-gssapi-8.4p1" # CVE-2021-28041 - ]; + systemd = let secrets-watcher-name = "secrets-ownership-fixer"; + in { + paths.${secrets-watcher-name} = { + description = "Watch ${secrets-path} and correct perms on change."; + wantedBy = [ "multi-user.target" ]; + pathConfig = { + PathChanged = secrets-path; + Unit = "${secrets-watcher-name}.service"; + }; + }; + + services.${secrets-watcher-name} = { + wantedBy = [ "multi-user.target" ]; + description = "Correct perms on ${secrets-path}."; + serviceConfig = { + ExecStart = pkgs.writeShellScript "${secrets-watcher-name}.sh" '' + chown -R root:${deploy-group} ${secrets-path} + chmod -R ug=rX,o= ${secrets-path} + ''; + }; + }; + + tmpfiles.rules = [ + "L /root/.gnupg - - - - /state/root/gnupg" + # "L /root/.emacs.d - - - - /state/root/emacs.d" + "L /root/.ssh/id_rsa - - - - /state/root/ssh/id_rsa" + "L /root/.ssh/id_rsa.pub - - - - /state/root/ssh/id_rsa.pub" + "L /root/.ssh/known_hosts - - - - /state/root/ssh/known_hosts" + "L /etc/ssh/ssh_host_ed25519_key - - - - /state/ssh/ssh_host_ed25519_key" + "L /etc/ssh/ssh_host_rsa_key - - - - /state/ssh/ssh_host_rsa_key" + ]; + }; environment.etc = { nixos.source = "/state/nixos"; @@ -35,16 +68,6 @@ in { Defaults lecture = never ''; - systemd.tmpfiles.rules = [ - "L /root/.gnupg - - - - /state/root/gnupg" - # "L /root/.emacs.d - - - - /state/root/emacs.d" - "L /root/.ssh/id_rsa - - - - /state/root/ssh/id_rsa" - "L /root/.ssh/id_rsa.pub - - - - /state/root/ssh/id_rsa.pub" - "L /root/.ssh/known_hosts - - - - /state/root/ssh/known_hosts" - "L /etc/ssh/ssh_host_ed25519_key - - - - /state/ssh/ssh_host_ed25519_key" - "L /etc/ssh/ssh_host_rsa_key - - - - /state/ssh/ssh_host_rsa_key" - ]; - networking = { defaultGateway = { address = "10.0.0.1"; diff --git a/config/host-config/procul.nix b/config/host-config/procul.nix index 173a83c..62a283e 100644 --- a/config/host-config/procul.nix +++ b/config/host-config/procul.nix @@ -71,13 +71,24 @@ in { fudo = { hosts.procul.external-interfaces = [ "extif0" ]; - secrets = { - backplane-client-limina-passwd = { + secrets.procul = { + backplane-client-passwd = { source-file = /srv/secrets/backplane-client/procul.passwd; target-file = "/srv/backplane/dns/client.passwd"; - target-host = "procul"; user = config.fudo.client.dns.user; }; + + postgres-keytab = { + source-file = /srv/secrets/kerberos/procul-postgres.keytab; + target-file = "/srv/postgres/secure/postgres.keytab"; + user = "root"; + }; + + gitea-database-password = { + source-file = /srv/secrets/gitea/procul-database.passwd; + target-file = "/srv/gitea/secure/database.passwd"; + user = config.fudo.git.user; + }; }; client.dns = { @@ -86,7 +97,8 @@ in { ipv6 = true; user = "fudo-client"; external-interface = "extif0"; - password-file = "/srv/backplane/dns/client.passwd"; + password-file = + config.fudo.secrets.procul.backplane-client-passwd.target-file; }; auth.kdc = { @@ -183,12 +195,13 @@ in { enable = true; ssl-certificate = (acme-certificate host-fqdn); ssl-private-key = (acme-private-key host-fqdn); - keytab = "/srv/postgres/secure/postgres.keytab"; + keytab = config.fudo.secrets.procul.postgres-keytab.target-file; local-networks = local-networks; users = { gituser = { - password-file = "/srv/git/secure/db.passwd"; + password-file = + config.fudo.secrets.procul.gitea-database-password.target-file; databases = { git = { access = "CONNECT"; @@ -213,7 +226,8 @@ in { state-dir = /srv/git/state; database = { user = "gituser"; - password-file = /srv/git/secure/db.passwd; + password-file = + config.fudo.secrets.procul.gitea-database-password.target-file; hostname = "127.0.0.1"; name = "git"; }; diff --git a/lib/fudo/secrets.nix b/lib/fudo/secrets.nix index 8073d99..420fd7f 100644 --- a/lib/fudo/secrets.nix +++ b/lib/fudo/secrets.nix @@ -2,12 +2,9 @@ with lib; let - all-secrets = config.fudo.secrets; - - encrypt-on-disk = name: - { target-host, source-file }: + encrypt-on-disk = { secret-name, target-host, source-file }: pkgs.stdenv.mkDerivation { - name = "${name}-secret"; + name = "${target-host}-${secret-name}-secret"; phases = "installPhase"; buildInputs = [ pkgs.age ]; installPhase = let key = config.fudo.hosts.${target-host}.ssh-pubkey; @@ -16,41 +13,42 @@ let ''; }; - decrypt-script = name: - { source-file, target-host, target-file, decrypt-key, user, group - , permissions }: - pkgs.writeShellScript "decrypt-fudo-secret-${name}.sh" '' + decrypt-script = { secret-name, source-file, target-host, target-file + , decrypt-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 name { inherit source-file target-host; } + encrypt-on-disk { inherit secret-name source-file target-host; } } chown ${user}:${group} ${target-file} chmod ${permissions} ${target-file} ''; - secret-service = name: - { source-file, target-host, target-file, user, group, permissions - , key-type ? "ed25519" }: { - description = "decrypt secret ${name} for ${target-host}."; + secret-service = target-host: secret-name: + { source-file, target-file, user, group, permissions, key-type ? "ed25519" + }: { + description = "decrypt secret ${secret-name} for ${target-host}."; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; - ExecStartPre = pkgs.writeShellScript "prepare-${name}-secret-dir.sh" '' - TARGET_DIR=$(dirname ${target-file}) - if [[ ! -d "$TARGET_DIR" ]]; then - mkdir -p "$TARGET_DIR" - fi - ''; - ExecStop = pkgs.writeShellScript "clear-${name}-secret.sh" '' + ExecStartPre = pkgs.writeShellScript + "prepare-${target-host}-${secret-name}-secret-dir.sh" '' + TARGET_DIR=$(dirname ${target-file}) + if [[ ! -d "$TARGET_DIR" ]]; then + mkdir -p "$TARGET_DIR" + fi + ''; + ExecStop = pkgs.writeShellScript "clear-${secret-name}-secret.sh" '' rm -f ${target-file} ''; ExecStart = let decrypt-keys = filter (key: key.type == key-type) config.services.openssh.hostKeys; decrypt-key = head (map (key: key.path) decrypt-keys); - in decrypt-script name { - inherit source-file target-host target-file decrypt-key user group - permissions; + in decrypt-script { + inherit secret-name source-file target-host target-file decrypt-key + user group permissions; }; }; path = [ pkgs.age ]; @@ -63,12 +61,6 @@ let description = "File from which to load the secret."; }; - target-host = mkOption { - type = str; - description = - "Host to which the secret belongs (determins SSH key to encrypt)."; - }; - target-file = mkOption { type = str; description = @@ -97,19 +89,26 @@ let in { options.fudo.secrets = with types; mkOption { - type = attrsOf (submodule secretOpts); - description = "Map of secrets to secret config."; + type = attrsOf (attrsOf (submodule secretOpts)); + description = "Map of hosts, to secrets, to secret config."; default = { }; + example = { + my-host = { + my-host-secret = { + source-file = /path/to/file/on/this/host; + target-file = "/target/path/on/host"; + user = "some-user"; + }; + }; + }; }; config = { systemd.services = let hostname = config.instance.hostname; - host-secrets = - filterAttrs (secret: secretOpts: secretOpts.target-host == hostname) - all-secrets; + host-secrets = config.fudo.secrets.${hostname}; in mapAttrs' (secret: secretOpts: - (nameValuePair "fudo-secret-${secret}" - (secret-service secret secretOpts))) host-secrets; + (nameValuePair "fudo-secret-${hostname}-${secret}" + (secret-service hostname secret secretOpts))) host-secrets; }; }