swarm-authelia: run the secret publisher and a journal forwarder inside the container
swarm-secret-publish and its path unit now run inside authelia's container, beside the mint, and read each client secret at the path authelia writes it. The host unit and host path unit, which read the secrets through the container's root on the host, are gone, and so is deploy.authelia.hostClientSecretDir, which only they read. The publisher keeps its store identity, the secret-publisher leaf. The host hands the leaf and the store's CA into the container as nspawn system credentials, and the unit loads them; where this host mints the leaf, the container waits for swarm-bao-pki. Authelia does not wait for the publisher, which retries every 30 seconds while the store is down. The container also runs the journal forwarder the other service containers run, pushing to a receiver of its own on the swarm collector (serviceProducers swarm-authelia) as a new machine OIDC client (swarm.authelia.otel.clientId) that authelia registers for itself and the publisher carries to the store. The fetch unit reads it back under the publisher's leaf, also handed to it as a system credential, so the swarm-secret-publisher policy gains read on that one leaf; its stanza keeps create and update, which the exact path would otherwise take from the services/* prefix. Without the leaf the forwarder is off. The container drops --link-journal=host, and the host collector stops reading it. The services' "nothing at <path>" errors name the publisher in authelia's container.
This commit is contained in:
parent
a2dca32bb8
commit
b68a8ef290
36 changed files with 753 additions and 363 deletions
|
|
@ -414,10 +414,13 @@ let
|
|||
# The whole point of a second principal. The two prefixes and one leaf it
|
||||
# publishes to and not `swarm/`, so it cannot touch an agent's
|
||||
# credentials or the appservice token beside the controller's client;
|
||||
# and no `read`, so a unit whose job is copying a file cannot recover
|
||||
# what is already there. Pinned as the full capability list per path,
|
||||
# because an added capability is exactly what a presence check misses.
|
||||
name = "the publisher's grant is write-only and reaches the hive and service prefixes and the controller's client alone";
|
||||
# and `read` on one leaf alone, the client secret of the journal forwarder
|
||||
# that shares its identity in authelia's container, so a unit whose job
|
||||
# is copying a file cannot recover what is already there. Pinned as the
|
||||
# full capability list per path, because an added capability is exactly
|
||||
# what a presence check misses. The one `read` is found at that leaf and
|
||||
# counted once, so a read on any other path fails the count.
|
||||
name = "the publisher's grant writes the hive and service prefixes and the controller's client, and reads its forwarder's client alone";
|
||||
ok =
|
||||
let
|
||||
s = baoGrantHere.systemd.services.swarm-bao-secret-publisher-policy.script;
|
||||
|
|
@ -429,7 +432,10 @@ let
|
|||
&& !(lib.hasInfix "appservice-token" s)
|
||||
&& !(lib.hasInfix "secret/data/swarm/agents" s)
|
||||
&& !(lib.hasInfix "secret/data/swarm/*" s)
|
||||
&& !(lib.hasInfix "sys/policies/acl" s);
|
||||
&& !(lib.hasInfix "sys/policies/acl" s)
|
||||
&& lib.hasInfix "path \"secret/data/swarm/services/swarm-authelia-collector/oidc/client\" {\n capabilities = [\"create\", \"update\", \"read\"]\n}" s
|
||||
&& lib.length (lib.splitString "\"read\"" s) == 2
|
||||
&& !(lib.hasInfix "\"list\"" s);
|
||||
}
|
||||
{
|
||||
# The publisher's `services/*` write covers the callout xkey's seed, and
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ let
|
|||
c != null
|
||||
&& c.kind == "machine"
|
||||
&& lib.hasInfix "secret/swarm/services/swarm-builder/oidc/client" (
|
||||
autheliaHere.systemd.services.swarm-secret-publish.script
|
||||
autheliaHere.containers.swarm-authelia.config.systemd.services.swarm-secret-publish.script
|
||||
);
|
||||
}
|
||||
];
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ let
|
|||
ok =
|
||||
let
|
||||
fetch = builtins.unsafeDiscardStringContext (hiveOtelFetch hiveOtelAllLocal).script;
|
||||
publish = builtins.unsafeDiscardStringContext hiveOtelAllLocal.systemd.services.swarm-secret-publish.script;
|
||||
publish = builtins.unsafeDiscardStringContext hiveOtelAllLocal.containers.swarm-authelia.config.systemd.services.swarm-secret-publish.script;
|
||||
path = "secret/swarm/hives/h1/oidc/client";
|
||||
in
|
||||
lib.hasInfix "bao kv get -field=value ${path}" fetch && lib.hasInfix "bao kv put ${path} " publish;
|
||||
|
|
|
|||
|
|
@ -25,18 +25,13 @@ let
|
|||
# No store identity, which the first case below relies on.
|
||||
natsQueueOnly = shared.natsQueueOnly;
|
||||
|
||||
# The IdP and the queue on one host. A reader of authelia's host paths has to
|
||||
# follow the `deploy` namespace; seven of those reads go through an alias a
|
||||
# path-shaped grep cannot see.
|
||||
# The IdP and the queue on one host.
|
||||
autheliaAndNats = hive {
|
||||
deploy.authelia.enable = true;
|
||||
deploy.nats.enable = true;
|
||||
deploy.authelia.usersFile = "/var/lib/test-authelia/users.yml";
|
||||
deploy.authelia.package = pkgs.emptyDirectory;
|
||||
deploy.authelia.bridgePackage = pkgs.emptyDirectory;
|
||||
# Renders the publisher, which reads the host client-secret dir.
|
||||
deploy.swarm-secret-publisher.baoClientCertFile = "/etc/pki/publisher.pem";
|
||||
deploy.swarm-secret-publisher.baoClientKeyFile = "/etc/pki/publisher-key.pem";
|
||||
};
|
||||
|
||||
# The queue with a store identity for its responder, placed by hand: the
|
||||
|
|
@ -671,16 +666,6 @@ let
|
|||
&& lib.hasInfix "[ -s /var/lib/swarm-bao-pki/nats-auth.pem ] ||" mint
|
||||
&& lib.hasInfix "/var/lib/swarm-bao-pki nats-auth " mint;
|
||||
}
|
||||
{
|
||||
# Not a rename test. `hostClientSecretDir` is `readOnly`, so the fixture
|
||||
# cannot define it; what can break is a reader left pointing at
|
||||
# `swarm.authelia` instead of `deploy.authelia`. Several modules read this
|
||||
# through an `autheliaCfg` alias, where a path-shaped grep does not see it.
|
||||
name = "a consumer of authelia's host client-secret dir renders it from the deploy namespace";
|
||||
ok =
|
||||
autheliaAndNats.systemd.paths.swarm-secret-publish.pathConfig.PathChanged
|
||||
== "/var/lib/nixos-containers/swarm-authelia/var/lib/authelia-swarm/oidc-clients";
|
||||
}
|
||||
{
|
||||
# authelia exits at startup on `users: {}`, so an empty database, and a
|
||||
# file holding exactly that document, must be replaced by the disabled
|
||||
|
|
@ -1017,6 +1002,58 @@ let
|
|||
&& lib.elem "-/run/swarm-victoriametrics-egress" h.systemd.services.nginx.serviceConfig.ReadWritePaths
|
||||
&& lib.hasInfix "rm -f ${sock}" h.systemd.services.nginx.preStart;
|
||||
}
|
||||
{
|
||||
# Authelia's forwarder reads its secret from the store under the
|
||||
# publisher's identity, handed in for both units. The IdP host with no
|
||||
# identity is the control: the forwarder is off there, and on the
|
||||
# services host it is on, so the lookup is the right one.
|
||||
name = "the authelia container forwards its journal to its own route under the publisher's identity";
|
||||
ok =
|
||||
let
|
||||
h = servicesHost;
|
||||
container = h.containers.swarm-authelia;
|
||||
c = container.config;
|
||||
s = c.services.opentelemetry-collector.settings;
|
||||
otel = h.services.hyperhive.swarm.otel;
|
||||
clientId = h.services.hyperhive.swarm.authelia.otel.clientId;
|
||||
fetch = c.systemd.services.swarm-journal-forwarder-oidc;
|
||||
dir = forwarderFetchDir;
|
||||
registered = lib.findFirst (
|
||||
x: x.id == clientId
|
||||
) null h.services.hyperhive.swarm.authelia.oidc.clients;
|
||||
reader = lib.head s.service.telemetry.metrics.readers;
|
||||
taken = [
|
||||
8888
|
||||
8889
|
||||
8890
|
||||
h.services.hyperhive.swarm.nats.otel.telemetryPort
|
||||
]
|
||||
++ map (o: o.port) hostNetnsForwarders;
|
||||
in
|
||||
c.services.opentelemetry-collector.enable
|
||||
&& s.exporters.otlphttp.endpoint == "https://${otel.domain}/swarm-authelia"
|
||||
&& s.extensions."oauth2client/swarm".client_id == clientId
|
||||
&& s.extensions."oauth2client/swarm".endpoint_params.audience == clientId
|
||||
&& otel.serviceProducers.swarm-authelia.clientId == clientId
|
||||
&&
|
||||
(lib.findFirst (a: a.key == "service.name") null s.processors.resource.attributes).value
|
||||
== "authelia"
|
||||
&& fetch.environment.BAO_CLIENT_CERT == "${dir}/publisher-bao-cert"
|
||||
&& fetch.environment.BAO_CLIENT_KEY == "${dir}/publisher-bao-key"
|
||||
&& lib.elem "publisher-bao-cert" fetch.serviceConfig.LoadCredential
|
||||
&& lib.elem "publisher-bao-key" fetch.serviceConfig.LoadCredential
|
||||
&& lib.hasInfix "bao kv get -field=value secret/swarm/services/${clientId}/oidc/client" fetch.script
|
||||
&& registered.kind == "machine"
|
||||
&& registered.audience == [ clientId ]
|
||||
&& !(lib.elem "--link-journal=host" container.extraFlags)
|
||||
&& lib.any (lib.hasPrefix "--load-credential=publisher-bao-cert:") container.extraFlags
|
||||
&& reader.pull.exporter.prometheus.host == "127.0.0.1"
|
||||
&& !(lib.elem reader.pull.exporter.prometheus.port taken)
|
||||
&& !autheliaColocated.containers.swarm-authelia.config.services.opentelemetry-collector.enable
|
||||
&& !(
|
||||
autheliaColocated.containers.swarm-authelia.config.systemd.services ? swarm-journal-forwarder-oidc
|
||||
);
|
||||
}
|
||||
]
|
||||
++ forwarderCases
|
||||
++ hostNetnsForwarderCases;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,9 @@ let
|
|||
# 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.
|
||||
inherit (shared) baoWithMatrix;
|
||||
|
||||
# The publisher runs inside authelia's container.
|
||||
inAuthelia = m: m.containers.${m.services.hyperhive.swarm.authelia.machine}.config;
|
||||
cases = [
|
||||
{
|
||||
# Each hive's hive-c0re reads this exact path
|
||||
|
|
@ -81,7 +84,7 @@ let
|
|||
name = "the publisher writes every hive's own client under that hive's prefix";
|
||||
ok =
|
||||
let
|
||||
s = secretPublisherHere.systemd.services.swarm-secret-publish.script;
|
||||
s = (inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script;
|
||||
in
|
||||
lib.all
|
||||
(h: lib.hasInfix "secret/swarm/hives/${h}/oidc/client" s && lib.hasInfix "/hive-${h}.secret" s)
|
||||
|
|
@ -99,7 +102,7 @@ let
|
|||
name = "the publisher writes the controller's client under controller/, never services/";
|
||||
ok =
|
||||
let
|
||||
s = secretPublisherHere.systemd.services.swarm-secret-publish.script;
|
||||
s = (inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script;
|
||||
in
|
||||
lib.hasInfix "secret/swarm/controller/swarm-controller/oidc/client" s
|
||||
&& lib.hasInfix "/swarm-controller.secret" s
|
||||
|
|
@ -107,12 +110,12 @@ let
|
|||
}
|
||||
{
|
||||
# Both ends of a wire nothing at eval time carries end to end: the
|
||||
# publisher on authelia's host writes the path the reader on Grafana's host
|
||||
# reads, and the two files agree only because both compose it from the same
|
||||
# swarm-wide client id.
|
||||
# publisher in authelia's container writes the path the reader on
|
||||
# Grafana's host reads, and the two files agree only because both compose
|
||||
# it from the same swarm-wide client id.
|
||||
name = "the publisher writes the swarm service path grafana reads";
|
||||
ok = lib.hasInfix "secret/swarm/services/swarm-grafana/oidc/client" (
|
||||
secretPublisherHere.systemd.services.swarm-secret-publish.script
|
||||
(inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script
|
||||
);
|
||||
}
|
||||
{
|
||||
|
|
@ -184,7 +187,7 @@ let
|
|||
name = "the publisher on an authelia host carries the queue's, homeserver's and forge's secrets";
|
||||
ok =
|
||||
let
|
||||
s = secretPublisherRemote.systemd.services.swarm-secret-publish.script;
|
||||
s = (inAuthelia secretPublisherRemote).systemd.services.swarm-secret-publish.script;
|
||||
in
|
||||
lib.hasInfix "secret/swarm/services/swarm-nats/oidc/client" s
|
||||
&& lib.hasInfix "/swarm-nats.secret" s
|
||||
|
|
@ -196,13 +199,13 @@ let
|
|||
}
|
||||
{
|
||||
# Both ends of a wire nothing at eval time carries end to end: the
|
||||
# publisher on authelia's host writes the path the reader on the
|
||||
# publisher in authelia's container writes the path the reader on the
|
||||
# collector's host reads, and the two files agree only because both
|
||||
# compose it from the same swarm-wide client id. `secretPublisherHere`
|
||||
# already grew this client when `serviceClientIds` did.
|
||||
name = "the publisher writes the swarm service path the collector reads";
|
||||
ok = lib.hasInfix "secret/swarm/services/swarm-collector/oidc/client" (
|
||||
secretPublisherHere.systemd.services.swarm-secret-publish.script
|
||||
(inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script
|
||||
);
|
||||
}
|
||||
{
|
||||
|
|
@ -213,20 +216,20 @@ let
|
|||
# store's host waits forever on a path nothing writes.
|
||||
name = "the publisher carries the store forwarder's secret too";
|
||||
ok = lib.hasInfix "secret/swarm/services/swarm-bao-collector/oidc/client" (
|
||||
secretPublisherHere.systemd.services.swarm-secret-publish.script
|
||||
(inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script
|
||||
);
|
||||
}
|
||||
{
|
||||
# The forwarders in the CI runner's, Grafana's, the log store's, the
|
||||
# forge's and the homeserver's containers read their secrets from these
|
||||
# paths, and the metrics store's host reads its container's.
|
||||
name = "the publisher carries the CI runner, Grafana, log store, forge, homeserver and metrics store forwarders' secrets";
|
||||
# forge's, the homeserver's and authelia's containers read their secrets
|
||||
# from these paths, and the metrics store's host reads its container's.
|
||||
name = "the publisher carries the CI runner, Grafana, log store, forge, homeserver, metrics store and authelia forwarders' secrets";
|
||||
ok =
|
||||
lib.all
|
||||
(
|
||||
id:
|
||||
lib.hasInfix "secret/swarm/services/${id}/oidc/client" (
|
||||
secretPublisherHere.systemd.services.swarm-secret-publish.script
|
||||
(inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script
|
||||
)
|
||||
)
|
||||
[
|
||||
|
|
@ -236,6 +239,7 @@ let
|
|||
"swarm-forge-collector"
|
||||
"swarm-matrix-collector"
|
||||
"swarm-victoriametrics-collector"
|
||||
"swarm-authelia-collector"
|
||||
];
|
||||
}
|
||||
{
|
||||
|
|
@ -251,7 +255,7 @@ let
|
|||
c != null
|
||||
&& c.kind == "machine"
|
||||
&& lib.hasInfix "secret/swarm/services/swarm-review-classifier/oidc/client" (
|
||||
secretPublisherHere.systemd.services.swarm-secret-publish.script
|
||||
(inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script
|
||||
);
|
||||
}
|
||||
{
|
||||
|
|
@ -270,7 +274,7 @@ let
|
|||
&& ui.kind == "interactive"
|
||||
&& ui.redirectUris == [ "https://bao-ui.t.local/ui/vault/auth/oidc/oidc/callback" ]
|
||||
&& lib.hasInfix "secret/swarm/services/swarm-bao-ui/oidc/client" (
|
||||
secretPublisherHere.systemd.services.swarm-secret-publish.script
|
||||
(inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script
|
||||
)
|
||||
&& !(lib.any (
|
||||
c: c.id == "swarm-bao-ui"
|
||||
|
|
@ -321,7 +325,7 @@ let
|
|||
name = "the publisher hands bao the secret's path, never the secret";
|
||||
ok =
|
||||
let
|
||||
s = secretPublisherHere.systemd.services.swarm-secret-publish.script;
|
||||
s = (inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script;
|
||||
code = lib.concatStringsSep "\n" (
|
||||
lib.filter (l: builtins.match "[[:space:]]*#.*" l == null) (lib.splitString "\n" s)
|
||||
);
|
||||
|
|
@ -336,7 +340,7 @@ let
|
|||
name = "the publisher writes every hive in the roster to that hive's own queue path";
|
||||
ok =
|
||||
let
|
||||
s = secretPublisherHere.systemd.services.swarm-secret-publish.script;
|
||||
s = (inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script;
|
||||
in
|
||||
lib.hasInfix "secret/swarm/hives/h1/queue/agent" s
|
||||
&& lib.hasInfix "secret/swarm/hives/h2/queue/agent" s;
|
||||
|
|
@ -368,7 +372,7 @@ let
|
|||
&& lib.hasInfix "-token-only" c
|
||||
&& !(lib.hasInfix "bao kv" (lib.head (lib.splitString "bao login" c)));
|
||||
in
|
||||
holdsTokenFirst secretPublisherHere.systemd.services.swarm-secret-publish.script
|
||||
holdsTokenFirst (inAuthelia secretPublisherHere).systemd.services.swarm-secret-publish.script
|
||||
&& holdsTokenFirst baoWithMatrix.systemd.services.swarm-bao-queue-agent.script
|
||||
# Controls, so a clean verdict above means something. In order: a bare
|
||||
# read is refused, a read placed before the login is refused, and a
|
||||
|
|
@ -384,43 +388,132 @@ let
|
|||
# keep: a client is defined by holding a certificate the store accepts,
|
||||
# never by standing next to the store. Gating this on `deploy.bao.enable`
|
||||
# would have left the unit rendering only on the one deployment that has
|
||||
# no use for it.
|
||||
name = "a publisher holding an identity runs on a host with no store";
|
||||
# no use for it. It runs beside the mint, in authelia's container, and
|
||||
# never on the host.
|
||||
name = "a publisher holding an identity runs in authelia's container on a host with no store";
|
||||
ok =
|
||||
let
|
||||
m = secretPublisherRemote;
|
||||
c = inAuthelia m;
|
||||
in
|
||||
!m.services.hyperhive.deploy.bao.enable
|
||||
&& (m.systemd.services ? swarm-secret-publish)
|
||||
&& (m.systemd.paths ? swarm-secret-publish);
|
||||
&& (c.systemd.services ? swarm-secret-publish)
|
||||
&& (c.systemd.paths ? swarm-secret-publish)
|
||||
&& !(m.systemd.services ? swarm-secret-publish)
|
||||
&& !(m.systemd.paths ? swarm-secret-publish)
|
||||
# Control: the host's own unit set is the one read above.
|
||||
&& (m.systemd.services ? "container@swarm-authelia");
|
||||
}
|
||||
{
|
||||
# What makes the arm above able to fail. Minting the secrets is not being
|
||||
# able to publish them: with no certificate the unit would fail a TLS
|
||||
# handshake on every rotation, so it must not exist at all.
|
||||
# handshake on every rotation, so it must not exist at all, and nspawn
|
||||
# gets no credential to load.
|
||||
name = "an IdP host with no store identity renders no publisher";
|
||||
ok =
|
||||
let
|
||||
m = secretPublisherNoIdentity;
|
||||
c = inAuthelia m;
|
||||
in
|
||||
m.services.hyperhive.deploy.authelia.enable
|
||||
&& !(c.systemd.services ? swarm-secret-publish)
|
||||
&& !(c.systemd.paths ? swarm-secret-publish)
|
||||
&& !(m.systemd.services ? swarm-secret-publish)
|
||||
&& !(m.systemd.paths ? swarm-secret-publish);
|
||||
&& !(lib.any (lib.hasPrefix "--load-credential=") m.containers.swarm-authelia.extraFlags)
|
||||
# Controls: with an identity, the same lookups find both.
|
||||
&& ((inAuthelia secretPublisherHere).systemd.services ? swarm-secret-publish)
|
||||
&& lib.any (lib.hasPrefix "--load-credential=") secretPublisherHere.containers.swarm-authelia.extraFlags;
|
||||
}
|
||||
{
|
||||
# The path unit's start is a no-op while its target is `active (exited)`,
|
||||
# so a secret minted after the first run would never be published.
|
||||
# `Type` is read too, so a missing `serviceConfig` cannot pass the arm.
|
||||
name = "the publisher's path unit starts a oneshot that does not remain active";
|
||||
# The watched directory is the mint's own, inside the container.
|
||||
name = "the publisher's path unit watches the mint's directory and starts a oneshot that does not remain active";
|
||||
ok =
|
||||
let
|
||||
m = secretPublisherHere;
|
||||
sc = m.systemd.services.swarm-secret-publish.serviceConfig;
|
||||
c = inAuthelia secretPublisherHere;
|
||||
sc = c.systemd.services.swarm-secret-publish.serviceConfig;
|
||||
in
|
||||
m.systemd.paths.swarm-secret-publish.pathConfig.Unit == "swarm-secret-publish.service"
|
||||
c.systemd.paths.swarm-secret-publish.pathConfig.Unit == "swarm-secret-publish.service"
|
||||
&&
|
||||
c.systemd.paths.swarm-secret-publish.pathConfig.PathChanged
|
||||
== "/var/lib/authelia-swarm/oidc-clients"
|
||||
&& lib.hasInfix "/var/lib/authelia-swarm/oidc-clients/swarm-grafana.secret" c.systemd.services.swarm-secret-publish.script
|
||||
&& !(lib.hasInfix "/var/lib/nixos-containers" c.systemd.services.swarm-secret-publish.script)
|
||||
&& sc.Type == "oneshot"
|
||||
&& !(sc.RemainAfterExit or false);
|
||||
}
|
||||
{
|
||||
# The leaf crosses into the container as nspawn system credentials, and
|
||||
# the unit loads them and names them in its environment. On the store's
|
||||
# host the container waits for the unit that mints the leaf, since nspawn
|
||||
# refuses a missing credential source; with the leaf placed by hand,
|
||||
# those paths cross.
|
||||
name = "the publisher's store identity reaches authelia's container as system credentials";
|
||||
ok =
|
||||
let
|
||||
dir = "/run/credentials/swarm-secret-publish.service";
|
||||
unit = m: (inAuthelia m).systemd.services.swarm-secret-publish;
|
||||
flags = m: m.containers.swarm-authelia.extraFlags;
|
||||
here = unit secretPublisherHere;
|
||||
in
|
||||
lib.elem "--load-credential=publisher-bao-cert:/var/lib/swarm-bao-pki/secret-publisher.pem" (
|
||||
flags secretPublisherHere
|
||||
)
|
||||
&& lib.elem "--load-credential=publisher-bao-key:/var/lib/swarm-bao-pki/secret-publisher-key.pem" (
|
||||
flags secretPublisherHere
|
||||
)
|
||||
&& lib.elem "--load-credential=publisher-bao-server-ca:/var/lib/swarm-bao-pki/ca.pem" (
|
||||
flags secretPublisherHere
|
||||
)
|
||||
&&
|
||||
lib.sort lib.lessThan here.serviceConfig.LoadCredential == [
|
||||
"publisher-bao-cert"
|
||||
"publisher-bao-key"
|
||||
"publisher-bao-server-ca"
|
||||
]
|
||||
&& here.environment.BAO_CLIENT_CERT == "${dir}/publisher-bao-cert"
|
||||
&& here.environment.BAO_CLIENT_KEY == "${dir}/publisher-bao-key"
|
||||
&& here.environment.BAO_CACERT == "${dir}/publisher-bao-server-ca"
|
||||
&&
|
||||
lib.elem "swarm-bao-pki.service"
|
||||
secretPublisherHere.systemd.services."container@swarm-authelia".after
|
||||
&& lib.elem "--load-credential=publisher-bao-cert:/etc/pki/publisher.pem" (
|
||||
flags secretPublisherRemote
|
||||
)
|
||||
&& lib.elem "--load-credential=publisher-bao-key:/etc/pki/publisher-key.pem" (
|
||||
flags secretPublisherRemote
|
||||
)
|
||||
&& (unit secretPublisherRemote).environment.BAO_CLIENT_CERT == "${dir}/publisher-bao-cert";
|
||||
}
|
||||
{
|
||||
# Authelia is the swarm's IdP and has to come up while the store is down.
|
||||
# Nothing it starts after or needs may be the publisher, and the
|
||||
# publisher may not order itself in front of authelia.
|
||||
name = "authelia does not wait for the secret publisher";
|
||||
ok =
|
||||
let
|
||||
c = inAuthelia secretPublisherHere;
|
||||
authelia = c.systemd.services.authelia-swarm;
|
||||
publisher = c.systemd.services.swarm-secret-publish;
|
||||
unit = "swarm-secret-publish.service";
|
||||
in
|
||||
!(lib.any (l: lib.elem unit (authelia.${l} or [ ])) [
|
||||
"after"
|
||||
"requires"
|
||||
"wants"
|
||||
"bindsTo"
|
||||
"requisite"
|
||||
])
|
||||
&& !(lib.any (l: lib.elem "authelia-swarm.service" (publisher.${l} or [ ])) [
|
||||
"before"
|
||||
"requiredBy"
|
||||
])
|
||||
# Controls: both lookups find the real units.
|
||||
&& authelia.serviceConfig ? ExecStart
|
||||
&& lib.elem "authelia-swarm-secrets.service" publisher.after;
|
||||
}
|
||||
];
|
||||
in
|
||||
runGroup "secret-publisher" cases
|
||||
|
|
|
|||
Loading…
Reference in a new issue