nixos/spire: make Workload API socket reachable by non-root workloads (#516497)

This commit is contained in:
Arian van Putten
2026-05-04 15:34:00 +00:00
committed by GitHub
2 changed files with 25 additions and 6 deletions
@@ -150,7 +150,7 @@ in
Restart = "on-failure";
StateDirectory = "spire/agent";
StateDirectoryMode = "0700";
RuntimeDirectory = "spire/agent";
RuntimeDirectory = "spire/agent/public";
# TODO: Switch to DynamicUser once https://github.com/NixOS/nixpkgs/issues/299476 lands
# Without it, the systemd plugin can not talk to dbus
+24 -5
View File
@@ -45,6 +45,14 @@ let
config.services.spire.agent.settings.agent.socket_path;
virtualisation.credentials."spire.trust_bundle".source = "./trust_bundle";
systemd.services.spire-agent.serviceConfig.ImportCredential = [ "spire.trust_bundle" ];
# A non-root, non-spire-agent user used to verify that arbitrary
# workloads can reach the Workload API socket.
users.users.workload = {
isNormalUser = true;
group = "workload";
};
users.groups.workload = { };
};
in
{
@@ -180,25 +188,36 @@ in
join_token = server.succeed("spire-server token generate -socketPath ${adminSocket}").split()[1]
with open(agent.state_dir / "join_token", "w") as f:
f.write(join_token)
parent_id = f"spiffe://${trustDomain}/spire/agent/join_token/{join_token}"
server.succeed(f"spire-server entry create -socketPath ${adminSocket} -selector 'systemd:id:backdoor.service' -parentID {parent_id} -spiffeID {spiffe_id}")
return f"spiffe://${trustDomain}/spire/agent/join_token/{join_token}"
def provision_tpm(agent):
agent.wait_for_unit("tpm2.target")
ek_hash = agent.succeed("get_tpm_pubhash").strip()
parent_id = f"spiffe://${trustDomain}/spire/agent/tpm/{ek_hash}"
server.succeed(f"spire-server entry create -socketPath ${adminSocket} -selector 'systemd:id:backdoor.service' -parentID '{parent_id}' -spiffeID {spiffe_id}")
return f"spiffe://${trustDomain}/spire/agent/tpm/{ek_hash}"
def register_entry(parent_id, selector, spiffe_id):
server.succeed(f"spire-server entry create -socketPath ${adminSocket} -selector '{selector}' -parentID '{parent_id}' -spiffeID '{spiffe_id}'")
def test_agent(name, agent_node, provision_fn):
with subtest(f"Setup SPIRE agent with {name} attestation"):
provision_trust_bundle(agent_node)
provision_fn(agent_node)
parent_id = provision_fn(agent_node)
register_entry(parent_id, "systemd:id:backdoor.service", spiffe_id)
register_entry(parent_id, "unix:user:workload", "spiffe://${trustDomain}/workload")
agent_node.wait_for_unit("spire-agent.service")
agent_node.wait_until_succeeds("spire-agent healthcheck -socketPath $SPIFFE_ENDPOINT_SOCKET", timeout=90)
with subtest(f"Test certificate authentication from {name} agent"):
agent_node.wait_until_succeeds("spire-agent api fetch x509 -socketPath $SPIFFE_ENDPOINT_SOCKET -write .")
with subtest(f"Workload running as non-root, non-spire-agent user can reach Workload API ({name})"):
# SPIRE's security model relies on workload attestation, not unix
# permissions on the socket. Verify an unrelated user can connect.
agent_node.wait_until_succeeds(
"su -s /bin/sh workload -c "
"'spire-agent api fetch x509 -socketPath \"$SPIFFE_ENDPOINT_SOCKET\"'"
)
# TODO: Add something to communicate with