Skip to content

Commit 1d6cda1

Browse files
committed
TEST/MEDIUM: acme: add test infrastructure and HTTP-01 testing
1 parent a27e514 commit 1d6cda1

File tree

14 files changed

+431
-7
lines changed

14 files changed

+431
-7
lines changed

e2e/fixtures/pebble/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# certs/
2+
3+
This directory contains a CA certificate (`pebble.minica.pem`) and a private key
4+
(`pebble.minica.key.pem`) that are used to issue a end-entity certificate (See
5+
`certs/localhost`) for the Pebble HTTPS server.
6+
7+
To get your **testing code** to use Pebble without HTTPS errors you should
8+
configure your ACME client to trust the `pebble.minica.pem` CA certificate. Your
9+
ACME client should offer a runtime option to specify a list of root CAs that you
10+
can configure to include the `pebble.minica.pem` file.
11+
12+
**Do not** add this CA certificate to the system trust store or in production
13+
code!!! The CA's private key is **public** and anyone can use it to issue
14+
certificates that will be trusted by a system with the Pebble CA in the trust
15+
store.
16+
17+
To re-create all of the Pebble certificates run:
18+
19+
minica -ca-cert pebble.minica.pem \
20+
-ca-key pebble.minica.key.pem \
21+
-domains localhost,pebble \
22+
-ip-addresses 127.0.0.1
23+
24+
From the `test/certs/` directory after [installing
25+
MiniCA](https://github.com/jsha/minica#installation)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# certs/localhost
2+
3+
This directory contains an end-entity (leaf) certificate (`cert.pem`) and
4+
a private key (`key.pem`) for the Pebble HTTPS server. It includes `127.0.0.1`
5+
as an IP address SAN, and `[localhost, pebble]` as DNS SANs.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDGzCCAgOgAwIBAgIIbEfayDFsBtwwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
3+
AxMVbWluaWNhIHJvb3QgY2EgMjRlMmRiMCAXDTE3MTIwNjE5NDIxMFoYDzIxMDcx
4+
MjA2MTk0MjEwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB
5+
AQUAA4IBDwAwggEKAoIBAQCbFMW3DXXdErvQf2lCZ0qz0DGEWadDoF0O2neM5mVa
6+
VQ7QGW0xc5Qwvn3Tl62C0JtwLpF0pG2BICIN+DHdVaIUwkf77iBS2doH1I3waE1I
7+
8GkV9JrYmFY+j0dA1SwBmqUZNXhLNwZGq1a91nFSI59DZNy/JciqxoPX2K++ojU2
8+
FPpuXe2t51NmXMsszpa+TDqF/IeskA9A/ws6UIh4Mzhghx7oay2/qqj2IIPjAmJj
9+
i73kdUvtEry3wmlkBvtVH50+FscS9WmPC5h3lDTk5nbzSAXKuFusotuqy3XTgY5B
10+
PiRAwkZbEY43JNfqenQPHo7mNTt29i+NVVrBsnAa5ovrAgMBAAGjYzBhMA4GA1Ud
11+
DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T
12+
AQH/BAIwADAiBgNVHREEGzAZgglsb2NhbGhvc3SCBnBlYmJsZYcEfwAAATANBgkq
13+
hkiG9w0BAQsFAAOCAQEAYIkXff8H28KS0KyLHtbbSOGU4sujHHVwiVXSATACsNAE
14+
D0Qa8hdtTQ6AUqA6/n8/u1tk0O4rPE/cTpsM3IJFX9S3rZMRsguBP7BSr1Lq/XAB
15+
7JP/CNHt+Z9aKCKcg11wIX9/B9F7pyKM3TdKgOpqXGV6TMuLjg5PlYWI/07lVGFW
16+
/mSJDRs8bSCFmbRtEqc4lpwlrpz+kTTnX6G7JDLfLWYw/xXVqwFfdengcDTHCc8K
17+
wtgGq/Gu6vcoBxIO3jaca+OIkMfxxXmGrcNdseuUCa3RMZ8Qy03DqGu6Y6XQyK4B
18+
W8zIG6H9SVKkAznM2yfYhW8v2ktcaZ95/OBHY97ZIw==
19+
-----END CERTIFICATE-----
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEowIBAAKCAQEAmxTFtw113RK70H9pQmdKs9AxhFmnQ6BdDtp3jOZlWlUO0Blt
3+
MXOUML5905etgtCbcC6RdKRtgSAiDfgx3VWiFMJH++4gUtnaB9SN8GhNSPBpFfSa
4+
2JhWPo9HQNUsAZqlGTV4SzcGRqtWvdZxUiOfQ2TcvyXIqsaD19ivvqI1NhT6bl3t
5+
redTZlzLLM6Wvkw6hfyHrJAPQP8LOlCIeDM4YIce6Gstv6qo9iCD4wJiY4u95HVL
6+
7RK8t8JpZAb7VR+dPhbHEvVpjwuYd5Q05OZ280gFyrhbrKLbqst104GOQT4kQMJG
7+
WxGONyTX6np0Dx6O5jU7dvYvjVVawbJwGuaL6wIDAQABAoIBAGW9W/S6lO+DIcoo
8+
PHL+9sg+tq2gb5ZzN3nOI45BfI6lrMEjXTqLG9ZasovFP2TJ3J/dPTnrwZdr8Et/
9+
357YViwORVFnKLeSCnMGpFPq6YEHj7mCrq+YSURjlRhYgbVPsi52oMOfhrOIJrEG
10+
ZXPAwPRi0Ftqu1omQEqz8qA7JHOkjB2p0i2Xc/uOSJccCmUDMlksRYz8zFe8wHuD
11+
XvUL2k23n2pBZ6wiez6Xjr0wUQ4ESI02x7PmYgA3aqF2Q6ECDwHhjVeQmAuypMF6
12+
IaTjIJkWdZCW96pPaK1t+5nTNZ+Mg7tpJ/PRE4BkJvqcfHEOOl6wAE8gSk5uVApY
13+
ZRKGmGkCgYEAzF9iRXYo7A/UphL11bR0gqxB6qnQl54iLhqS/E6CVNcmwJ2d9pF8
14+
5HTfSo1/lOXT3hGV8gizN2S5RmWBrc9HBZ+dNrVo7FYeeBiHu+opbX1X/C1HC0m1
15+
wJNsyoXeqD1OFc1WbDpHz5iv4IOXzYdOdKiYEcTv5JkqE7jomqBLQk8CgYEAwkG/
16+
rnwr4ThUo/DG5oH+l0LVnHkrJY+BUSI33g3eQ3eM0MSbfJXGT7snh5puJW0oXP7Z
17+
Gw88nK3Vnz2nTPesiwtO2OkUVgrIgWryIvKHaqrYnapZHuM+io30jbZOVaVTMR9c
18+
X/7/d5/evwXuP7p2DIdZKQKKFgROm1XnhNqVgaUCgYBD/ogHbCR5RVsOVciMbRlG
19+
UGEt3YmUp/vfMuAsKUKbT2mJM+dWHVlb+LZBa4pC06QFgfxNJi/aAhzSGvtmBEww
20+
xsXbaceauZwxgJfIIUPfNZCMSdQVIVTi2Smcx6UofBz6i/Jw14MEwlvhamaa7qVf
21+
kqflYYwelga1wRNCPopLaQKBgQCWsZqZKQqBNMm0Q9yIhN+TR+2d7QFjqeePoRPl
22+
1qxNejhq25ojE607vNv1ff9kWUGuoqSZMUC76r6FQba/JoNbefI4otd7x/GzM9uS
23+
8MHMJazU4okwROkHYwgLxxkNp6rZuJJYheB4VDTfyyH/ng5lubmY7rdgTQcNyZ5I
24+
majRYQKBgAMKJ3RlII0qvAfNFZr4Y2bNIq+60Z+Qu2W5xokIHCFNly3W1XDDKGFe
25+
CCPHSvQljinke3P9gPt2HVdXxcnku9VkTti+JygxuLkVg7E0/SWwrWfGsaMJs+84
26+
fK+mTZay2d3v24r9WKEKwLykngYPyZw5+BdWU0E+xx5lGUd3U4gG
27+
-----END RSA PRIVATE KEY-----
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"pebble": {
3+
"listenAddress": "0.0.0.0:14000",
4+
"managementListenAddress": "0.0.0.0:15000",
5+
"certificate": "/mnt/localhost/cert.pem",
6+
"privateKey": "/mnt/localhost/key.pem",
7+
"httpPort": 1080,
8+
"tlsPort": 1443,
9+
"ocspResponderURL": "",
10+
"externalAccountBindingRequired": false,
11+
"retryAfter": {
12+
"authz": 1,
13+
"order": 1
14+
},
15+
"profiles": {
16+
"default": {
17+
"description": "The profile you know and love",
18+
"validityPeriod": 7776000
19+
},
20+
"shortlived": {
21+
"description": "A short-lived cert profile, without actual enforcement",
22+
"validityPeriod": 518400
23+
}
24+
}
25+
}
26+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEpAIBAAKCAQEAuVoGTaFSWp3Y+N5JC8lOdL8wmWpaM73UaNzhYiqA7ZqijzVk
3+
TTtoQvQFDcUwyXKOdWHONrv1ld3z224Us504jjlbZwI5uoquCOZ2WJbRhmXrRgzk
4+
Fq+/MtoFmPkhtO/DLjjtocgyIirVXN8Yl2APvB5brvRfCm6kktYeecsWfW/O3ikf
5+
gdM7tmocwQiBypiloHOjdd5e2g8cWNw+rqvILSUVNLaLpsi23cxnLqVb424wz9dZ
6+
5dO0REg1gSxtf4N5LSb6iGuAVoFNhzIeKzQ+svDg9x8tx/DGOghJS/jDgmxSY1qo
7+
bTsXhcmWVfat5GJ5PQgLkCSjBBrjeBlOrc4VtQIDAQABAoIBAQCAoRoou6C0ZEDU
8+
DScyN8TrvlcS0LzClaWYFFmRT5/jxOG1cr8l3elwNXpgYQ2Hb6mvim2ajHxVQg/e
9+
oxlYwO4jvWhSJzg63c0DPjS5LAlCNO6+0Wlk2RheSPGDhLlAoPeZ10YKdS1dis5B
10+
Qk4Fl1O0IHlOBCcEzV4GzPOfYDI+X6/f4xY7qz1s+CgoIxjIeiG+1/WpZQpYhobY
11+
7CfSDdYDKtksXi7iQkc5earUAHBqZ1gQTq6e5LVm9AjRzENhMctFgcPs5zOjp2ak
12+
PluixrA8LTAfu9wQzvxDkPl0UarZVxCerw6nlAziILpQ+U6PtoPZj49VpntTc+cq
13+
1qjzkbhBAoGBANElJmFWY2X6LgBpszeqt0ZOSbkFg2bC0wHCJrMlRzUMEn83w9e8
14+
Z2Fqml9eCC5qxJcyxWDVQeoAX6090m0qgP8xNmGdafcVic2cUlrqtkqhhst2OHCO
15+
MCQEB7cdsjiidNNrOgLbQ3i1bYID8BVLf/TDhEbRgvTewDaz6XPdoSIRAoGBAOLg
16+
RuOec5gn50SrVycx8BLFO8AXjXojpZb1Xg26V5miz1IavSfDcgae/699ppSz+UWi
17+
jGMFr/PokY2JxDVs3PyQLu7ahMzyFHr16Agvp5g5kq056XV+uI/HhqLHOWSQ09DS
18+
1Vrj7FOYpKRzge3/AC7ty9Vr35uMiebpm4/CLFVlAoGALnsIJZfSbWaFdLgJCXUa
19+
WDir77/G7T6dMIXanfPJ+IMfVUCqeLa5bxAHEOzP+qjl2giBjzy18nB00warTnGk
20+
y5I/WMBoPW5++sAkGWqSatGtKGi0sGcZUdfHcy3ZXvbT6eyprtrWCuyfUsbXQ5RM
21+
8rPFIQwNA6jBpSak2ohF+FECgYEAn+6IKncNd6pRfnfmdSvf1+uPxkcUJZCxb2xC
22+
xByjGhvKWE+fHkPJwt8c0SIbZuJEC5Gds0RUF/XPfV4roZm/Yo9ldl02lp7kTxXA
23+
XtzxIP8c5d5YM8qD4l8+Csu0Kq9pkeC+JFddxkRpc8A1TIehInPhZ+6mb6mvoMb3
24+
MW0pAX0CgYATT74RYuIYWZvx0TK4ZXIKTw2i6HObLF63Y6UwyPXXdEVie/ToYRNH
25+
JIxE1weVpHvnHZvVD6D3yGk39ZsCIt31VvKpatWXlWBm875MbBc6kuIGsYT+mSSj
26+
y9TXaE89E5zfL27nZe15QLJ+Xw8Io6PMLZ/jtC5TYoEixSZ9J8v6HA==
27+
-----END RSA PRIVATE KEY-----
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDCTCCAfGgAwIBAgIIJOLbes8sTr4wDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
3+
AxMVbWluaWNhIHJvb3QgY2EgMjRlMmRiMCAXDTE3MTIwNjE5NDIxMFoYDzIxMTcx
4+
MjA2MTk0MjEwWjAgMR4wHAYDVQQDExVtaW5pY2Egcm9vdCBjYSAyNGUyZGIwggEi
5+
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5WgZNoVJandj43kkLyU50vzCZ
6+
alozvdRo3OFiKoDtmqKPNWRNO2hC9AUNxTDJco51Yc42u/WV3fPbbhSznTiOOVtn
7+
Ajm6iq4I5nZYltGGZetGDOQWr78y2gWY+SG078MuOO2hyDIiKtVc3xiXYA+8Hluu
8+
9F8KbqSS1h55yxZ9b87eKR+B0zu2ahzBCIHKmKWgc6N13l7aDxxY3D6uq8gtJRU0
9+
toumyLbdzGcupVvjbjDP11nl07RESDWBLG1/g3ktJvqIa4BWgU2HMh4rND6y8OD3
10+
Hy3H8MY6CElL+MOCbFJjWqhtOxeFyZZV9q3kYnk9CAuQJKMEGuN4GU6tzhW1AgMB
11+
AAGjRTBDMA4GA1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
12+
BQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEAF85v
13+
d40HK1ouDAtWeO1PbnWfGEmC5Xa478s9ddOd9Clvp2McYzNlAFfM7kdcj6xeiNhF
14+
WPIfaGAi/QdURSL/6C1KsVDqlFBlTs9zYfh2g0UXGvJtj1maeih7zxFLvet+fqll
15+
xseM4P9EVJaQxwuK/F78YBt0tCNfivC6JNZMgxKF59h0FBpH70ytUSHXdz7FKwix
16+
Mfn3qEb9BXSk0Q3prNV5sOV3vgjEtB4THfDxSz9z3+DepVnW3vbbqwEbkXdk3j82
17+
2muVldgOUgTwK8eT+XdofVdntzU/kzygSAtAQwLJfn51fS1GvEcYGBc1bDryIqmF
18+
p9BI7gVKtWSZYegicA==
19+
-----END CERTIFICATE-----

e2e/libs/acme.bash

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Copyright 2025 HAProxy Technologies
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http:#www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
18+
# This module will launch 2 extra containers needed for ACME tests:
19+
# - pebble - the "official" ACME test server from LetsEncrypt
20+
# - challserv - pebble's companion used to fake DNS challenges
21+
#
22+
# Those containers can be accessed via their respective variables:
23+
# - ACME_DIR_CONTAINER_NAME=pebble
24+
# - ACME_DNS_CONTAINER_NAME=challtestsrv
25+
26+
load '../../libs/haproxy_version'
27+
28+
# ACME is available starting with HAProxy 3.2,
29+
# but became compatible with pebble in version 3.3.
30+
ACME=false
31+
if haproxy_version_ge 3.3; then
32+
ACME=true
33+
ACME_DIR_CONTAINER_NAME=pebble
34+
ACME_DNS_CONTAINER_NAME=challtestsrv
35+
PEBBLE_IMAGE="ghcr.io/letsencrypt/pebble:latest"
36+
CHALLTESTSRV_IMAGE="ghcr.io/letsencrypt/pebble-challtestsrv:latest"
37+
fi
38+
39+
setup_file() {
40+
$ACME || return 0
41+
42+
echo '>>> Setting up ACME challtestsrv' >&3
43+
# Start challtestsrv -- https://github.com/letsencrypt/pebble/blob/main/cmd/pebble-challtestsrv/README.md
44+
docker pull "$CHALLTESTSRV_IMAGE" >/dev/null
45+
docker run -d --name "$ACME_DNS_CONTAINER_NAME" --net "$DOCKER_NETWORK" \
46+
-p 5001:5001 -p 5002:5002 -p 5003:5003 -p 8053:8053 -p 8055:8055 \
47+
"$CHALLTESTSRV_IMAGE"
48+
49+
echo '>>> Setting up ACME directory: pebble' >&3
50+
docker pull "$PEBBLE_IMAGE" >/dev/null
51+
docker run -d --name "$ACME_DIR_CONTAINER_NAME" --net "$DOCKER_NETWORK" \
52+
-p 14000:14000 -p 15000:15000 -v "${E2E_DIR}/fixtures/pebble:/mnt:ro" \
53+
-e PEBBLE_VA_NOSLEEP=1 -e PEBBLE_VA_ALWAYS_VALID=1 -e PEBBLE_WFE_NONCEREJECT=0 \
54+
"$PEBBLE_IMAGE" -config /mnt/pebble-config.json -strict -dnsserver $ACME_DNS_CONTAINER_NAME:8053
55+
sleep 1
56+
57+
# Allow HAProxy's HTTPS client to connect to Pebble (the fake ACME server)
58+
docker cp "${E2E_DIR}/fixtures/pebble/pebble.minica.pem" ${DOCKER_CONTAINER_NAME}:/var/lib/haproxy/pebble.minica.pem
59+
}
60+
61+
teardown_file() {
62+
$ACME || return 0
63+
64+
for c in "$ACME_DIR_CONTAINER_NAME" "$ACME_DNS_CONTAINER_NAME"; do
65+
echo ">>> Shutting down ACME container $c" >&3
66+
mkdir -p "$E2E_DIR/logs"
67+
docker logs "$c" &> "$E2E_DIR/logs/$c.log"
68+
docker stop "$c"
69+
docker rm -f "$c"
70+
done
71+
}

e2e/libs/cleanup.bash

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ function cleanup() {
1919
echo ">>> Stopping ${1} docker container"
2020
docker stop "$1" > /dev/null
2121
docker rm "$1" > /dev/null
22+
23+
echo ">>> Removing docker network $DOCKER_NETWORK"
24+
docker network rm "$DOCKER_NETWORK" >/dev/null
2225
}

e2e/libs/haproxy_config_setup.bash

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ setup() {
6363
if [ -f "${BATS_TEST_DIRNAME}/dataplaneapi.yaml" ]; then
6464
run docker cp "${BATS_TEST_DIRNAME}/dataplaneapi.yaml" "${DOCKER_CONTAINER_NAME}:/etc/haproxy/dataplaneapi.yaml"
6565
else
66+
# TODO: we should respect $VARIANT here
6667
run docker cp "${E2E_DIR}/fixtures/dataplaneapi.yaml" "${DOCKER_CONTAINER_NAME}:/etc/haproxy/dataplaneapi.yaml"
6768
fi
6869
assert_success
@@ -75,15 +76,17 @@ setup() {
7576
run dpa_docker_exec 'kill -s 12 1'
7677
assert_success
7778

78-
run dpa_docker_exec 'pkill -9 dataplaneapi'
79-
assert_success
79+
if [ -z "$DONT_RESTART_DPAPI" ]; then
80+
run dpa_docker_exec 'pkill -9 dataplaneapi'
81+
assert_success
8082

81-
if [ -x "${BATS_TEST_DIRNAME}/custom_dataplane_launch.sh" ]; then
82-
run "${BATS_TEST_DIRNAME}/custom_dataplane_launch.sh"
83-
else
84-
run docker exec -d ${DOCKER_CONTAINER_NAME} /bin/sh -c "CI_DATAPLANE_RELOAD_DELAY_OVERRIDE=1 dataplaneapi -f /etc/haproxy/dataplaneapi.yaml"
83+
if [ -x "${BATS_TEST_DIRNAME}/custom_dataplane_launch.sh" ]; then
84+
run "${BATS_TEST_DIRNAME}/custom_dataplane_launch.sh"
85+
else
86+
run docker exec -d ${DOCKER_CONTAINER_NAME} /bin/sh -c "CI_DATAPLANE_RELOAD_DELAY_OVERRIDE=1 dataplaneapi -f /etc/haproxy/dataplaneapi.yaml"
87+
fi
88+
assert_success
8589
fi
86-
assert_success
8790

8891
local restart_retry_count=0
8992

0 commit comments

Comments
 (0)