diff options
Diffstat (limited to 'nixos/tests/common/acme/server/default.nix')
-rw-r--r-- | nixos/tests/common/acme/server/default.nix | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/nixos/tests/common/acme/server/default.nix b/nixos/tests/common/acme/server/default.nix new file mode 100644 index 00000000000..450d49e6039 --- /dev/null +++ b/nixos/tests/common/acme/server/default.nix @@ -0,0 +1,141 @@ +# The certificate for the ACME service is exported as: +# +# config.test-support.acme.caCert +# +# This value can be used inside the configuration of other test nodes to inject +# the test certificate into security.pki.certificateFiles or into package +# overlays. +# +# Another value that's needed if you don't use a custom resolver (see below for +# notes on that) is to add the acme node as a nameserver to every node +# that needs to acquire certificates using ACME, because otherwise the API host +# for acme.test can't be resolved. +# +# A configuration example of a full node setup using this would be this: +# +# { +# acme = import ./common/acme/server; +# +# example = { nodes, ... }: { +# networking.nameservers = [ +# nodes.acme.config.networking.primaryIPAddress +# ]; +# security.pki.certificateFiles = [ +# nodes.acme.config.test-support.acme.caCert +# ]; +# }; +# } +# +# By default, this module runs a local resolver, generated using resolver.nix +# from the parent directory to automatically discover all zones in the network. +# +# If you do not want this and want to use your own resolver, you can just +# override networking.nameservers like this: +# +# { +# acme = { nodes, lib, ... }: { +# imports = [ ./common/acme/server ]; +# networking.nameservers = lib.mkForce [ +# nodes.myresolver.config.networking.primaryIPAddress +# ]; +# }; +# +# myresolver = ...; +# } +# +# Keep in mind, that currently only _one_ resolver is supported, if you have +# more than one resolver in networking.nameservers only the first one will be +# used. +# +# Also make sure that whenever you use a resolver from a different test node +# that it has to be started _before_ the ACME service. +{ config, pkgs, lib, ... }: +let + testCerts = import ./snakeoil-certs.nix; + domain = testCerts.domain; + + resolver = let + message = "You need to define a resolver for the acme test module."; + firstNS = lib.head config.networking.nameservers; + in if config.networking.nameservers == [] then throw message else firstNS; + + pebbleConf.pebble = { + listenAddress = "0.0.0.0:443"; + managementListenAddress = "0.0.0.0:15000"; + # These certs and keys are used for the Web Front End (WFE) + certificate = testCerts.${domain}.cert; + privateKey = testCerts.${domain}.key; + httpPort = 80; + tlsPort = 443; + ocspResponderURL = "http://${domain}:4002"; + strict = true; + }; + + pebbleConfFile = pkgs.writeText "pebble.conf" (builtins.toJSON pebbleConf); + +in { + imports = [ ../../resolver.nix ]; + + options.test-support.acme = with lib; { + caDomain = mkOption { + type = types.str; + readOnly = true; + default = domain; + description = '' + A domain name to use with the <literal>nodes</literal> attribute to + identify the CA server. + ''; + }; + caCert = mkOption { + type = types.path; + readOnly = true; + default = testCerts.ca.cert; + description = '' + A certificate file to use with the <literal>nodes</literal> attribute to + inject the test CA certificate used in the ACME server into + <option>security.pki.certificateFiles</option>. + ''; + }; + }; + + config = { + test-support = { + resolver.enable = let + isLocalResolver = config.networking.nameservers == [ "127.0.0.1" ]; + in lib.mkOverride 900 isLocalResolver; + }; + + # This has priority 140, because modules/testing/test-instrumentation.nix + # already overrides this with priority 150. + networking.nameservers = lib.mkOverride 140 [ "127.0.0.1" ]; + networking.firewall.allowedTCPPorts = [ 80 443 15000 4002 ]; + + networking.extraHosts = '' + 127.0.0.1 ${domain} + ${config.networking.primaryIPAddress} ${domain} + ''; + + systemd.services = { + pebble = { + enable = true; + description = "Pebble ACME server"; + wantedBy = [ "network.target" ]; + environment = { + # We're not testing lego, we're just testing our configuration. + # No need to sleep. + PEBBLE_VA_NOSLEEP = "1"; + }; + + serviceConfig = { + RuntimeDirectory = "pebble"; + WorkingDirectory = "/run/pebble"; + + # Required to bind on privileged ports. + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; + + ExecStart = "${pkgs.pebble}/bin/pebble -config ${pebbleConfFile}"; + }; + }; + }; + }; +} |