Working on secrets
This commit is contained in:
parent
5d572b3726
commit
962abd52e7
@ -15,11 +15,6 @@ let
|
|||||||
in {
|
in {
|
||||||
config = {
|
config = {
|
||||||
|
|
||||||
# TODO: remove?
|
|
||||||
nixpkgs.config.permittedInsecurePackages = [
|
|
||||||
"openssh-with-gssapi-8.4p1" # CVE-2021-28041
|
|
||||||
];
|
|
||||||
|
|
||||||
networking = {
|
networking = {
|
||||||
interfaces = {
|
interfaces = {
|
||||||
enp1s0 = { useDHCP = true; };
|
enp1s0 = { useDHCP = true; };
|
||||||
@ -64,11 +59,10 @@ in {
|
|||||||
network-definition = config.fudo.networks.${domain-name};
|
network-definition = config.fudo.networks.${domain-name};
|
||||||
};
|
};
|
||||||
|
|
||||||
secrets = {
|
secrets.limina = {
|
||||||
backplane-client-limina-passwd = {
|
backplane-client-passwd = {
|
||||||
source-file = /srv/secrets/backplane-client/limina.passwd;
|
source-file = /srv/secrets/backplane-client/limina.passwd;
|
||||||
target-file = "/srv/backplane/dns/client.passwd";
|
target-file = "/srv/backplane/dns/client.passwd";
|
||||||
target-host = "limina";
|
|
||||||
user = config.fudo.client.dns.user;
|
user = config.fudo.client.dns.user;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -80,7 +74,7 @@ in {
|
|||||||
user = "fudo-client";
|
user = "fudo-client";
|
||||||
external-interface = "enp1s0";
|
external-interface = "enp1s0";
|
||||||
password-file =
|
password-file =
|
||||||
config.fudo.secrets.backplane-client-limina-passwd.target-file;
|
config.fudo.secrets.limina.backplane-client-passwd.target-file;
|
||||||
};
|
};
|
||||||
|
|
||||||
garbage-collector = {
|
garbage-collector = {
|
||||||
|
@ -1,14 +1,47 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
with lib;
|
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 {
|
in {
|
||||||
config = {
|
config = {
|
||||||
|
users.groups = { ${deploy-group} = { members = [ "niten" ]; }; };
|
||||||
|
|
||||||
# TODO: remove?
|
systemd = let secrets-watcher-name = "secrets-ownership-fixer";
|
||||||
nixpkgs.config.permittedInsecurePackages = [
|
in {
|
||||||
"openssh-with-gssapi-8.4p1" # CVE-2021-28041
|
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 = {
|
environment.etc = {
|
||||||
nixos.source = "/state/nixos";
|
nixos.source = "/state/nixos";
|
||||||
@ -35,16 +68,6 @@ in {
|
|||||||
Defaults lecture = never
|
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 = {
|
networking = {
|
||||||
defaultGateway = {
|
defaultGateway = {
|
||||||
address = "10.0.0.1";
|
address = "10.0.0.1";
|
||||||
|
@ -71,13 +71,24 @@ in {
|
|||||||
fudo = {
|
fudo = {
|
||||||
hosts.procul.external-interfaces = [ "extif0" ];
|
hosts.procul.external-interfaces = [ "extif0" ];
|
||||||
|
|
||||||
secrets = {
|
secrets.procul = {
|
||||||
backplane-client-limina-passwd = {
|
backplane-client-passwd = {
|
||||||
source-file = /srv/secrets/backplane-client/procul.passwd;
|
source-file = /srv/secrets/backplane-client/procul.passwd;
|
||||||
target-file = "/srv/backplane/dns/client.passwd";
|
target-file = "/srv/backplane/dns/client.passwd";
|
||||||
target-host = "procul";
|
|
||||||
user = config.fudo.client.dns.user;
|
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 = {
|
client.dns = {
|
||||||
@ -86,7 +97,8 @@ in {
|
|||||||
ipv6 = true;
|
ipv6 = true;
|
||||||
user = "fudo-client";
|
user = "fudo-client";
|
||||||
external-interface = "extif0";
|
external-interface = "extif0";
|
||||||
password-file = "/srv/backplane/dns/client.passwd";
|
password-file =
|
||||||
|
config.fudo.secrets.procul.backplane-client-passwd.target-file;
|
||||||
};
|
};
|
||||||
|
|
||||||
auth.kdc = {
|
auth.kdc = {
|
||||||
@ -183,12 +195,13 @@ in {
|
|||||||
enable = true;
|
enable = true;
|
||||||
ssl-certificate = (acme-certificate host-fqdn);
|
ssl-certificate = (acme-certificate host-fqdn);
|
||||||
ssl-private-key = (acme-private-key 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;
|
local-networks = local-networks;
|
||||||
|
|
||||||
users = {
|
users = {
|
||||||
gituser = {
|
gituser = {
|
||||||
password-file = "/srv/git/secure/db.passwd";
|
password-file =
|
||||||
|
config.fudo.secrets.procul.gitea-database-password.target-file;
|
||||||
databases = {
|
databases = {
|
||||||
git = {
|
git = {
|
||||||
access = "CONNECT";
|
access = "CONNECT";
|
||||||
@ -213,7 +226,8 @@ in {
|
|||||||
state-dir = /srv/git/state;
|
state-dir = /srv/git/state;
|
||||||
database = {
|
database = {
|
||||||
user = "gituser";
|
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";
|
hostname = "127.0.0.1";
|
||||||
name = "git";
|
name = "git";
|
||||||
};
|
};
|
||||||
|
@ -2,12 +2,9 @@
|
|||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
let
|
let
|
||||||
all-secrets = config.fudo.secrets;
|
encrypt-on-disk = { secret-name, target-host, source-file }:
|
||||||
|
|
||||||
encrypt-on-disk = name:
|
|
||||||
{ target-host, source-file }:
|
|
||||||
pkgs.stdenv.mkDerivation {
|
pkgs.stdenv.mkDerivation {
|
||||||
name = "${name}-secret";
|
name = "${target-host}-${secret-name}-secret";
|
||||||
phases = "installPhase";
|
phases = "installPhase";
|
||||||
buildInputs = [ pkgs.age ];
|
buildInputs = [ pkgs.age ];
|
||||||
installPhase = let key = config.fudo.hosts.${target-host}.ssh-pubkey;
|
installPhase = let key = config.fudo.hosts.${target-host}.ssh-pubkey;
|
||||||
@ -16,41 +13,42 @@ let
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
decrypt-script = name:
|
decrypt-script = { secret-name, source-file, target-host, target-file
|
||||||
{ source-file, target-host, target-file, decrypt-key, user, group
|
, decrypt-key, user, group, permissions }:
|
||||||
, permissions }:
|
pkgs.writeShellScript
|
||||||
pkgs.writeShellScript "decrypt-fudo-secret-${name}.sh" ''
|
"decrypt-fudo-secret-${target-host}-${secret-name}.sh" ''
|
||||||
rm -rf ${target-file}
|
rm -rf ${target-file}
|
||||||
age -d -i ${decrypt-key} -o ${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}
|
chown ${user}:${group} ${target-file}
|
||||||
chmod ${permissions} ${target-file}
|
chmod ${permissions} ${target-file}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
secret-service = name:
|
secret-service = target-host: secret-name:
|
||||||
{ source-file, target-host, target-file, user, group, permissions
|
{ source-file, target-file, user, group, permissions, key-type ? "ed25519"
|
||||||
, key-type ? "ed25519" }: {
|
}: {
|
||||||
description = "decrypt secret ${name} for ${target-host}.";
|
description = "decrypt secret ${secret-name} for ${target-host}.";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
ExecStartPre = pkgs.writeShellScript "prepare-${name}-secret-dir.sh" ''
|
ExecStartPre = pkgs.writeShellScript
|
||||||
TARGET_DIR=$(dirname ${target-file})
|
"prepare-${target-host}-${secret-name}-secret-dir.sh" ''
|
||||||
if [[ ! -d "$TARGET_DIR" ]]; then
|
TARGET_DIR=$(dirname ${target-file})
|
||||||
mkdir -p "$TARGET_DIR"
|
if [[ ! -d "$TARGET_DIR" ]]; then
|
||||||
fi
|
mkdir -p "$TARGET_DIR"
|
||||||
'';
|
fi
|
||||||
ExecStop = pkgs.writeShellScript "clear-${name}-secret.sh" ''
|
'';
|
||||||
|
ExecStop = pkgs.writeShellScript "clear-${secret-name}-secret.sh" ''
|
||||||
rm -f ${target-file}
|
rm -f ${target-file}
|
||||||
'';
|
'';
|
||||||
ExecStart = let
|
ExecStart = let
|
||||||
decrypt-keys =
|
decrypt-keys =
|
||||||
filter (key: key.type == key-type) config.services.openssh.hostKeys;
|
filter (key: key.type == key-type) config.services.openssh.hostKeys;
|
||||||
decrypt-key = head (map (key: key.path) decrypt-keys);
|
decrypt-key = head (map (key: key.path) decrypt-keys);
|
||||||
in decrypt-script name {
|
in decrypt-script {
|
||||||
inherit source-file target-host target-file decrypt-key user group
|
inherit secret-name source-file target-host target-file decrypt-key
|
||||||
permissions;
|
user group permissions;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
path = [ pkgs.age ];
|
path = [ pkgs.age ];
|
||||||
@ -63,12 +61,6 @@ let
|
|||||||
description = "File from which to load the secret.";
|
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 {
|
target-file = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description =
|
description =
|
||||||
@ -97,19 +89,26 @@ let
|
|||||||
in {
|
in {
|
||||||
options.fudo.secrets = with types;
|
options.fudo.secrets = with types;
|
||||||
mkOption {
|
mkOption {
|
||||||
type = attrsOf (submodule secretOpts);
|
type = attrsOf (attrsOf (submodule secretOpts));
|
||||||
description = "Map of secrets to secret config.";
|
description = "Map of hosts, to secrets, to secret config.";
|
||||||
default = { };
|
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 = {
|
config = {
|
||||||
systemd.services = let
|
systemd.services = let
|
||||||
hostname = config.instance.hostname;
|
hostname = config.instance.hostname;
|
||||||
host-secrets =
|
host-secrets = config.fudo.secrets.${hostname};
|
||||||
filterAttrs (secret: secretOpts: secretOpts.target-host == hostname)
|
|
||||||
all-secrets;
|
|
||||||
in mapAttrs' (secret: secretOpts:
|
in mapAttrs' (secret: secretOpts:
|
||||||
(nameValuePair "fudo-secret-${secret}"
|
(nameValuePair "fudo-secret-${hostname}-${secret}"
|
||||||
(secret-service secret secretOpts))) host-secrets;
|
(secret-service hostname secret secretOpts))) host-secrets;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user