hive-gateway: idempotent cert oneshot, always-run + parse check (#856 follow-up)
This commit is contained in:
parent
2bdb8c7d51
commit
0aa0e5b95a
1 changed files with 27 additions and 17 deletions
|
|
@ -403,21 +403,22 @@ in
|
||||||
{
|
{
|
||||||
system.stateVersion = "26.05";
|
system.stateVersion = "26.05";
|
||||||
|
|
||||||
# Generate a self-signed cert on first boot if missing. nginx
|
# Ensure a valid self-signed cert exists before nginx starts.
|
||||||
# `Requires=` this via `requiredBy`, so systemd refuses to
|
# nginx `Requires=` this via `requiredBy`, so systemd refuses
|
||||||
# start nginx until the cert exists — `before=` alone wasn't
|
# to start nginx until the script succeeds. ALWAYS runs (no
|
||||||
# enough (it only orders within a single transaction, but
|
# ConditionPathExists) and is idempotent — that's necessary
|
||||||
# nginx was being pulled into a different transaction by
|
# to reconcile broken state left over from prior failed
|
||||||
# multi-user.target and started without waiting, #856). Cert
|
# boots (a 0700 dir from a stale UMask, a truncated cert
|
||||||
# covers the bare hive domain plus `*.${hyperhiveDomain}` so
|
# from an interrupted oneshot, etc.) which a guarded-on-
|
||||||
# the matrix + forge sub-domains are valid under the same
|
# missing-cert script would silently skip and leave broken.
|
||||||
|
# Cert covers the bare hive domain plus `*.${hyperhiveDomain}`
|
||||||
|
# so the matrix + forge sub-domains are valid under the same
|
||||||
# cert. See `docs/gateway.md` ("Self-signed TLS").
|
# cert. See `docs/gateway.md` ("Self-signed TLS").
|
||||||
systemd.services.hive-gateway-self-signed-cert = lib.mkIf cfg.selfSignedTls {
|
systemd.services.hive-gateway-self-signed-cert = lib.mkIf cfg.selfSignedTls {
|
||||||
description = "Generate self-signed TLS cert for hive-gateway";
|
description = "Ensure self-signed TLS cert for hive-gateway";
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
before = [ "nginx.service" ];
|
before = [ "nginx.service" ];
|
||||||
requiredBy = [ "nginx.service" ];
|
requiredBy = [ "nginx.service" ];
|
||||||
unitConfig.ConditionPathExists = "!${tlsCert}";
|
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
RemainAfterExit = true;
|
RemainAfterExit = true;
|
||||||
|
|
@ -438,16 +439,25 @@ in
|
||||||
);
|
);
|
||||||
in
|
in
|
||||||
''
|
''
|
||||||
|
set -eu
|
||||||
mkdir -p ${tlsDir}
|
mkdir -p ${tlsDir}
|
||||||
# 0755 dir so nginx (master starts as root but workers
|
# 0755 dir so nginx (master starts as root but workers
|
||||||
# drop to the nginx user) can read the cert path
|
# drop to the nginx user) can traverse to read the cert
|
||||||
# without traversal failures. Key stays 0600 below.
|
# path. Re-applied every boot in case a prior run left
|
||||||
|
# a tighter mode behind. Key stays 0600 below.
|
||||||
chmod 0755 ${tlsDir}
|
chmod 0755 ${tlsDir}
|
||||||
openssl req -x509 -newkey rsa:4096 -nodes -sha256 -days 3650 \
|
# Generate the cert when it's missing OR fails an
|
||||||
-keyout ${tlsKey} \
|
# openssl parse — catches truncated / corrupt leftovers
|
||||||
-out ${tlsCert} \
|
# from a previous interrupted run. The whole oneshot is
|
||||||
-subj "/CN=${subjectCN}" \
|
# safe to re-run; a healthy cert is left alone.
|
||||||
-addext "subjectAltName=${sanLines}"
|
if [ ! -s ${tlsCert} ] || ! openssl x509 -in ${tlsCert} -noout >/dev/null 2>&1; then
|
||||||
|
echo "generating fresh self-signed cert at ${tlsCert}"
|
||||||
|
openssl req -x509 -newkey rsa:4096 -nodes -sha256 -days 3650 \
|
||||||
|
-keyout ${tlsKey} \
|
||||||
|
-out ${tlsCert} \
|
||||||
|
-subj "/CN=${subjectCN}" \
|
||||||
|
-addext "subjectAltName=${sanLines}"
|
||||||
|
fi
|
||||||
chmod 0600 ${tlsKey}
|
chmod 0600 ${tlsKey}
|
||||||
chmod 0644 ${tlsCert}
|
chmod 0644 ${tlsCert}
|
||||||
'';
|
'';
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue