swarm-tls: narrow each gateway's services leaf to the names it fronts
Every gateway asked the store's `pki/issue/swarm-services` for the whole swarm's service set, so a private key on any gateway host could serve a valid certificate for services that host does not front and never has. `swarm.localServiceDomains` derives the per-host subset by filtering `swarm.serviceDomains` against the vhosts this host actually renders — the deploy flags those vhosts are already guarded on, read once rather than copied into a second filter. The leaf request and the coverage guard that decides whether to re-issue both read it, so they cannot disagree about which names the leaf owes. The sub-CA's name constraint and the role's `allowed_domains` stay the swarm-wide set: every host's subset is inside it, and narrowing the constraint per host would turn one signing into N.
This commit is contained in:
parent
0649673ebf
commit
ed2ec52fe5
5 changed files with 89 additions and 20 deletions
|
|
@ -299,6 +299,27 @@ in
|
|||
'';
|
||||
};
|
||||
|
||||
options.services.hyperhive.swarm.localServiceDomains = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
readOnly = true;
|
||||
internal = true;
|
||||
description = ''
|
||||
Read-only: the names in `serviceDomains` **this host actually
|
||||
fronts**, which is what its services leaf may carry. The swarm-wide
|
||||
set stays what the sub-CA is name-constrained to and what the
|
||||
store's issuing role permits; narrowing the leaf is what stops a
|
||||
private key on one gateway presenting a valid certificate for
|
||||
services that host does not serve and never has.
|
||||
|
||||
Read off the rendered `services.nginx.virtualHosts` rather than off
|
||||
the per-service deploy flags: those flags are what the vhosts are
|
||||
already guarded on, so a second reading of them is a copy that
|
||||
drifts from the thing it claims to describe. Filtering
|
||||
`serviceDomains` rather than assembling a list beside it is that
|
||||
option's own constraint, and it applies here for the same reason.
|
||||
'';
|
||||
};
|
||||
|
||||
config = {
|
||||
services.hyperhive.swarm.peerHives = lib.filterAttrs (name: _: name != cfg.hiveName) swarmCfg.hives;
|
||||
|
||||
|
|
@ -306,6 +327,10 @@ in
|
|||
lib.unique (lib.filter (d: d != null && d != "") serviceDomains')
|
||||
);
|
||||
|
||||
services.hyperhive.swarm.localServiceDomains = lib.filter (
|
||||
d: config.services.nginx.virtualHosts ? ${d}
|
||||
) swarmCfg.serviceDomains;
|
||||
|
||||
assertions = [
|
||||
{
|
||||
# An EMPTY `hives` fires this too, deliberately: since
|
||||
|
|
|
|||
Loading…
Reference in a new issue