module-eval: the seal, the store's identity, and the reader pairing
The seal choice gates the TPM machinery, in both directions. The store's three certificate paths are a function of the glue: present when the store is deployed, and an operator's own path beats the mkDefault. The absence arm this replaces asserted the store defaults NO path -- true while nothing supplied one, false the moment something did. The reader unit is a function of the PAIRING: present with store and homeserver together, absent with the store alone. That pair is what makes it glue rather than a feature of either side, and it is the case that fails if a later change wires the reader to one of them.
This commit is contained in:
parent
0e5eb1e8d6
commit
aa784a746d
1 changed files with 71 additions and 0 deletions
|
|
@ -71,6 +71,26 @@ let
|
||||||
bare = hive { };
|
bare = hive { };
|
||||||
withCi = hive { deploy.forgejo.ci.enable = true; };
|
withCi = hive { deploy.forgejo.ci.enable = true; };
|
||||||
|
|
||||||
|
baoPkcs11 = hive {
|
||||||
|
deploy.bao.enable = true;
|
||||||
|
deploy.bao.seal = "pkcs11";
|
||||||
|
};
|
||||||
|
baoShamir = hive {
|
||||||
|
deploy.bao.enable = true;
|
||||||
|
deploy.bao.seal = "shamir";
|
||||||
|
};
|
||||||
|
baoExplicitCerts = hive {
|
||||||
|
deploy.bao.enable = true;
|
||||||
|
deploy.bao.serverCertFile = "/etc/pki/bao.pem";
|
||||||
|
deploy.bao.serverKeyFile = "/etc/pki/bao-key.pem";
|
||||||
|
};
|
||||||
|
# The store and a service that reads from it, versus the store alone. The
|
||||||
|
# pair is what makes the reader's absence arm mean anything.
|
||||||
|
baoWithMatrix = hive {
|
||||||
|
deploy.bao.enable = true;
|
||||||
|
deploy.matrix.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
# A priority collision is a property of the *option*, not
|
# A priority collision is a property of the *option*, not
|
||||||
# of the merged value's interior — nix throws the moment the value is
|
# of the merged value's interior — nix throws the moment the value is
|
||||||
# demanded at all, so `seq`-ing each `serviceConfig` value to WHNF is
|
# demanded at all, so `seq`-ing each `serviceConfig` value to WHNF is
|
||||||
|
|
@ -134,6 +154,57 @@ let
|
||||||
name = "the CI container's unit definitions merge without a priority collision";
|
name = "the CI container's unit definitions merge without a priority collision";
|
||||||
ok = forceCiServiceConfigs;
|
ok = forceCiServiceConfigs;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
# The store's seal is spread over five gates — the stanza, the
|
||||||
|
# provisioning unit, a bind mount, a device and an EnvironmentFile.
|
||||||
|
# Rendering only some of them is the dangerous state: a store that
|
||||||
|
# says hardware-backed and seals with a software key, which no
|
||||||
|
# assertion can catch because every value is individually valid.
|
||||||
|
name = "a shamir store renders no TPM provisioning unit";
|
||||||
|
ok = !(baoShamir.systemd.services ? swarm-bao-token);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# Presence control for the case above. Without it, a typo in the
|
||||||
|
# option name would satisfy the absence arm forever.
|
||||||
|
name = "a pkcs11 store renders the TPM provisioning unit";
|
||||||
|
ok = baoPkcs11.systemd.services ? swarm-bao-token;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# The store's mTLS identity is a separate trust domain from both CAs in
|
||||||
|
# this tree, because it must not come from an authority the store will
|
||||||
|
# itself distribute. What supplies it is the glue, which mints a CA of
|
||||||
|
# the store's own — so an enabled store has all three paths, and if this
|
||||||
|
# ever reads null again the store stops coming up on its own.
|
||||||
|
name = "a deployed store is given its own certificate, key and client CA";
|
||||||
|
ok =
|
||||||
|
let
|
||||||
|
b = baoPkcs11.services.hyperhive.deploy.bao;
|
||||||
|
in
|
||||||
|
b.serverCertFile != null && b.serverKeyFile != null && b.clientCaFile != null;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# Everything the glue sets is `mkDefault`, and this is the case that
|
||||||
|
# says so: a deployment whose certificates come from somewhere the glue
|
||||||
|
# has never heard of must win. Also the presence control for the case
|
||||||
|
# above — a renamed option would read `null` on both and satisfy
|
||||||
|
# neither, but only this one names a value.
|
||||||
|
name = "an operator's own certificate path beats the glue's default";
|
||||||
|
ok = baoExplicitCerts.services.hyperhive.deploy.bao.serverCertFile == "/etc/pki/bao.pem";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# The store's first reader. Its unit belongs to the pairing, not to
|
||||||
|
# either service: matrix must not learn the store exists, and the store
|
||||||
|
# must not know who reads it.
|
||||||
|
name = "a store deployed beside the homeserver fetches its registration token";
|
||||||
|
ok = baoWithMatrix.systemd.services ? swarm-bao-matrix-token;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
# Absence arm. A store with nothing to serve renders no reader, so the
|
||||||
|
# unit is a function of the PAIRING rather than of the store — which is
|
||||||
|
# the property that makes it glue instead of a feature of either side.
|
||||||
|
name = "a store with no homeserver beside it renders no token reader";
|
||||||
|
ok = !(baoPkcs11.systemd.services ? swarm-bao-matrix-token);
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
bad = builtins.filter (c: !c.ok) cases;
|
bad = builtins.filter (c: !c.ok) cases;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue