fix(#3462): re-sign a leaf when it stops covering the configured names
Expiry was the only re-sign trigger, so a leaf signed when the name set was smaller stayed valid -- and wrong -- for its whole lifetime. Adding a service to swarm.serviceDomains reissues the sub-CA (its own .names reconciliation) but nothing regenerated the leaf nginx actually serves, which left the previous commit's config change unable to fix anything on a hive whose gateway leaf was not near expiry. covers() reads the DNS names back out of the certificate rather than a sidecar file: the pem is what nginx serves, and a bookkeeping file drifts from it the moment a leaf is replaced by hand. Applied to both leaves -- the hive leaf has the same defect if the hive domain ever changes.
This commit is contained in:
parent
2dea5798e4
commit
2d2f16406f
1 changed files with 37 additions and 3 deletions
|
|
@ -514,6 +514,39 @@ in
|
||||||
[ -s "$1" ] && openssl x509 -in "$1" -noout -checkend "$halflife" >/dev/null 2>&1
|
[ -s "$1" ] && openssl x509 -in "$1" -noout -checkend "$halflife" >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Expiry is not the only way a leaf goes wrong. A leaf signed
|
||||||
|
# when the configured name set was smaller stays valid for its
|
||||||
|
# whole lifetime while omitting every name added since — so a
|
||||||
|
# config change can evaluate, build and deploy cleanly and the
|
||||||
|
# gateway still serves a certificate that does not cover the new
|
||||||
|
# service. The services sub-CA already reconciles this way (its
|
||||||
|
# `.names` comparison in ../swarm-ca.nix); the leaves did not, so
|
||||||
|
# adding a name to the config alone could not fix a mis-served
|
||||||
|
# certificate on any hive whose leaf was not already near expiry.
|
||||||
|
#
|
||||||
|
# Read the names out of the CERTIFICATE, not a sidecar file: the
|
||||||
|
# pem is what nginx actually serves, and a bookkeeping file
|
||||||
|
# drifts from it the moment anyone replaces a leaf by hand.
|
||||||
|
covers() { # $1 = leaf, $2 = space-separated names it must carry
|
||||||
|
[ -s "$1" ] || return 1
|
||||||
|
_have="$(openssl x509 -in "$1" -noout -ext subjectAltName 2>/dev/null \
|
||||||
|
| tr ',' '\n' | sed -n 's/^[[:space:]]*DNS:\(.*\)$/\1/p')"
|
||||||
|
[ -n "$_have" ] || return 1
|
||||||
|
_missing=0
|
||||||
|
# ⚠️ The hive leaf carries `*.<domain>`; without this the shell
|
||||||
|
# expands it against the cwd and the comparison silently tests
|
||||||
|
# a filename.
|
||||||
|
set -f
|
||||||
|
for _n in $2; do
|
||||||
|
printf '%s\n' "$_have" | grep -qxF "$_n" || _missing=1
|
||||||
|
done
|
||||||
|
set +f
|
||||||
|
[ "$_missing" = 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
hiveNames=${lib.escapeShellArg "${domain} *.${domain}"}
|
||||||
|
svcNames=${lib.escapeShellArg (lib.concatStringsSep " " swarmServiceDomains)}
|
||||||
|
|
||||||
# The services leaf is only expected where the sub-CA exists;
|
# The services leaf is only expected where the sub-CA exists;
|
||||||
# elsewhere its absence is the correct state, not a stale leaf.
|
# elsewhere its absence is the correct state, not a stale leaf.
|
||||||
want_svc=${if swarmServiceDomains == [ ] then "0" else "1"}
|
want_svc=${if swarmServiceDomains == [ ] then "0" else "1"}
|
||||||
|
|
@ -521,12 +554,13 @@ in
|
||||||
want_svc=0
|
want_svc=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if fresh "$leaf" && { [ "$want_svc" = 0 ] || fresh "$svcleaf"; }; then
|
if fresh "$leaf" && covers "$leaf" "$hiveNames" \
|
||||||
echo "leaves valid for more than half their lifetime — no resign needed"
|
&& { [ "$want_svc" = 0 ] || { fresh "$svcleaf" && covers "$svcleaf" "$svcNames"; }; }; then
|
||||||
|
echo "leaves valid, and covering the configured names — no resign needed"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "a leaf is missing or near expiry — re-signing under the current CAs"
|
echo "a leaf is missing, near expiry, or missing a configured name — re-signing"
|
||||||
before="$(sha256sum "$leaf" "$svcleaf" 2>/dev/null || true)"
|
before="$(sha256sum "$leaf" "$svcleaf" 2>/dev/null || true)"
|
||||||
|
|
||||||
${signHiveLeaf}
|
${signHiveLeaf}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue