bao: make the controller's CN an option, and give it cert options of its own

Two halves of one interface that currently exists in one file only.

The CN was a `let` binding in swarm-bao.nix. Whatever mints the
controller's leaf has to spell it identically, and that lives in another
file, so a literal in one place is an interface with no name. It becomes
`deploy.bao.controllerCommonName` -- under bao because it is a property
of the role this module writes, not a credential belonging to the
controller.

The certificate gets `deploy.swarm-controller.baoClientCertFile` /
`baoClientKeyFile` rather than reusing `deploy.bao.clientCertFile`. That
one means "this host as a reader" and carries the hive's name, while the
controller's policy lets it create roles for every hive; one certificate
serving both would hand that power to whatever else reads the store
here.

Both default to null. The glue that mints the leaf sets them with
`mkDefault`, the same way glue-bao-tls.nix already supplies the reader's
paths -- so the controller module names no path of bao's, and deleting
the glue leaves a controller that takes operator-provided ones.

Nothing reads the new options yet; the minting half is the next commit.
`module-eval`'s derivation is unchanged, which is the honest result for
a change that adds options without altering any asserted value -- it
proves the tree still evaluates, not that anything behaves differently.
This commit is contained in:
atlas 2026-09-07 22:12:27 +02:00
commit a5dc62cecd
2 changed files with 55 additions and 4 deletions

View file

@ -154,10 +154,9 @@ let
# policy by spelling it the same way, and is itself named after it.
controllerPolicyName = "swarm-controller";
# The subject the controller's certificate must carry. Cert auth matches on
# the CN, so this is an interface rather than a label: a leaf signed by the
# right CA but minted with any other subject cannot authenticate.
controllerCn = "swarm-controller";
# An option rather than a literal because whatever mints the controller's
# leaf has to spell it identically, and that lives in another file.
controllerCn = baoDeploy.controllerCommonName;
# Derived with `bao write -output-policy`, which short-circuits the request
# and needs no server, rather than written from memory.
@ -478,6 +477,27 @@ in
'';
};
controllerCommonName = lib.mkOption {
type = lib.types.str;
default = "swarm-controller";
example = "swarm-controller.svc";
description = ''
Subject the store's `swarm-controller` cert-auth role accepts. An
interface, not a label: cert auth matches on the CN, so whatever mints
the controller's leaf has to spell it the same way.
Lives here because it is a property of the **role**, which this module
writes not a credential belonging to the controller. Nothing outside
the store needs it except whatever issues that leaf.
The CA this role trusts also signs each hive's reader leaf, whose CN
is the hive's own name, so a hive named `swarm-controller` would satisfy
the role. Changing this to something outside the hive-name grammar
(`[a-z0-9-]`) rules that out at the cost of a role rename in any store
that has already run the granting unit.
'';
};
serverCaFile = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;

View file

@ -467,6 +467,37 @@ in
'';
};
baoClientCertFile = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "/var/lib/swarm-controller/bao-client.pem";
description = ''
Certificate this daemon presents to the swarm's secret store. Its
subject has to match
{option}`services.hyperhive.deploy.bao.controllerCommonName`, which is
what the store's cert-auth role matches on.
Distinct from {option}`services.hyperhive.deploy.bao.clientCertFile` on
purpose, and not an oversight: that one is **this host as a reader** and
carries the hive's name, while the controller's policy lets it create
roles for every hive. One certificate serving both would hand that power
to whatever else reads the store here.
Defaulted by `glue-controller-bao-identity.nix` where this deployment
mints its own; elsewhere the leaf is issued out of band and named here.
'';
};
baoClientKeyFile = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "/var/lib/swarm-controller/bao-client-key.pem";
description = ''
Private key for {option}`services.hyperhive.deploy.swarm-controller.baoClientCertFile`.
Both or neither a certificate with no key authenticates nothing.
'';
};
queue = {
clientSecretFile = lib.mkOption {
type = lib.types.str;