Skip to content

Commit

Permalink
nixos/tests/letsencrypt: use Pebble instead of Boulder
Browse files Browse the repository at this point in the history
Let's encrypt bumped ACME to V2. We need to update our nixos test to
be compatible with this new protocol version.

We decided to drop the Boulder ACME server in favor of the more
integration test friendly Pebble.

- overriding cacert not necessary
- this avoids rebuilding lots of packages needlessly
- nixos/tests/acme: use pebble's ca for client tests
- pebble always generates its own ca which has to be fetched

(cherry picked from commit 0c0af28)
  • Loading branch information
picnoir committed Oct 24, 2019
1 parent 353333e commit f4b14ce
Show file tree
Hide file tree
Showing 7 changed files with 313 additions and 592 deletions.
5 changes: 5 additions & 0 deletions nixos/modules/security/acme.nix
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ in
description = "Renew ACME Certificate for ${cert}";
after = [ "network.target" "network-online.target" ];
wants = [ "network-online.target" ];
# simp_le uses requests, which uses certifi under the hood,
# which doesn't respect the system trust store.
# At least in the acme test, we provision a fake CA, impersonating the LE endpoint.
# REQUESTS_CA_BUNDLE is a way to teach python requests to use something else
environment.REQUESTS_CA_BUNDLE = "/etc/ssl/certs/ca-certificates.crt";
serviceConfig = {
Type = "oneshot";
SuccessExitStatus = [ "0" "1" ];
Expand Down
18 changes: 13 additions & 5 deletions nixos/tests/acme.nix
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ in import ./make-test.nix {
client = commonConfig;
};

testScript = {nodes, ...}:
testScript = {nodes, ...}:
let
newServerSystem = nodes.webserver2.config.system.build.toplevel;
switchToNewServer = "${newServerSystem}/bin/switch-to-configuration test";
Expand All @@ -91,25 +91,33 @@ in import ./make-test.nix {
# get pulled in by the oneshot units. The target units linger after activation, and hence we
# can use them to probe that a oneshot fired. It is a bit ugly, but it is the best we can do
''
$client->waitForUnit("default.target");
$client->start;
$letsencrypt->start;
$acmeStandalone->start;
$letsencrypt->waitForUnit("default.target");
$letsencrypt->waitForUnit("boulder.service");
$letsencrypt->waitForUnit("pebble.service");
subtest "can request certificate with HTTPS-01 challenge", sub {
$acmeStandalone->waitForUnit("default.target");
$acmeStandalone->succeed("systemctl start acme-standalone.com.service");
$acmeStandalone->waitForUnit("acme-finished-standalone.com.target");
};
$client->waitForUnit("default.target");
$client->succeed('curl https://acme-v02.api.letsencrypt.org:15000/roots/0 > /tmp/ca.crt');
$client->succeed('curl https://acme-v02.api.letsencrypt.org:15000/intermediate-keys/0 >> /tmp/ca.crt');
subtest "Can request certificate for nginx service", sub {
$webserver->waitForUnit("acme-finished-a.example.com.target");
$client->succeed('curl https://a.example.com/ | grep -qF "hello world"');
$client->succeed('curl --cacert /tmp/ca.crt https://a.example.com/ | grep -qF "hello world"');
};
subtest "Can add another certificate for nginx service", sub {
$webserver->succeed("/run/current-system/fine-tune/child-1/bin/switch-to-configuration test");
$webserver->waitForUnit("acme-finished-b.example.com.target");
$client->succeed('curl https://b.example.com/ | grep -qF "hello world"');
$client->succeed('curl --cacert /tmp/ca.crt https://b.example.com/ | grep -qF "hello world"');
};
'';
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
From c3b4004386074342d22cab5e129c1f7e623f4272 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix=20Baylac-Jacqu=C3=A9?= <[email protected]>
Date: Mon, 21 Oct 2019 10:56:13 +0200
Subject: [PATCH] Change ACME directory endpoint to /directory

---
wfe/wfe.go | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/wfe/wfe.go b/wfe/wfe.go
index e24797f..10d29fb 100644
--- a/wfe/wfe.go
+++ b/wfe/wfe.go
@@ -39,7 +39,7 @@ const (
// Note: We deliberately pick endpoint paths that differ from Boulder to
// exercise clients processing of the /directory response
// We export the DirectoryPath so that the pebble binary can reference it
- DirectoryPath = "/dir"
+ DirectoryPath = "/directory"
noncePath = "/nonce-plz"
newAccountPath = "/sign-me-up"
acctPath = "/my-account/"
--
2.23.0

26 changes: 4 additions & 22 deletions nixos/tests/common/letsencrypt/common.nix
Original file line number Diff line number Diff line change
@@ -1,27 +1,9 @@
{ lib, nodes, ... }: {
{ lib, nodes, pkgs, ... }: let
letsencrypt-ca = nodes.letsencrypt.config.test-support.letsencrypt.caCert;
in {
networking.nameservers = [
nodes.letsencrypt.config.networking.primaryIPAddress
];

nixpkgs.overlays = lib.singleton (self: super: {
cacert = super.cacert.overrideDerivation (drv: {
installPhase = (drv.installPhase or "") + ''
cat "${nodes.letsencrypt.config.test-support.letsencrypt.caCert}" \
>> "$out/etc/ssl/certs/ca-bundle.crt"
'';
});

# Override certifi so that it accepts fake certificate for Let's Encrypt
# Need to override the attribute used by simp_le, which is python3Packages
python3Packages = (super.python3.override {
packageOverrides = lib.const (pysuper: {
certifi = pysuper.certifi.overridePythonAttrs (attrs: {
postPatch = (attrs.postPatch or "") + ''
cat "${self.cacert}/etc/ssl/certs/ca-bundle.crt" \
> certifi/cacert.pem
'';
});
});
}).pkgs;
});
security.pki.certificateFiles = [ letsencrypt-ca ];
}
Loading

0 comments on commit f4b14ce

Please sign in to comment.