From 7b2da0349c80107d82fe09695e94b3e0456bed72 Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Wed, 6 Jan 2021 13:09:29 +0100 Subject: [PATCH] Overhaul secrets management --- modules/default.nix | 2 +- modules/media-proxy.nix | 67 +++++++++++++++++++++----------------- modules/nginx.nix | 40 ----------------------- modules/restic.nix | 9 +++-- modules/secrets.nix | 66 +++++++++++++++++++++++++++++++++++++ modules/wireguard/home.nix | 31 +++++++++--------- 6 files changed, 126 insertions(+), 89 deletions(-) delete mode 100644 modules/nginx.nix create mode 100644 modules/secrets.nix diff --git a/modules/default.nix b/modules/default.nix index 875be04..c983c67 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -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 diff --git a/modules/media-proxy.nix b/modules/media-proxy.nix index 8283dd7..6abdabb 100644 --- a/modules/media-proxy.nix +++ b/modules/media-proxy.nix @@ -2,41 +2,48 @@ let port = 8888; services = { - "media" = ; - "scan" = ; - "torrent" = ; + "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; + }; }; }; } diff --git a/modules/nginx.nix b/modules/nginx.nix deleted file mode 100644 index 383b113..0000000 --- a/modules/nginx.nix +++ /dev/null @@ -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"; - }; - }; - }; -} diff --git a/modules/restic.nix b/modules/restic.nix index 6f49214..8b0be71 100644 --- a/modules/restic.nix +++ b/modules/restic.nix @@ -68,10 +68,15 @@ in }; config = lib.mkIf cfg.enable { + krops.secrets = { + restic-password = { }; + restic-s3 = { }; + }; + services.restic.backups."${name}" = { inherit repository; - passwordFile = toString ; - s3CredentialsFile = toString ; + passwordFile = config.krops.secrets.restic-password.path; + s3CredentialsFile = config.krops.secrets.restic-s3.path; paths = [ "/home" "/srv" diff --git a/modules/secrets.nix b/modules/secrets.nix new file mode 100644 index 0000000..3ea55cf --- /dev/null +++ b/modules/secrets.nix @@ -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 haven’t 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 + "/${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}"; + }; +} diff --git a/modules/wireguard/home.nix b/modules/wireguard/home.nix index 6eb3b69..3ff2a8e 100644 --- a/modules/wireguard/home.nix +++ b/modules/wireguard/home.nix @@ -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 ; - }; }; }; - 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; + } + ]; + }; }; }