Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .github/workflows/traefik_v3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: traefik_v3 tests

on:
pull_request:
branches: master

jobs:
# Run tests
test:
runs-on: ubuntu-latest

steps:
- name: Checkout repository and submodules
uses: actions/checkout@v3
with:
submodules: recursive

- name: Build docker image
run: make build-no-cache

- name: Run tests
run: make traefik_v3
45 changes: 43 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ define dnsbl_probe
-@docker exec $(1) sh /tmp/tests/dnsbl-probe.sh
endef

all: build-no-cache default reverse ldap ldap2 sieve ecdsa traefik_acmev1 traefik_acmev2 clean
no-build: default reverse ldap ldap2 sieve ecdsa traefik_acmev1 traefik_acmev2 clean
all: build-no-cache default reverse ldap ldap2 sieve ecdsa traefik_acmev1 traefik_acmev2 traefik_v3 clean
no-build: default reverse ldap ldap2 sieve ecdsa traefik_acmev1 traefik_acmev2 traefik_v3 clean
default: init_default fixtures_default run_default stop_default
reverse: init_reverse fixtures_reverse run_reverse stop_reverse
ldap: init_ldap fixtures_ldap run_ldap stop_ldap
Expand All @@ -33,6 +33,7 @@ sieve: init_sieve fixtures_sieve run_sieve stop_sieve
ecdsa: init_ecdsa run_ecdsa stop_ecdsa
traefik_acmev1: init_traefik_acmev1 fixtures_traefik_acmev1 run_traefik_acmev1 stop_traefik_acmev1
traefik_acmev2: init_traefik_acmev2 fixtures_traefik_acmev2 run_traefik_acmev2 stop_traefik_acmev2
traefik_v3: init_traefik_v3 fixtures_traefik_v3 run_traefik_v3 stop_traefik_v3

build-no-cache:
docker build --no-cache -t $(NAME) .
Expand Down Expand Up @@ -461,6 +462,46 @@ stop_traefik_acmev2:
-docker rm -f \
mailserver_traefik_acmev2 || true

# acme.json as written by Traefik 2 and 3 (they share the format), generated
# with Traefik 3.6 against a local ACME test server. It holds two certificate
# resolvers, the case that used to leave the mailserver without a certificate.
init_traefik_v3: init_redis init_mariadb
-docker rm -f \
mailserver_traefik_v3 || true
docker run \
-d \
--name mailserver_traefik_v3 \
--link mariadb:mariadb \
--link redis:redis \
-e DBPASS=testpasswd \
-e RSPAMD_PASSWORD=testpasswd \
-e VMAILUID=`id -u` \
-e VMAILGID=`id -g` \
-e DISABLE_CLAMAV=true \
-e TESTING=true \
-v "`pwd`/test/share/traefik/v3":/etc/letsencrypt/acme \
-h mail.domain.tld \
-t $(NAME)
fixtures_traefik_v3:
# One in-place rewrite of acme.json (same bytes) has to produce exactly one
# reload; the tests count them. Postfix and dovecot must be up so the
# reload has something to signal.
@timeout $(WAIT_TIMEOUT) sh -c 'until docker exec mailserver_traefik_v3 nc -z 0.0.0.0 25 && docker exec mailserver_traefik_v3 nc -z 0.0.0.0 143; do sleep 2; done' \
|| { echo "TIMEOUT: postfix/dovecot not listening"; docker logs --tail 20 mailserver_traefik_v3; exit 1; }
@timeout $(WAIT_TIMEOUT) sh -c 'until docker logs mailserver_traefik_v3 2>&1 | grep -q "Watching /etc/letsencrypt/acme"; do sleep 2; done' \
|| { echo "TIMEOUT: cert watcher did not start"; docker logs --tail 20 mailserver_traefik_v3; exit 1; }
docker exec mailserver_traefik_v3 python3 -c "p='/etc/letsencrypt/acme/acme.json'; d=open(p,'rb').read(); f=open(p,'r+b'); f.write(d); f.close()"
@timeout $(WAIT_TIMEOUT) sh -c 'until docker logs mailserver_traefik_v3 2>&1 | grep -q "Updating SSL certificates and reloading"; do sleep 2; done' \
|| { echo "TIMEOUT: watcher did not react to writing acme.json"; docker logs --tail 20 mailserver_traefik_v3; exit 1; }
# Settle time in which a watcher reacting to its own reads would reload again
sleep 15
run_traefik_v3:
docker exec mailserver_traefik_v3 /bin/sh -c "while ! echo PING | nc -z 0.0.0.0 587 ; do sleep 1 ; done"
./test/bats/bin/bats test/traefik_v3.bats
stop_traefik_v3:
-docker rm -f \
mailserver_traefik_v3 || true

fixtures_default:

# Wait for clamav unofficial sigs database update (default)
Expand Down
21 changes: 14 additions & 7 deletions rootfs/usr/local/bin/certs_helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ elif [ "$1" = "update_certs" ]; then
mkdir -p "$SSL_MOUNT_PATH"
mkdir -p "$CERT_TEMP_PATH"
mkdir -p "$LIVE_CERT_PATH"
rm -rf "$CERT_TEMP_PATH/*"
rm -rf "$CERT_TEMP_PATH"/*

NORMALIZED_CERT_PATH="$CERT_TEMP_PATH"/normalized
mkdir -p "$NORMALIZED_CERT_PATH"
Expand All @@ -74,7 +74,9 @@ elif [ "$1" = "update_certs" ]; then
sleep 10
fi

if jq -e -r '.PrivateKey' "$ACME_FILE" >/dev/null ; then
if [ ! -r "$ACME_FILE" ]; then
echo "[ERROR] $ACME_FILE is not readable, check its ownership and permissions" | tee -a "$ACME_DUMP"
elif jq -e -r '.PrivateKey' "$ACME_FILE" >/dev/null ; then
echo "[INFO] acme.json found with ACME v1 format, dumping into pem files" | tee -a "$ACME_DUMP"
dumpcerts.acme.v1.sh "$ACME_FILE" "$CERT_TEMP_PATH" >> "$ACME_DUMP" 2>&1
elif jq -e -r '.Account.PrivateKey' "$ACME_FILE" >/dev/null ; then
Expand All @@ -87,14 +89,15 @@ elif [ "$1" = "update_certs" ]; then
fi
elif jq -e -r '.[].Account.PrivateKey' "$ACME_FILE" >/dev/null ; then
echo "[INFO] acme.json found with Traefik v2 format, dumping into pem files" | tee -a "$ACME_DUMP"
dumpcerts.traefik.v2.sh "$ACME_FILE" "$CERT_TEMP_PATH" >> "$ACME_DUMP" 2>&1
traefik-certs-dumper file --version v2 --clean=false \
--source "$ACME_FILE" --dest "$CERT_TEMP_PATH" >> "$ACME_DUMP" 2>&1
if [ -e "$CERT_TEMP_PATH"/certs/"*.${DOMAIN}.crt" ] && [ -e "$CERT_TEMP_PATH"/private/"*.${DOMAIN}.key" ]; then
echo "[INFO] Let's encrypt wildcard certificate found" | tee -a "$ACME_DUMP"
mv -f "$CERT_TEMP_PATH"/certs/"*.${DOMAIN}.crt" "$CERT_TEMP_PATH"/certs/"$FQDN".crt
mv -f "$CERT_TEMP_PATH"/private/"*.${DOMAIN}.key" "$CERT_TEMP_PATH"/private/"$FQDN".key
fi
else
echo "[ERROR] acme.json found but with an unknown format" >> "$ACME_DUMP"
echo "[ERROR] acme.json found but with an unknown format" | tee -a "$ACME_DUMP"
fi

if [ -e "$CERT_TEMP_PATH"/certs/"$FQDN".crt ] && [ -e "$CERT_TEMP_PATH"/private/"$FQDN".key ]; then
Expand All @@ -103,8 +106,8 @@ elif [ "$1" = "update_certs" ]; then
DOMAIN_NAME="$DOMAIN"
else
echo "[ERROR] The certificate for ${FQDN} or the private key was not found !"
echo "[INFO] Don't forget to add a new traefik frontend rule to generate a certificate for ${FQDN} subdomain"
echo "[INFO] Look /mnt/docker/traefik/acme/dump.log and 'docker logs traefik' for more information"
echo "[INFO] Don't forget to add a new traefik router rule to generate a certificate for ${FQDN} subdomain"
echo "[INFO] Look $ACME_DUMP in the mail volume and 'docker logs traefik' for more information"
exit 1
fi

Expand All @@ -113,6 +116,10 @@ elif [ "$1" = "update_certs" ]; then
rm -rf "$ACME_DUMP"
RENEWED_CERTIFICATE=true
else
if [ -d "$ACME_PATH" ] && [ ! -r "$ACME_PATH" ]; then
echo "[ERROR] $ACME_PATH is not readable, check its ownership and permissions"
fi

echo "[INFO] Traefik SSL certificates not used"

if [ -d "$LETS_ENCRYPT_LIVE_PATH" ]; then
Expand Down Expand Up @@ -151,7 +158,7 @@ elif [ "$1" = "update_certs" ]; then
exit 1
fi

rm -rf "$LIVE_CERT_PATH/*"
rm -rf "$LIVE_CERT_PATH"/*
cp -RT "$NORMALIZED_CERT_PATH/." "$LIVE_CERT_PATH"

elif [ "$1" = "reload" ]; then
Expand Down
170 changes: 0 additions & 170 deletions rootfs/usr/local/bin/dumpcerts.traefik.v2.sh

This file was deleted.

Loading
Loading