A module names who its secret files belong to (secrets-owner)

The control plane runs as 65534 and crash-looped on permission denied the
first time its credentials were mounted as files the host wrote as root at
0600 — the env-file shape hid this because the daemon reads an env-file on
the host side. The composer now gives a module's secret files the owner the
manifest names.
This commit is contained in:
2026-09-21 10:19:00 +02:00
parent 4531f2244f
commit 69bb0fcb67
3 changed files with 55 additions and 4 deletions
+12 -4
View File
@@ -271,9 +271,9 @@ func (r Resolution) Declaration(with Rendering) ([]map[string]any, error) {
return nil, fmt.Errorf(
"%s needs a secret called %q and none was made for it", m.Module, name)
}
first = append(first, map[string]any{
first = append(first, ownedBy(m.SecretsOwner, map[string]any{
"id": NeedID(name), "type": "file", "path": m.OwnSecrets[name], "sealed": sealed,
})
}))
}
// Operator-owned paths this module is granted use of (novox/hq ADR 0051). Written before
// the module's own resources, and so before the container that mounts them: the host must
@@ -320,10 +320,10 @@ func (r Resolution) Declaration(with Rendering) ([]map[string]any, error) {
// worse than none: something would read it and fail authenticating.
continue
}
first = append(first, map[string]any{
first = append(first, ownedBy(m.SecretsOwner, map[string]any{
"id": SecretID(to), "type": "file", "path": m.Secrets[to],
"sealed": found.Sealed,
})
}))
}
for _, to := range sortedKeys(m.Grants) {
for _, g := range with.Grants {
@@ -799,6 +799,14 @@ func keptFile(dir string, kept *KeptExport) (map[string]any, error) {
}, nil
}
// ownedBy gives a secret file the owner the module named, when it named one (Manifest.SecretsOwner).
func ownedBy(owner string, file map[string]any) map[string]any {
if owner != "" {
file["owner"] = owner
}
return file
}
// sortedKeys is map iteration made repeatable, which everything written to a machine needs.
func sortedKeys[V any](m map[string]V) []string {
out := make([]string, 0, len(m))