diff --git a/ops/vault/cfg/acme-ca.nix b/ops/vault/cfg/acme-ca.nix new file mode 100644 index 0000000000..312dc1eabe --- /dev/null +++ b/ops/vault/cfg/acme-ca.nix @@ -0,0 +1,48 @@ +{ ... }: + +{ + imports = [ ./module-acme-ca.nix ]; + + my.acme.accounts = let + base = { + key_type = "EC256"; + ignore_dns_propagation = true; + }; + letsencrypt = base // { + contact = "letsencrypt@lukegb.com"; + terms_of_service_agreed = true; + }; + letsencrypt-staging = letsencrypt // { + server_url = "https://acme-staging-v02.api.letsencrypt.org/directory"; + }; + letsencrypt-prod = letsencrypt // { + server_url = "https://acme-v02.api.letsencrypt.org/directory"; + }; + + cloudflare = t: t // { + provider = "cloudflare"; + provider_configuration.CLOUDFLARE_DNS_API_TOKEN = "\${data.vault_generic_secret.misc.data[\"cloudflareToken\"]}"; + }; + gcloud-as205479 = t: t // { + provider = "gcloud"; + provider_configuration.GCE_PROJECT = "as205479-177317"; + }; + in { + letsencrypt-cloudflare = cloudflare letsencrypt-prod; + letsencrypt-staging-cloudflare = cloudflare letsencrypt-staging; + + letsencrypt-gcloud-as205479 = gcloud-as205479 letsencrypt-prod; + letsencrypt-staging-gcloud-as205479 = gcloud-as205479 letsencrypt-staging; + }; + + my.acme.roles = let + cloudflareDomains = [ "lukegb.com" "bfob.gg" "lukegb.dev" "lukegb.tech" "lukegb.xyz" "zxcvbnm.ninja" ]; + gcloudDomains = [ "as205479.net" "event.lukegb.tech" "tech.lukegb.tech" ]; + in { + letsencrypt-cloudflare.allowed_domains = cloudflareDomains; + letsencrypt-staging-cloudflare.allowed_domains = cloudflareDomains; + + letsencrypt-gcloud-as205479.allowed_domains = gcloudDomains; + letsencrypt-staging-gcloud-as205479.allowed_domains = gcloudDomains; + }; +} diff --git a/ops/vault/cfg/config.nix b/ops/vault/cfg/config.nix index 769a1be9cb..dc494c39f7 100644 --- a/ops/vault/cfg/config.nix +++ b/ops/vault/cfg/config.nix @@ -12,6 +12,8 @@ ./ssh-ca-server.nix ./servers.nix + + ./acme-ca.nix ]; terraform = { diff --git a/ops/vault/cfg/module-acme-ca.nix b/ops/vault/cfg/module-acme-ca.nix new file mode 100644 index 0000000000..91b193d689 --- /dev/null +++ b/ops/vault/cfg/module-acme-ca.nix @@ -0,0 +1,89 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) mapAttrs' nameValuePair mkMerge mkOption mkIf any types; + + hackterpolate = s: let + parts = builtins.split "(\\\$\\{[^}]+})" s; + unescape = s: builtins.fromJSON ''"${s}"''; + strParts = lib.imap1 (i: v: if lib.mod i 2 == 0 then unescape (builtins.elemAt v 0) else v) parts; + in lib.concatStrings strParts; + + cfg = config.my.acme; + accountsEndpoints = mapAttrs' (name: value: nameValuePair "acme_account_${name}" { + depends_on = [ "vault_mount.acme" ]; + path = "acme/accounts/${name}"; + disable_read = true; + + data_json = hackterpolate (builtins.toJSON value); + }) cfg.accounts; + rolesEndpoints = mapAttrs' (name: value: nameValuePair "acme_role_${name}" { + depends_on = [ "vault_mount.acme" ]; + path = "acme/roles/${name}"; + disable_read = true; + + data_json = hackterpolate (builtins.toJSON value); + }) cfg.roles; + + mkMergeIf = things: mkIf (any (t: t != { }) things) (mkMerge things); +in { + options = { + my.acme.mountPoint = mkOption { + default = "acme"; + type = types.str; + }; + + my.acme.accounts = mkOption { + default = {}; + type = (pkgs.formats.json { }).type; + }; + + my.acme.roles = mkOption { + default = {}; + type = types.attrsOf (types.submodule ({ name, ... }: { + options = { + account = mkOption { + type = types.str; + default = name; + }; + + allow_bare_domains = mkOption { + type = types.bool; + default = true; + }; + + allow_subdomains = mkOption { + type = types.bool; + default = true; + }; + + allowed_domains = mkOption { + type = with types; listOf str; + }; + + cache_for_ratio = mkOption { + type = types.int; + default = 20; + }; + + disable_cache = mkOption { + type = types.bool; + default = false; + }; + }; + })); + }; + }; + + config = { + resource.vault_mount.acme = { + path = config.my.acme.mountPoint; + type = "acme"; + }; + + resource.vault_generic_endpoint = mkMergeIf [ + accountsEndpoints + rolesEndpoints + ]; + }; +}