From df5fba19f839c770bf2fb962be0a435b1df5e3d9 Mon Sep 17 00:00:00 2001 From: Noah Masur <7386960+nmasur@users.noreply.github.com> Date: Wed, 31 May 2023 21:03:08 -0400 Subject: [PATCH] cloudflare caddy module for dns validation --- modules/nixos/services/caddy.nix | 6 +++ modules/nixos/services/cloudflare.nix | 61 ++++++++++++++++++++++++++- private/cloudflare-api.age | 13 ++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 private/cloudflare-api.age diff --git a/modules/nixos/services/caddy.nix b/modules/nixos/services/caddy.nix index ab24506..702e20b 100644 --- a/modules/nixos/services/caddy.nix +++ b/modules/nixos/services/caddy.nix @@ -2,6 +2,11 @@ options = { caddy.enable = lib.mkEnableOption "Caddy reverse proxy."; + caddy.tlsPolicies = lib.mkOption { + type = lib.types.listOf lib.types.attrs; + description = "Caddy JSON TLS policies"; + default = [ ]; + }; caddy.routes = lib.mkOption { type = lib.types.listOf lib.types.attrs; description = "Caddy JSON routes for http servers"; @@ -26,6 +31,7 @@ errors.routes = config.caddy.blocks; # logs = { }; # Uncomment to collect access logs }; + apps.tls.automation.policies = config.caddy.tlsPolicies; logging.logs.main = { encoder = { format = "console"; }; writer = { diff --git a/modules/nixos/services/cloudflare.nix b/modules/nixos/services/cloudflare.nix index aac2582..3d7c8ab 100644 --- a/modules/nixos/services/cloudflare.nix +++ b/modules/nixos/services/cloudflare.nix @@ -1,6 +1,6 @@ # This module is necessary for hosts that are serving through Cloudflare. -{ config, lib, ... }: +{ config, pkgs, lib, ... }: let @@ -34,6 +34,41 @@ let ]; + # Build with Cloudflare plugin for DNS validation + # Otherwise, requires HTTPS to be disabled for issuance + caddy = pkgs.stdenv.mkDerivation rec { + pname = "caddy"; + version = "latest"; + dontUnpack = true; + + nativeBuildInputs = with pkgs; [ git go xcaddy ]; + + plugins = [ + "github.com/caddy-dns/cloudflare@a9d3ae2690a1d232bc9f8fc8b15bd4e0a6960eec" + ]; + + configurePhase = '' + export GOCACHE=$TMPDIR/go-cache + export GOPATH="$TMPDIR/go" + ''; + + buildPhase = let + pluginArgs = + lib.concatMapStringsSep " " (plugin: "--with ${plugin}") plugins; + in '' + runHook preBuild + ${pkgs.xcaddy}/bin/xcaddy build "v${version}" ${pluginArgs} + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out/bin + mv caddy $out/bin + runHook postInstall + ''; + }; + in { options.cloudflare.enable = lib.mkEnableOption "Use Cloudflare."; @@ -49,6 +84,30 @@ in { }]; }]; + # Tell Caddy to use Cloudflare DNS for ACME challenge validation + services.caddy.package = caddy; + caddy.tlsPolicies = [{ + issuers = [{ + module = "acme"; + challenges = { + dns.provider = { + name = "cloudflare"; + api_token = "{env.CF_API_TOKEN}"; + }; + }; + }]; + }]; + systemd.services.caddy.serviceConfig.EnvironmentFile = + config.secrets.cloudflareApi.dest; + + # API key must have access to modify Cloudflare DNS records + secrets.cloudflareApi = { + source = ../../../private/cloudflare-api.age; + dest = "${config.secretsDirectory}/cloudflare-api"; + owner = "caddy"; + group = "caddy"; + }; + # Allows Nextcloud to trust Cloudflare IPs services.nextcloud.config.trustedProxies = cloudflareIpRanges; diff --git a/private/cloudflare-api.age b/private/cloudflare-api.age new file mode 100644 index 0000000..51f3080 --- /dev/null +++ b/private/cloudflare-api.age @@ -0,0 +1,13 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IE1nSGFPdyByWGJS +SmJlSVhZcUx5Y3JhVXYxUVhUbmp2QjNXeUxYL1EwNThJelRoTVNvCjFsU0gyaWNJ +SEJpNVpYWm1TL24yeHNLaWNIdU9FdWw2d3p6UVVMSEYwT28KLT4gc3NoLWVkMjU1 +MTkgWXlTVU1RIEV4NU1sOENFK1NvUWlZL1NmUCtUM2RRQmd1c2pnb3p6V3Bsc3pC +UVdYV3cKYmFkR0EwNVpRbzJBb2Z4RmpXSGVyK3BkLzd6TTMvQWRRK3BtRXZDUjVZ +UQotPiBzc2gtZWQyNTUxOSBuanZYNUEgMG9rU0lzTU1iV1grOTNzZS85cldQZGE5 +Ym9nVkRvNC9OMUFBbStNT1BBOApucnl1Z0w1Y1RRU3grS0Z0TjNNRXcwVnVqeDFF +VGc3Mm93UFc0YXoweVBBCi0tLSBvTnpCc3hBVU81dkpBRzV2L3NWTlZaV2QxUVNZ +KzJwcUI2QUl2NEY0R1p3CmDvQwsKrtmTJliCxHv+LSoIV8jYpQJ7I2LJSH9uP89N ++7wbAwGjv/Uxk7gnMn5EqQuFKZeOl8LLhKEprmVqVZqlkgbpaaaWud/4xNKu9v5h +lWuY1sYd +-----END AGE ENCRYPTED FILE-----