nix(ci): trust the hive CA in the runner's Node actions (self-signed TLS)
With self-signed TLS the gateway/forge serve a hive-CA-signed leaf and forgejo's ROOT_URL is https://forge.<domain>. The CI runner's Node-based actions (e.g. upload-artifact) POST to the ROOT_URL-derived artifact endpoint and fail with "unable to verify the first certificate": Node uses its own bundled CA bundle, not the system store, so it rejects the self-signed chain. checkout etc. are fine — they hit the localhost http registration URL. Bind-mount the public hive CA cert (only ca.pem — never the hive-tls state dir, which holds the CA + leaf private keys) into the hive-ci container and set NODE_EXTRA_CA_CERTS on the runner service so every Node action trusts it, hive-wide. Order container@hive-ci after the host hive-tls-ca service so the cert exists before the bind-mount is set up. All gated on self-signed mode; with an operator cert / ACME the public CA already validates and the mount + env var are absent. Eval-proven: self-signed → /run/hive-ca/ca.pem bind-mount (from /var/lib/hive-tls/ca.pem), NODE_EXTRA_CA_CERTS=/run/hive-ca/ca.pem, and container@hive-ci ordered after hive-tls-ca.service; certDir → all absent.
This commit is contained in:
parent
1bc26429f2
commit
9f03cf31ba
1 changed files with 46 additions and 0 deletions
|
|
@ -7,6 +7,18 @@
|
|||
let
|
||||
cfg = config.services.hyperhive.forge.ci;
|
||||
forgeCfg = config.services.hyperhive.forge;
|
||||
gatewayCfg = config.services.hyperhive.gateway;
|
||||
tlsCfg = config.services.hyperhive.tls;
|
||||
|
||||
# Self-signed TLS is the gateway default (no operator cert / ACME). When
|
||||
# active, forgejo's ROOT_URL is `https://forge.<domain>` and the leaf is
|
||||
# signed by the host hive CA — so the runner's Node-based actions (e.g.
|
||||
# `upload-artifact`, which POSTs to the ROOT_URL-derived artifact endpoint)
|
||||
# reject the chain, since Node trusts only its bundled CA bundle, not the
|
||||
# system store. Trust the hive CA explicitly via NODE_EXTRA_CA_CERTS below.
|
||||
useSelfSigned = gatewayCfg.tls.certDir == null && !gatewayCfg.tls.acme.enable;
|
||||
caHostPath = "${tlsCfg.stateDir}/ca.pem";
|
||||
caContainerPath = "/run/hive-ca/ca.pem";
|
||||
|
||||
# hive-c0re writes its own admin token here on first forge startup.
|
||||
# The token has read:admin + write:admin scopes — sufficient to call
|
||||
|
|
@ -315,6 +327,15 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
# Self-signed mode: the CA cert the bind-mount above sources is
|
||||
# generated by the host `hive-tls-ca` service. Order the container after
|
||||
# it so the bind source exists before nspawn sets the mount up (a
|
||||
# condition-skipped/late CA would otherwise fail the container start).
|
||||
systemd.services."container@hive-ci" = lib.mkIf useSelfSigned {
|
||||
after = [ "hive-tls-ca.service" ];
|
||||
requires = [ "hive-tls-ca.service" ];
|
||||
};
|
||||
|
||||
containers.hive-ci = {
|
||||
autoStart = true;
|
||||
ephemeral = false;
|
||||
|
|
@ -329,6 +350,18 @@ in
|
|||
hostPath = "/run/hive-ci/runner-token";
|
||||
isReadOnly = true;
|
||||
};
|
||||
}
|
||||
# Self-signed mode: bind ONLY the public hive CA cert (never the
|
||||
# `hive-tls` state dir — it holds the CA + leaf private keys) so the
|
||||
# runner's Node actions can trust the gateway/forge self-signed leaf
|
||||
# (see NODE_EXTRA_CA_CERTS in the container config). Source generated
|
||||
# by the host `hive-tls-ca` service; the container@hive-ci ordering
|
||||
# below guarantees it exists before this mount is set up.
|
||||
// lib.optionalAttrs useSelfSigned {
|
||||
${caContainerPath} = {
|
||||
hostPath = caHostPath;
|
||||
isReadOnly = true;
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
|
|
@ -408,6 +441,19 @@ in
|
|||
|
||||
systemd.services."gitea-runner-hive" = {
|
||||
path = [ pkgs.nix ];
|
||||
# Trust the hive CA in Node-based actions. With self-signed TLS,
|
||||
# forgejo's ROOT_URL is `https://forge.<domain>` (CA-signed leaf),
|
||||
# so actions like `upload-artifact` — whose Node HTTP client uses
|
||||
# Node's *bundled* CA bundle, not the system store — reject the
|
||||
# chain with "unable to verify the first certificate". Pointing
|
||||
# NODE_EXTRA_CA_CERTS at the bind-mounted CA adds it to Node's
|
||||
# roots for every action, hive-wide. Inherited by the job
|
||||
# processes the runner spawns (host execution mode). Only set in
|
||||
# self-signed mode; with an operator cert / ACME the public CA
|
||||
# already validates and the bind-mount is absent.
|
||||
environment = lib.mkIf useSelfSigned {
|
||||
NODE_EXTRA_CA_CERTS = caContainerPath;
|
||||
};
|
||||
# Gate runner start (and therefore job registration/claiming) on
|
||||
# the in-container nix daemon being reachable. After a hive-ci
|
||||
# restart the runner re-registers and immediately claims any
|
||||
|
|
|
|||
Loading…
Reference in a new issue