Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b8e77c1c1 | ||
|
|
9f03cf31ba |
3 changed files with 69 additions and 5 deletions
|
|
@ -7,6 +7,20 @@
|
||||||
let
|
let
|
||||||
cfg = config.services.hyperhive.forge.ci;
|
cfg = config.services.hyperhive.forge.ci;
|
||||||
forgeCfg = config.services.hyperhive.forge;
|
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.
|
||||||
|
# `gateway.useSelfSigned` is the gateway module's single source of truth
|
||||||
|
# for the self-signed condition (no duplicated derivation here).
|
||||||
|
useSelfSigned = gatewayCfg.useSelfSigned;
|
||||||
|
caHostPath = "${tlsCfg.stateDir}/ca.pem";
|
||||||
|
caContainerPath = "/run/hive-ca/ca.pem";
|
||||||
|
|
||||||
# hive-c0re writes its own admin token here on first forge startup.
|
# hive-c0re writes its own admin token here on first forge startup.
|
||||||
# The token has read:admin + write:admin scopes — sufficient to call
|
# The token has read:admin + write:admin scopes — sufficient to call
|
||||||
|
|
@ -315,6 +329,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 = {
|
containers.hive-ci = {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
ephemeral = false;
|
ephemeral = false;
|
||||||
|
|
@ -329,6 +352,18 @@ in
|
||||||
hostPath = "/run/hive-ci/runner-token";
|
hostPath = "/run/hive-ci/runner-token";
|
||||||
isReadOnly = true;
|
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 =
|
config =
|
||||||
|
|
@ -408,6 +443,19 @@ in
|
||||||
|
|
||||||
systemd.services."gitea-runner-hive" = {
|
systemd.services."gitea-runner-hive" = {
|
||||||
path = [ pkgs.nix ];
|
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
|
# Gate runner start (and therefore job registration/claiming) on
|
||||||
# the in-container nix daemon being reachable. After a hive-ci
|
# the in-container nix daemon being reachable. After a hive-ci
|
||||||
# restart the runner re-registers and immediately claims any
|
# restart the runner re-registers and immediately claims any
|
||||||
|
|
|
||||||
|
|
@ -175,6 +175,23 @@ in
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useSelfSigned = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
default = useSelfSigned;
|
||||||
|
defaultText = lib.literalExpression "tls.certDir == null && !tls.acme.enable";
|
||||||
|
description = ''
|
||||||
|
Read-only derived flag: `true` when the gateway serves the
|
||||||
|
self-signed (hive-CA-signed) leaf — i.e. neither `tls.certDir` nor
|
||||||
|
`tls.acme.enable` is configured. Single source of truth for the
|
||||||
|
self-signed condition; consumed by the `hive-tls` and `hive-ci`
|
||||||
|
modules so the derivation isn't duplicated. Internal — not meant to
|
||||||
|
be set by operators (use `tls.certDir` / `tls.acme` to override the
|
||||||
|
self-signed default).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
httpsPort = lib.mkOption {
|
httpsPort = lib.mkOption {
|
||||||
type = lib.types.port;
|
type = lib.types.port;
|
||||||
default = 443;
|
default = 443;
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,10 @@ let
|
||||||
# The host-managed hive CA is the trust anchor for self-signed mode.
|
# The host-managed hive CA is the trust anchor for self-signed mode.
|
||||||
# It is only stood up when the gateway actually serves a self-signed
|
# It is only stood up when the gateway actually serves a self-signed
|
||||||
# cert: a domain must be set (the leaf SANs derive from it) and the
|
# cert: a domain must be set (the leaf SANs derive from it) and the
|
||||||
# gateway must be in self-signed mode — i.e. neither an operator cert
|
# gateway must be in self-signed mode. The self-signed condition is the
|
||||||
# (`tls.certDir`) nor ACME is configured. With either of those the
|
# gateway module's single source of truth (`gateway.useSelfSigned`):
|
||||||
# public/operator CA already validates, so the hive CA is unnecessary.
|
# true when neither an operator cert (`tls.certDir`) nor ACME is set.
|
||||||
useSelfSigned = gatewayCfg.tls.certDir == null && !gatewayCfg.tls.acme.enable;
|
active = hyperhiveCfg.enable && gatewayCfg.useSelfSigned && domain != null;
|
||||||
active = hyperhiveCfg.enable && useSelfSigned && domain != null;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# Host-side TLS trust root for the self-signed gateway mode.
|
# Host-side TLS trust root for the self-signed gateway mode.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue