summary refs log tree commit diff
path: root/nixos/tests/common/acme/server/default.nix
diff options
context:
space:
mode:
authorLucas Savva <lucas@m1cr0man.com>2020-06-19 20:27:46 +0100
committerLucas Savva <lucas@m1cr0man.com>2020-09-02 19:22:43 +0100
commit982c5a1f0e7f282f856391304aa4da7bb36c45b8 (patch)
tree4cf0e93b6cd4e1ae2371c0d9184fca87ae8e43ca /nixos/tests/common/acme/server/default.nix
parent6ab387699a9f23201cf76091d0f7d4ff09fa510e (diff)
downloadnixpkgs-982c5a1f0e7f282f856391304aa4da7bb36c45b8.tar
nixpkgs-982c5a1f0e7f282f856391304aa4da7bb36c45b8.tar.gz
nixpkgs-982c5a1f0e7f282f856391304aa4da7bb36c45b8.tar.bz2
nixpkgs-982c5a1f0e7f282f856391304aa4da7bb36c45b8.tar.lz
nixpkgs-982c5a1f0e7f282f856391304aa4da7bb36c45b8.tar.xz
nixpkgs-982c5a1f0e7f282f856391304aa4da7bb36c45b8.tar.zst
nixpkgs-982c5a1f0e7f282f856391304aa4da7bb36c45b8.zip
nixos/acme: Restructure module
- Use an acme user and group, allow group override only
- Use hashes to determine when certs actually need to regenerate
- Avoid running lego more than necessary
- Harden permissions
- Support "systemctl clean" for cert regeneration
- Support reuse of keys between some configuration changes
- Permissions fix services solves for previously root owned certs
- Add a note about multiple account creation and emails
- Migrate extraDomains to a list
- Deprecate user option
- Use minica for self-signed certs
- Rewrite all tests

I thought of a few more cases where things may go wrong,
and added tests to cover them. In particular, the web server
reload services were depending on the target - which stays alive,
meaning that the renewal timer wouldn't be triggering a reload
and old certs would stay on the web servers.

I encountered some problems ensuring that the reload took place
without accidently triggering it as part of the test. The sync
commands I added ended up being essential and I'm not sure why,
it seems like either node.succeed ends too early or there's an
oddity of the vm's filesystem I'm not aware of.

- Fix duplicate systemd rules on reload services

Since useACMEHost is not unique to every vhost, if one cert
was reused many times it would create duplicate entries in
${server}-config-reload.service for wants, before and
ConditionPathExists
Diffstat (limited to 'nixos/tests/common/acme/server/default.nix')
-rw-r--r--nixos/tests/common/acme/server/default.nix72
1 files changed, 38 insertions, 34 deletions
diff --git a/nixos/tests/common/acme/server/default.nix b/nixos/tests/common/acme/server/default.nix
index 1a0ee882572..4d8e664c4e1 100644
--- a/nixos/tests/common/acme/server/default.nix
+++ b/nixos/tests/common/acme/server/default.nix
@@ -3,7 +3,7 @@
 #   config.test-support.acme.caCert
 #
 # This value can be used inside the configuration of other test nodes to inject
-# the snakeoil certificate into security.pki.certificateFiles or into package
+# 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
@@ -50,19 +50,13 @@
 # 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
-  snakeOilCerts = import ./snakeoil-certs.nix;
-
-  wfeDomain = "acme.test";
-  wfeCertFile = snakeOilCerts.${wfeDomain}.cert;
-  wfeKeyFile = snakeOilCerts.${wfeDomain}.key;
+  testCerts = import ./snakeoil-certs.nix {
+    minica = pkgs.minica;
+    mkDerivation = pkgs.stdenv.mkDerivation;
+  };
+  domain = testCerts.domain;
 
-  siteDomain = "acme.test";
-  siteCertFile = snakeOilCerts.${siteDomain}.cert;
-  siteKeyFile = snakeOilCerts.${siteDomain}.key;
-  pebble = pkgs.pebble;
   resolver = let
     message = "You need to define a resolver for the acme test module.";
     firstNS = lib.head config.networking.nameservers;
@@ -71,8 +65,9 @@ let
   pebbleConf.pebble = {
     listenAddress = "0.0.0.0:443";
     managementListenAddress = "0.0.0.0:15000";
-    certificate = snakeOilCerts.${wfeDomain}.cert;
-    privateKey = snakeOilCerts.${wfeDomain}.key;
+    # 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://0.0.0.0:4002";
@@ -80,18 +75,30 @@ let
   };
 
   pebbleConfFile = pkgs.writeText "pebble.conf" (builtins.toJSON pebbleConf);
-  pebbleDataDir = "/root/pebble";
 
 in {
   imports = [ ../../resolver.nix ];
 
-  options.test-support.acme.caCert = lib.mkOption {
-    type = lib.types.path;
-    description = ''
-      A certificate file to use with the <literal>nodes</literal> attribute to
-      inject the snakeoil CA certificate used in the ACME server into
-      <option>security.pki.certificateFiles</option>.
-    '';
+  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 = {
@@ -99,35 +106,32 @@ in {
       resolver.enable = let
         isLocalResolver = config.networking.nameservers == [ "127.0.0.1" ];
       in lib.mkOverride 900 isLocalResolver;
-      acme.caCert = snakeOilCerts.ca.cert;
     };
 
     # 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.enable = false;
+    networking.firewall.allowedTCPPorts = [ 80 443 15000 4002 ];
 
     networking.extraHosts = ''
-      127.0.0.1 ${wfeDomain}
-      ${config.networking.primaryIPAddress} ${wfeDomain} ${siteDomain}
+      127.0.0.1 ${domain}
+      ${config.networking.primaryIPAddress} ${domain}
     '';
 
     systemd.services = {
       pebble = {
         enable = true;
         description = "Pebble ACME server";
-        requires = [ ];
         wantedBy = [ "network.target" ];
-        preStart = ''
-          mkdir ${pebbleDataDir}
-        '';
-        script = ''
-          cd ${pebbleDataDir}
-          ${pebble}/bin/pebble -config ${pebbleConfFile}
-        '';
+
         serviceConfig = {
+          RuntimeDirectory = "pebble";
+          WorkingDirectory = "/run/pebble";
+
           # Required to bind on privileged ports.
           AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
+
+          ExecStart = "${pkgs.pebble}/bin/pebble -config ${pebbleConfFile}";
         };
       };
     };