fix(#3396): move the forge onto the shared trust-bundle helper
Last of the three modules that hand-rolled the same concat with wantedBy + before and no requires, so a failed assembly left the consumer running against a missing file and trusting nothing -- every outbound TLS call fails while the unit looks healthy. The forge is the one with two consumers: forgejo-sso-source fetches the issuer's discovery document over the swarm CA and once shipped without the trust its sibling had. It only exists when SSO is on, so the consumer list is conditional -- naming an absent unit would define a serviceless one and order nothing. Removes the now-dead useSelfSigned and caContainerPath bindings (nix does not warn) and retargets three comments the deletion orphaned, including the helper header that still named this module as the per-call-site concat.
This commit is contained in:
parent
9073c9b3f7
commit
2eb74f3a74
2 changed files with 38 additions and 67 deletions
|
|
@ -11,18 +11,6 @@ let
|
||||||
swarmDomain = config.services.hyperhive.swarm.domain;
|
swarmDomain = config.services.hyperhive.swarm.domain;
|
||||||
tlsCfg = config.services.hyperhive.tls;
|
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. The bind-mount + `container@` ordering
|
|
||||||
# that make the CA reachable are shared with hive-ci via the
|
|
||||||
# `hive-ca-trust` helper; only the Go SSL_CERT_FILE concat below is
|
|
||||||
# hive-forge-specific.
|
|
||||||
# Forgejo's name for the login source. A constant, not an option: it
|
# Forgejo's name for the login source. A constant, not an option: it
|
||||||
# is the key this module's own idempotency check looks up, so making
|
# is the key this module's own idempotency check looks up, so making
|
||||||
# it configurable would buy nothing and add a way for the lookup and
|
# it configurable would buy nothing and add a way for the lookup and
|
||||||
|
|
@ -72,9 +60,6 @@ let
|
||||||
ssoRedirectUri = "${effectiveRootUrl}user/oauth2/${ssoSourceName}/callback";
|
ssoRedirectUri = "${effectiveRootUrl}user/oauth2/${ssoSourceName}/callback";
|
||||||
|
|
||||||
caTrust = import ../lib/hive-ca-trust.nix { inherit lib tlsCfg gatewayCfg; };
|
caTrust = import ../lib/hive-ca-trust.nix { inherit lib tlsCfg gatewayCfg; };
|
||||||
useSelfSigned = caTrust.useSelfSigned;
|
|
||||||
caContainerPath = caTrust.caContainerPath;
|
|
||||||
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
|
||||||
|
|
@ -579,9 +564,9 @@ in
|
||||||
privateNetwork = false;
|
privateNetwork = false;
|
||||||
# Self-signed mode: bind the public hive CA cert read-only so forgejo
|
# Self-signed mode: bind the public hive CA cert read-only so forgejo
|
||||||
# can trust the gateway's self-signed leaf for outbound webhook
|
# can trust the gateway's self-signed leaf for outbound webhook
|
||||||
# delivery (combined bundle assembled at container start by
|
# delivery. The bind-mount, the `container@` ordering and the bundle
|
||||||
# hive-forge-ca-bundle below). Shared bind-mount + ordering come from
|
# the container's consumers read all come from the hive-ca-trust
|
||||||
# the hive-ca-trust helper.
|
# helper — see the container's `imports` for the consumption half.
|
||||||
bindMounts = caTrust.bindMount;
|
bindMounts = caTrust.bindMount;
|
||||||
config =
|
config =
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
@ -607,6 +592,26 @@ in
|
||||||
'';
|
'';
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
imports = [
|
||||||
|
# Forgejo is Go, and `SSL_CERT_FILE` *replaces* the default store
|
||||||
|
# rather than adding to it — so it needs the system CAs and the
|
||||||
|
# hive CA concatenated, not the CA alone, or public mirror fetches
|
||||||
|
# lose every anchor they had.
|
||||||
|
#
|
||||||
|
# BOTH units that make an outbound HTTPS call are consumers, not
|
||||||
|
# just the obvious one: `forgejo-sso-source` fetches the issuer's
|
||||||
|
# `.well-known/openid-configuration` over the swarm CA, and it
|
||||||
|
# once shipped without the trust its sibling had. `optional`
|
||||||
|
# rather than a flat list because that unit only exists when SSO
|
||||||
|
# is on — naming an absent unit would order nothing and quietly
|
||||||
|
# define a serviceless one.
|
||||||
|
(caTrust.trustBundle {
|
||||||
|
inherit pkgs;
|
||||||
|
name = "hive-forge";
|
||||||
|
consumers = [ "forgejo" ] ++ lib.optional cfg.sso.enable "forgejo-sso-source";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
system.stateVersion = "25.11";
|
system.stateVersion = "25.11";
|
||||||
|
|
||||||
# Shared host netns: this container's own firewall.service
|
# Shared host netns: this container's own firewall.service
|
||||||
|
|
@ -764,36 +769,6 @@ 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
|
||||||
|
|
@ -888,23 +863,18 @@ in
|
||||||
# `FORGEJO_CUSTOM` (not `GITEA_CUSTOM` — forgejo renamed it)
|
# `FORGEJO_CUSTOM` (not `GITEA_CUSTOM` — forgejo renamed it)
|
||||||
# is how the CLI finds the app.ini upstream's module wrote.
|
# is how the CLI finds the app.ini upstream's module wrote.
|
||||||
#
|
#
|
||||||
# `SSL_CERT_FILE` for the same reason `forgejo.service` has it,
|
# This unit is also a trust-bundle consumer (declared in the
|
||||||
# and it was missing here: registering the login source makes an
|
# container's `imports` above, which is where `SSL_CERT_FILE`
|
||||||
# **outbound HTTPS call** — the CLI fetches
|
# comes from): registering the login source makes an **outbound
|
||||||
# `<issuer>/.well-known/openid-configuration` to validate the
|
# HTTPS call** to `<issuer>/.well-known/openid-configuration`,
|
||||||
# provider before writing the row. That URL is a swarm service
|
# served under the swarm CA the default store has never heard of.
|
||||||
# name served under the swarm CA, which the default system store
|
# It once shipped without the trust `forgejo.service` had, and
|
||||||
# has never heard of, so without this the unit fails every single
|
# failed every single time with `x509: certificate signed by
|
||||||
# time with `x509: certificate signed by unknown authority` and no
|
# unknown authority`. The trust belongs to every process that
|
||||||
# restart can help it.
|
# makes the call, not to the obvious consumer.
|
||||||
#
|
|
||||||
# The trust belongs to every process that makes the call, not to
|
|
||||||
# the service that happens to be the obvious consumer. Same
|
|
||||||
# binary, same host, different unit — and only one of them had it.
|
|
||||||
environment = {
|
environment = {
|
||||||
FORGEJO_CUSTOM = "/var/lib/forgejo/custom";
|
FORGEJO_CUSTOM = "/var/lib/forgejo/custom";
|
||||||
}
|
};
|
||||||
// lib.optionalAttrs useSelfSigned { SSL_CERT_FILE = forgeCaBundle; };
|
|
||||||
path = [
|
path = [
|
||||||
cfg.package
|
cfg.package
|
||||||
pkgs.coreutils
|
pkgs.coreutils
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,11 @@
|
||||||
# and orders its `container@<name>` unit after `hive-tls-ca.service` so the
|
# and orders its `container@<name>` unit after `hive-tls-ca.service` so the
|
||||||
# bind source exists before nspawn sets the mount up.
|
# bind source exists before nspawn sets the mount up.
|
||||||
#
|
#
|
||||||
# This is the language-agnostic half (bind-mount + systemd ordering). The
|
# `bindMount` + `containerOrdering` are the language-agnostic half. The
|
||||||
# *consumption* differs per runtime and stays at each call site: Node's
|
# *consumption* differs per runtime: an additive variable (Node's
|
||||||
# `NODE_EXTRA_CA_CERTS` is additive (hive-ci), Go's `SSL_CERT_FILE` replaces
|
# `NODE_EXTRA_CA_CERTS`, hive-ci) points straight at `caContainerPath` from
|
||||||
# the bundle so it needs a system-CAs+hive-CA concat step (hive-forge).
|
# the call site, while a *replacing* one (Go's `SSL_CERT_FILE`, rustls) needs
|
||||||
|
# the system-CAs+hive-CA concat that `trustBundle` below does for it.
|
||||||
#
|
#
|
||||||
# Pure function — NOT a NixOS module (don't add it to the host-modules
|
# Pure function — NOT a NixOS module (don't add it to the host-modules
|
||||||
# aggregator). Call it from a module's `let`:
|
# aggregator). Call it from a module's `let`:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue