fix(#2417): trust hive ca in forge container for self-signed webhook delivery
This commit is contained in:
parent
ec24b96022
commit
15e56986ad
1 changed files with 66 additions and 0 deletions
|
|
@ -8,6 +8,22 @@ let
|
||||||
cfg = config.services.hyperhive.forge;
|
cfg = config.services.hyperhive.forge;
|
||||||
gatewayCfg = config.services.hyperhive.gateway;
|
gatewayCfg = config.services.hyperhive.gateway;
|
||||||
hyperhiveDomain = config.services.hyperhive.domain;
|
hyperhiveDomain = config.services.hyperhive.domain;
|
||||||
|
tlsCfg = config.services.hyperhive.tls;
|
||||||
|
|
||||||
|
# Self-signed gateway TLS: forgejo (Go) validates outbound webhook
|
||||||
|
# deliveries (e.g. the config-PR webhook to https://<domain>/webhook/...)
|
||||||
|
# against its system cert store, which lacks the runtime-generated hive
|
||||||
|
# CA — so delivery fails with an x509 "unknown authority". Go has no
|
||||||
|
# additive trust env var (SSL_CERT_FILE *replaces* the default bundle),
|
||||||
|
# so bind the public CA in and hand forgejo a combined bundle (system
|
||||||
|
# CAs + hive CA) via SSL_CERT_FILE. Only active in self-signed mode;
|
||||||
|
# with an operator cert / ACME the public chain already validates and
|
||||||
|
# this whole block drops out. `gateway.useSelfSigned` is the single
|
||||||
|
# source of truth for the self-signed condition (no duplicated logic).
|
||||||
|
useSelfSigned = gatewayCfg.useSelfSigned;
|
||||||
|
caHostPath = "${tlsCfg.stateDir}/ca.pem";
|
||||||
|
caContainerPath = "/run/hive-ca/ca.pem";
|
||||||
|
forgeCaBundle = "/run/hive-forge-ca/ca-bundle.crt";
|
||||||
|
|
||||||
# ROOT_URL forgejo advertises in clone links + outbound URLs. When
|
# ROOT_URL forgejo advertises in clone links + outbound URLs. When
|
||||||
# served behind the gateway, `cfg.domain` doubles as both the
|
# served behind the gateway, `cfg.domain` doubles as both the
|
||||||
|
|
@ -303,6 +319,15 @@ in
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# The hive CA cert is generated at runtime by the host `hive-tls-ca`
|
||||||
|
# service. Order the container after it (self-signed mode only) so the
|
||||||
|
# bind source exists before nspawn sets the CA mount up — a
|
||||||
|
# condition-skipped/late CA would otherwise fail the container start.
|
||||||
|
systemd.services."container@hive-forge" = lib.mkIf useSelfSigned {
|
||||||
|
after = [ "hive-tls-ca.service" ];
|
||||||
|
requires = [ "hive-tls-ca.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
containers.hive-forge = {
|
containers.hive-forge = {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
ephemeral = false;
|
ephemeral = false;
|
||||||
|
|
@ -311,6 +336,17 @@ in
|
||||||
# and agent containers (which also share host netns) reach it
|
# and agent containers (which also share host netns) reach it
|
||||||
# via plain `localhost`.
|
# via plain `localhost`.
|
||||||
privateNetwork = false;
|
privateNetwork = false;
|
||||||
|
# Self-signed mode: bind ONLY the public hive CA cert (never the
|
||||||
|
# `hive-tls` state dir — it holds the CA + leaf private keys) so
|
||||||
|
# forgejo can trust the gateway's self-signed leaf for outbound
|
||||||
|
# webhook delivery. The combined bundle is assembled at container
|
||||||
|
# start by hive-forge-ca-bundle below.
|
||||||
|
bindMounts = lib.optionalAttrs useSelfSigned {
|
||||||
|
${caContainerPath} = {
|
||||||
|
hostPath = caHostPath;
|
||||||
|
isReadOnly = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
config =
|
config =
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
let
|
let
|
||||||
|
|
@ -447,6 +483,36 @@ in
|
||||||
"d /var/lib/forgejo/data/actions_artifacts 0750 forgejo forgejo - -"
|
"d /var/lib/forgejo/data/actions_artifacts 0750 forgejo forgejo - -"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Self-signed mode: assemble the combined TLS trust bundle
|
||||||
|
# (system CAs + the bind-mounted hive CA) forgejo's Go HTTP
|
||||||
|
# client validates outbound webhook deliveries against. Go's
|
||||||
|
# SSL_CERT_FILE *replaces* the default bundle, so we concatenate
|
||||||
|
# rather than point at the CA alone — otherwise mirror fetches
|
||||||
|
# from public hosts would lose their trust anchors. Runs before
|
||||||
|
# forgejo each boot; /run is tmpfs so the bundle is rebuilt from
|
||||||
|
# the current CA every start.
|
||||||
|
systemd.services.hive-forge-ca-bundle = lib.mkIf useSelfSigned {
|
||||||
|
description = "assemble forgejo TLS trust bundle (system CAs + hive CA)";
|
||||||
|
wantedBy = [ "forgejo.service" ];
|
||||||
|
before = [ "forgejo.service" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
SyslogIdentifier = "hive-forge-ca-bundle";
|
||||||
|
};
|
||||||
|
path = [ pkgs.coreutils ];
|
||||||
|
script = ''
|
||||||
|
set -euo pipefail
|
||||||
|
install -d -m 0755 /run/hive-forge-ca
|
||||||
|
cat /etc/ssl/certs/ca-certificates.crt ${caContainerPath} \
|
||||||
|
> ${forgeCaBundle}
|
||||||
|
chmod 0644 ${forgeCaBundle}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
# Point forgejo's Go TLS stack at the combined bundle so webhook
|
||||||
|
# delivery to the self-signed gateway validates.
|
||||||
|
systemd.services.forgejo.environment.SSL_CERT_FILE = lib.mkIf useSelfSigned forgeCaBundle;
|
||||||
|
|
||||||
# Ensure Forgejo has a usable GPG signing key so UI merges / CRUD
|
# Ensure Forgejo has a usable GPG signing key so UI merges / CRUD
|
||||||
# commits are signed instead of erroring "does not have a signing
|
# commits are signed instead of erroring "does not have a signing
|
||||||
# key". This service (a) generates a key in forgejo's persistent
|
# key". This service (a) generates a key in forgejo's persistent
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue