Compare commits

..

View file

@ -403,22 +403,21 @@ in
{ {
system.stateVersion = "26.05"; system.stateVersion = "26.05";
# Ensure a valid self-signed cert exists before nginx starts. # Generate a self-signed cert on first boot if missing. nginx
# nginx `Requires=` this via `requiredBy`, so systemd refuses # `Requires=` this via `requiredBy`, so systemd refuses to
# to start nginx until the script succeeds. ALWAYS runs (no # start nginx until the cert exists — `before=` alone wasn't
# ConditionPathExists) and is idempotent — that's necessary # enough (it only orders within a single transaction, but
# to reconcile broken state left over from prior failed # nginx was being pulled into a different transaction by
# boots (a 0700 dir from a stale UMask, a truncated cert # multi-user.target and started without waiting, #856). Cert
# from an interrupted oneshot, etc.) which a guarded-on- # covers the bare hive domain plus `*.${hyperhiveDomain}` so
# missing-cert script would silently skip and leave broken. # the matrix + forge sub-domains are valid under the same
# 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 = "Ensure self-signed TLS cert for hive-gateway"; description = "Generate 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;
@ -439,29 +438,16 @@ 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 traverse to read the cert # drop to the nginx user) can read the cert path
# path. Re-applied every boot in case a prior run left # without traversal failures. Key stays 0600 below.
# a tighter mode behind. Key stays 0600 below.
chmod 0755 ${tlsDir} chmod 0755 ${tlsDir}
# Generate the cert when EITHER the cert or key is openssl req -x509 -newkey rsa:4096 -nodes -sha256 -days 3650 \
# missing/empty, OR the cert fails an openssl parse — -keyout ${tlsKey} \
# catches truncated / corrupt leftovers from a previous -out ${tlsCert} \
# interrupted run AND the "cert clean but key absent" -subj "/CN=${subjectCN}" \
# edge case (argus 🟡 on the first revision) which -addext "subjectAltName=${sanLines}"
# otherwise tripped `chmod 0600 ${tlsKey}` below with
# ENOENT under `set -eu`. The whole oneshot is safe to
# re-run; a healthy cert+key pair is left alone.
if [ ! -s ${tlsCert} ] || [ ! -s ${tlsKey} ] || ! 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}
''; '';