mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-13 16:14:01 +09:00
Every engine in the catalog issues a per-release CA, but the object that holds ca.crt almost always holds a private key next to it, so any RBAC path that hands a tenant the trust anchor hands over key material too. Add a controller that publishes, for each application release, a canonical Opaque Secret <release>.tenant-ca holding only ca.crt. That name is claimed by none of the operators the platform ships, which matters: <release>-ca-cert, the obvious candidate, is already taken and means opposite things across engines — a key-free CA on one, a key-BEARING Secret on another — so projecting onto it could only be done by overwriting live key material. The certificate is found two ways. A Secret labelled internal.cozystack.io/publish-ca-cert is how a chart opts in, and it is watched, so a rotation propagates at once. For the engines whose operator owns the CA Secret and will not label it, the application's caCert declaration names that Secret, which is read by name and re-read on a resync. The two legs differ only in how the source is found — extraction, sanitization, ownership and collision handling are one shared write path, because forking it is where a key-leak bug would hide. Exactly one whitelisted key is ever copied, and every byte written is re-checked for a PEM private-key header first: on the name-driven leg the source is key-bearing by construction. The projection is owner-referenced to the release, so deleting the application collects it with no prune logic, and a Secret the controller did not create is never overwritten — a Secret carrying key material on the canonical name is refused with a Warning Event rather than adopted. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>