feat(swarm): ship host_uuid + swarmctl-port in agent enroll bundle

The rendered /etc/decnet/decnet.ini now carries host-uuid and
swarmctl-port in [agent], which config_ini seeds into DECNET_HOST_UUID
and DECNET_SWARMCTL_PORT. Gives the worker a stable self-identity for
the heartbeat loop — the INI never has to be rewritten because cert
pinning is the real gate (a rotated UUID with a matching CA-signed
cert would still be blocked by SHA-256 fingerprint mismatch against
the stored SwarmHost row).

Also adds DECNET_MASTER_HOST so the agent can find the swarmctl URL
via the INI's existing master-host key.
This commit is contained in:
2026-04-19 21:44:23 -04:00
parent 148e51011c
commit e411063075
2 changed files with 22 additions and 3 deletions

View File

@@ -187,7 +187,12 @@ def _is_excluded(rel: str) -> bool:
return False
def _render_decnet_ini(master_host: str, use_ipvlan: bool = False) -> bytes:
def _render_decnet_ini(
master_host: str,
host_uuid: str,
use_ipvlan: bool = False,
swarmctl_port: int = 8770,
) -> bytes:
ipvlan_line = f"ipvlan = {'true' if use_ipvlan else 'false'}\n"
return (
"; Generated by DECNET agent-enrollment bundle.\n"
@@ -199,10 +204,12 @@ def _render_decnet_ini(master_host: str, use_ipvlan: bool = False) -> bytes:
"\n"
"[agent]\n"
f"master-host = {master_host}\n"
f"swarmctl-port = {swarmctl_port}\n"
"swarm-syslog-port = 6514\n"
"agent-port = 8765\n"
"agent-dir = /etc/decnet/agent\n"
"updater-dir = /etc/decnet/updater\n"
f"host-uuid = {host_uuid}\n"
).encode()
@@ -217,6 +224,7 @@ def _add_bytes(tar: tarfile.TarFile, name: str, data: bytes, mode: int = 0o644)
def _build_tarball(
master_host: str,
agent_name: str,
host_uuid: str,
issued: pki.IssuedCert,
services_ini: Optional[str],
updater_issued: Optional[pki.IssuedCert] = None,
@@ -240,7 +248,11 @@ def _build_tarball(
continue
tar.add(path, arcname=rel, recursive=False)
_add_bytes(tar, "etc/decnet/decnet.ini", _render_decnet_ini(master_host, use_ipvlan))
_add_bytes(
tar,
"etc/decnet/decnet.ini",
_render_decnet_ini(master_host, host_uuid, use_ipvlan),
)
for unit in _SYSTEMD_UNITS:
_add_bytes(
tar,
@@ -365,7 +377,7 @@ async def create_enroll_bundle(
# 3. Render payload + bootstrap.
tarball = _build_tarball(
req.master_host, req.agent_name, issued, req.services_ini, updater_issued,
req.master_host, req.agent_name, host_uuid, issued, req.services_ini, updater_issued,
use_ipvlan=req.use_ipvlan,
)
token = secrets.token_urlsafe(24)