at master 4.0 kB view raw
1# The certificate for the ACME service is exported as: 2# 3# config.test-support.acme.caCert 4# 5# This value can be used inside the configuration of other test nodes to inject 6# the test certificate into security.pki.certificateFiles or into package 7# overlays. 8# 9# The hosts file of this node will be populated with a mapping of certificate 10# domains (including extraDomainNames) to their parent nodes in the test suite. 11# This negates the need for a DNS server for most testing. You can still specify 12# a custom nameserver/resolver if necessary for other reasons. 13{ 14 config, 15 pkgs, 16 lib, 17 nodes ? { }, 18 ... 19}: 20let 21 testCerts = import ./snakeoil-certs.nix; 22 domain = testCerts.domain; 23 24 pebbleConf.pebble = { 25 listenAddress = "0.0.0.0:443"; 26 managementListenAddress = "0.0.0.0:15000"; 27 # These certs and keys are used for the Web Front End (WFE) 28 certificate = testCerts.${domain}.cert; 29 privateKey = testCerts.${domain}.key; 30 httpPort = 80; 31 tlsPort = 443; 32 ocspResponderURL = "http://${domain}:4002"; 33 strict = true; 34 }; 35 36 pebbleConfFile = pkgs.writeText "pebble.conf" (builtins.toJSON pebbleConf); 37 38in 39{ 40 options.test-support.acme = { 41 caDomain = lib.mkOption { 42 type = lib.types.str; 43 readOnly = true; 44 default = domain; 45 description = '' 46 A domain name to use with the `nodes` attribute to 47 identify the CA server. 48 ''; 49 }; 50 caCert = lib.mkOption { 51 type = lib.types.path; 52 readOnly = true; 53 default = testCerts.ca.cert; 54 description = '' 55 A certificate file to use with the `nodes` attribute to 56 inject the test CA certificate used in the ACME server into 57 {option}`security.pki.certificateFiles`. 58 ''; 59 }; 60 }; 61 62 config = { 63 networking = { 64 firewall.allowedTCPPorts = [ 65 80 66 443 67 15000 68 4002 69 ]; 70 71 # Match the caDomain - nixos/lib/testing/network.nix will then add a record for us to 72 # all nodes in /etc/hosts 73 hostName = "acme"; 74 domain = "test"; 75 76 # Extend /etc/hosts to resolve all configured certificates to their hosts. 77 # This way, no DNS server will be needed to validate HTTP-01 certs. 78 hosts = lib.attrsets.concatMapAttrs ( 79 _: node: 80 let 81 inherit (node.networking) primaryIPAddress primaryIPv6Address; 82 ips = builtins.filter (ip: ip != "") [ 83 primaryIPAddress 84 primaryIPv6Address 85 ]; 86 names = lib.lists.unique ( 87 lib.lists.flatten ( 88 lib.lists.concatMap 89 ( 90 cfg: 91 lib.attrsets.mapAttrsToList ( 92 domain: cfg: 93 builtins.map (builtins.replaceStrings [ "*." ] [ "" ]) ([ domain ] ++ cfg.extraDomainNames) 94 ) cfg.configuration.security.acme.certs 95 ) 96 # A specialisation's config is nested under its configuration attribute. 97 # For ease of use, nest the root node's configuration similarly. 98 ([ { configuration = node; } ] ++ (builtins.attrValues node.specialisation)) 99 ) 100 ); 101 in 102 builtins.listToAttrs (builtins.map (ip: lib.attrsets.nameValuePair ip names) ips) 103 ) nodes; 104 }; 105 106 systemd.services = { 107 pebble = { 108 enable = true; 109 description = "Pebble ACME server"; 110 wantedBy = [ "network.target" ]; 111 environment = { 112 # We're not testing lego, we're just testing our configuration. 113 # No need to sleep or randomly fail nonces. 114 PEBBLE_VA_NOSLEEP = "1"; 115 PEBBLE_WFE_NONCEREJECT = "0"; 116 }; 117 118 serviceConfig = { 119 RuntimeDirectory = "pebble"; 120 WorkingDirectory = "/run/pebble"; 121 122 # Required to bind on privileged ports. 123 AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; 124 125 ExecStart = "${pkgs.pebble}/bin/pebble -config ${pebbleConfFile}"; 126 }; 127 }; 128 }; 129 }; 130}