Overhaul secrets management

pull/30/head
Simon Bruder 2021-01-06 13:09:29 +01:00
parent 826e196891
commit 7b2da0349c
Signed by: simon
GPG Key ID: 8D3C82F9F309F8EC
6 changed files with 126 additions and 89 deletions

View File

@ -20,12 +20,12 @@
./locales.nix
./media-proxy.nix
./network-manager.nix
./nginx.nix
./office.nix
./prometheus/node_exporter.nix
./pubkeys.nix
./pulseaudio.nix
./restic.nix
./secrets.nix
./ssd.nix
./ssh.nix
./tools.nix

View File

@ -2,41 +2,48 @@
let
port = 8888;
services = {
"media" = <secrets/media-proxy-auth>;
"scan" = <secrets/media-proxy-auth>;
"torrent" = <secrets/torrent-proxy-auth>;
"media" = config.krops.secrets.media-proxy-auth.path;
"scan" = config.krops.secrets.media-proxy-auth.path;
"torrent" = config.krops.secrets.torrent-proxy-auth.path;
};
in
{
options.sbruder.media-proxy.enable = lib.mkEnableOption "media proxy";
config.services.nginx = lib.mkIf config.sbruder.media-proxy.enable {
enable = true;
secrets = builtins.attrValues services;
virtualHosts.media-proxy = {
serverName = "localhost";
listen = [
{ inherit port; addr = "127.0.0.1"; }
{ inherit port; addr = "[::1]"; }
];
locations = {
"/".extraConfig = ''
rewrite ^/__assets/(.*)$ /media/__assets/$1;
'';
} // lib.mapAttrs'
(name: secret: {
name = "/${name}/";
value = {
proxyPass = "https://${name}.sbruder.de/";
proxyWebsockets = true;
extraConfig = ''
proxy_buffering off;
include /run/nginx/secrets/${lib.last (lib.splitString "/" (toString secret))};
charset utf-8;
'';
};
})
services;
config = lib.mkIf config.sbruder.media-proxy.enable {
krops.secrets = {
torrent-proxy-auth.group = "nginx";
media-proxy-auth.group = "nginx";
};
users.users.nginx.extraGroups = [ "keys" ];
services.nginx = {
enable = true;
virtualHosts.media-proxy = {
serverName = "localhost";
listen = [
{ inherit port; addr = "127.0.0.1"; }
{ inherit port; addr = "[::1]"; }
];
locations = {
"/".extraConfig = ''
rewrite ^/__assets/(.*)$ /media/__assets/$1;
'';
} // lib.mapAttrs'
(name: secret: {
name = "/${name}/";
value = {
proxyPass = "https://${name}.sbruder.de/";
proxyWebsockets = true;
extraConfig = ''
proxy_buffering off;
include ${secret};
charset utf-8;
'';
};
})
services;
};
};
};
}

View File

@ -1,40 +0,0 @@
{ config, lib, ... }:
let
cfg = config.services.nginx;
in
{
options.services.nginx.secrets = lib.mkOption {
type = with lib.types; listOf (either str path);
default = [ ];
description = "Secrets to be copied to `/run/nginx/secrets/`";
};
config.systemd = lib.mkIf (lib.length cfg.secrets != 0) {
services = {
nginx-secrets = {
description = "Secrets for nginx";
wantedBy = [ "nginx.service" ];
partOf = [ "nginx.service" ];
serviceConfig.Type = "oneshot";
script = ''
rm -rf /run/nginx/secrets
install -o ${cfg.user} -g ${cfg.group} -m 700 -d /run/nginx/secrets
'' + lib.concatStrings (map
(secret: ''
install -o ${cfg.user} -g ${cfg.group} -m 600 ${toString secret} /run/nginx/secrets
'')
cfg.secrets);
};
nginx.after = [ "nginx-secrets.service" ];
};
paths.nginx-secrets = {
wantedBy = [ "nginx-secrets.service" ];
partOf = [ "nginx-secrets.service" ];
pathConfig = {
PathModified = "/var/src/secrets";
Unit = "nginx-secrets.service";
};
};
};
}

View File

@ -68,10 +68,15 @@ in
};
config = lib.mkIf cfg.enable {
krops.secrets = {
restic-password = { };
restic-s3 = { };
};
services.restic.backups."${name}" = {
inherit repository;
passwordFile = toString <secrets/restic-password>;
s3CredentialsFile = toString <secrets/restic-s3>;
passwordFile = config.krops.secrets.restic-password.path;
s3CredentialsFile = config.krops.secrets.restic-s3.path;
paths = [
"/home"
"/srv"

66
modules/secrets.nix Normal file
View File

@ -0,0 +1,66 @@
# Adapted from https://github.com/Mic92/dotfiles/blob/23f163cae52545d44a7e379dc204010b013d679a/nixos/vms/modules/secrets.nix
#
# All of the users wanting to access any key under /run/keys have to be a
# member of the keys group (or be root). This is a hard coded limitation of
# NixOS and I havent found a way to allow everyone to access /run/keys/ (not a
# security problem since the keys themselves are given the right permissions).
{ config, lib, pkgs, ... }:
let
secret = lib.types.submodule ({ config, ... }: {
options = {
name = lib.mkOption {
type = lib.types.str;
default = config._module.args.name;
};
path = lib.mkOption {
type = lib.types.str;
default = "/run/keys/${config.name}";
};
mode = lib.mkOption {
type = lib.types.str;
default = "0440";
};
owner = lib.mkOption {
type = lib.types.str;
default = "root";
};
group = lib.mkOption {
type = lib.types.str;
default = "root";
};
source = lib.mkOption {
type = lib.types.str;
default = toString <secrets> + "/${config.name}";
};
};
});
in
{
options.krops.secrets = lib.mkOption {
type = lib.types.attrsOf secret;
default = { };
};
config = lib.mkIf (config.krops.secrets != { }) {
system.activationScripts.setup-secrets =
let
script = ''
echo "setting up secrets"
'' + lib.concatMapStringsSep
"\n"
(secret: ''
${pkgs.coreutils}/bin/install \
-D \
--compare \
--verbose \
--mode=${lib.escapeShellArg secret.mode} \
--owner=${lib.escapeShellArg secret.owner} \
--group=${lib.escapeShellArg secret.group} \
${lib.escapeShellArg secret.source} \
${lib.escapeShellArg secret.path} \
|| echo "failed to copy ${secret.source} to ${secret.path}"
'')
(lib.attrValues config.krops.secrets);
in
lib.stringAfter [ "users" "groups" ] "source ${pkgs.writeText "setup-secrets.sh" script}";
};
}

View File

@ -11,24 +11,23 @@ in
description = "IP(v4) address of the host";
example = "10.80.0.1";
};
privateKeyFile = lib.mkOption {
type = lib.types.str;
description = "Private key file";
default = toString <secrets/wg-home-private-key>;
};
};
};
config.networking.wireguard.interfaces.wg-home = lib.mkIf cfg.enable {
privateKeyFile = cfg.privateKeyFile;
ips = [ "${cfg.address}/24" ];
peers = [
{
allowedIPs = [ "10.80.0.0/24" ];
publicKey = "UyZRAVTIc/RMs/J+591wrA8lHU0e8dwDJJwcpRb3xQA=";
endpoint = "87.140.16.73:51820"; # IPv6 is tunneled so legacy is preferred
persistentKeepalive = 25;
}
];
config = lib.mkIf cfg.enable {
krops.secrets.wg-home-private-key = { };
networking.wireguard.interfaces.wg-home = {
privateKeyFile = config.krops.secrets.wg-home-private-key.path;
ips = [ "${cfg.address}/24" ];
peers = [
{
allowedIPs = [ "10.80.0.0/24" ];
publicKey = "UyZRAVTIc/RMs/J+591wrA8lHU0e8dwDJJwcpRb3xQA=";
endpoint = "87.140.16.73:51820"; # IPv6 is tunneled so legacy is preferred
persistentKeepalive = 25;
}
];
};
};
}