96 lines
3.5 KiB
Nix
96 lines
3.5 KiB
Nix
# Removal shim for the CAs a host held outside the secret store: the
|
|
# swarm root under `/var/lib/swarm-ca` (and its `services.hyperhive.swarm.ca.*`
|
|
# options), and a hive CA's `ca.pem`, `ca-previous.pem`, `ca-key.pem`,
|
|
# `ca.srl` and `.swarm-ca-adopted` in `deploy.hive-controller.tls.stateDir`.
|
|
#
|
|
# The secret store's `pki` root is the only trust anchor: it issues every
|
|
# hive's gateway leaf and the swarm's service names, and its key never leaves
|
|
# the store. Nothing generates, reads or bundles either CA, so a definition of
|
|
# a removed option fails evaluation with a message, a CA-file option naming
|
|
# one of the deleted paths fails it too, and every host deletes the files.
|
|
#
|
|
# Self-contained and deletable: one file to
|
|
# remove when the deprecation window closes.
|
|
{ lib, config, ... }:
|
|
let
|
|
deployCfg = config.services.hyperhive.deploy;
|
|
|
|
swarmCaDir = "/var/lib/swarm-ca";
|
|
hiveCaFiles = map (f: "${deployCfg.hive-controller.tls.stateDir}/${f}") [
|
|
"ca.pem"
|
|
"ca-previous.pem"
|
|
"ca-key.pem"
|
|
];
|
|
# Lexical only: empty and `.` components drop out and `..` removes the
|
|
# one before it. A symlink is not resolved, so a path reaching a deleted
|
|
# file through one passes the check below.
|
|
normalise =
|
|
p:
|
|
lib.optionalString (lib.hasPrefix "/" p) "/"
|
|
+ lib.concatStringsSep "/" (
|
|
lib.foldl' (
|
|
kept: c:
|
|
if c == "" || c == "." then
|
|
kept
|
|
else if c == ".." then
|
|
(if kept == [ ] then [ ] else lib.init kept)
|
|
else
|
|
kept ++ [ c ]
|
|
) [ ] (lib.splitString "/" p)
|
|
);
|
|
deleted =
|
|
p:
|
|
let
|
|
n = normalise p;
|
|
in
|
|
n == swarmCaDir || lib.hasPrefix "${swarmCaDir}/" n || lib.elem n (map normalise hiveCaFiles);
|
|
# The hive CA's serial file and its adoption marker: neither is a CA, so
|
|
# no CA-file option can name them, and nothing reads them.
|
|
hiveCaLeftovers = map (f: "${deployCfg.hive-controller.tls.stateDir}/${f}") [
|
|
"ca.srl"
|
|
".swarm-ca-adopted"
|
|
];
|
|
|
|
# Every option that names a CA the store's mTLS checks against. One
|
|
# pointing at a deleted file fails the unit that reads it at start.
|
|
caFileOptions = {
|
|
"services.hyperhive.deploy.bao.clientCaFile" = deployCfg.bao.clientCaFile;
|
|
"services.hyperhive.deploy.bao.serverCaFile" = deployCfg.bao.serverCaFile;
|
|
"services.hyperhive.deploy.swarm-controller.hiveClientCaFile" =
|
|
deployCfg.swarm-controller.hiveClientCaFile;
|
|
};
|
|
|
|
removed =
|
|
name:
|
|
lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "ca" name ] ''
|
|
The host-held swarm root CA is gone: the secret store's pki root is the
|
|
only trust anchor, and nothing generates or reads a root under
|
|
${swarmCaDir}. Remove this definition. See docs/swarm/ca.md.
|
|
'';
|
|
in
|
|
{
|
|
imports = map removed [
|
|
"autoConfigure"
|
|
"stateDir"
|
|
"validityDays"
|
|
];
|
|
|
|
assertions = lib.mapAttrsToList (option: path: {
|
|
assertion = path == null || !(deleted path);
|
|
message = ''
|
|
${option} is ${toString path}, a file every host deletes along with
|
|
the host-held CA it belonged to. Point it at the store's mTLS CA:
|
|
/var/lib/swarm-bao-pki/ca.pem on the host that runs the store, the copy
|
|
placed by hand on any other host. See docs/swarm/ca.md.
|
|
'';
|
|
}) caFileOptions;
|
|
|
|
# Both CAs' private keys are secrets outside the store, and the
|
|
# certificates beside them are anchors nothing issues under. The swarm
|
|
# root at the option's old default path only: a relocated `stateDir` is
|
|
# the operator's to delete.
|
|
systemd.tmpfiles.rules = [
|
|
"R ${swarmCaDir}"
|
|
]
|
|
++ map (f: "r ${f}") (hiveCaFiles ++ hiveCaLeftovers);
|
|
}
|