Skip to content

docs(unified-tls-pki): fix the canonical trust-anchor name and its owner#36

Open
Aleksei Sviridkin (lexfrei) wants to merge 2 commits into
mainfrom
fix/tls-pki-canonical-name-and-ownerref
Open

docs(unified-tls-pki): fix the canonical trust-anchor name and its owner#36
Aleksei Sviridkin (lexfrei) wants to merge 2 commits into
mainfrom
fix/tls-pki-canonical-name-and-ownerref

Conversation

@lexfrei

@lexfrei Aleksei Sviridkin (lexfrei) commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Implementing the accepted design surfaced three errors and gaps in it. All are corrected here, across both proposals.

The canonical trust anchor cannot be named <release>-ca-cert. Percona PSMDB creates a Secret of exactly that name and puts a private key in it, so source and target are the same object — and mongodb is precisely the engine that most needs the projection, since its operator cannot be made to label its output at all. Strimzi separately publishes its key-free CA as <release>-clients-ca-cert, so the "one canonical name" contract did not hold for kafka either. The document had the evidence and drew the wrong conclusion from it: it states three times that <release>-ca-cert "means opposite things on redis and mongodb", uses that fact to reject selecting the source by name, and then names the target the same thing. The canonical object is now <release>-tenant-ca, which no operator this platform ships claims.

The projection cannot be owner-referenced to the application CR. The apps.cozystack.io kinds are virtual: they are served by the aggregated apiserver, and an application is stored as a HelmRelease whose spec.values is the application spec verbatim. There is no application object in etcd and therefore no UID to reference. The HelmRelease is the only real object in the chain — and it is sufficient, because deleting the application through the aggregated API deletes the HelmRelease, which garbage-collects the projection with it.

The source-selection label is not enough on its own. The platform runs cert-manager with enableCertificateOwnerRef: false, so a cert-manager-issued Secret carries no ownerReference back to its application and the lineage graph cannot resolve which release it belongs to. The consume contract therefore requires a second label, internal.cozystack.io/publish-ca-cert-release, carrying the release name, stamped alongside the opt-in label in the same secretTemplate block.

All three were found by the controller implementation, tracked in cozystack/cozystack#3286 — the first by a test that reproduced PSMDB's actual Secret shape.

Implementation surfaced two errors in the accepted design.

The canonical projection cannot be named <release>-ca-cert. Percona PSMDB
creates a Secret of exactly that name and puts a private key in it, so
source and target collide on the very engine that most needs the
projection; Strimzi publishes its key-free CA under a different name
again. The document itself warned three times that this name means
opposite things on different engines, used that to reject name-based
source selection, and then picked it for the target anyway. The canonical
object is now <release>-tenant-ca, which no shipped operator claims.

The projection also cannot be owner-referenced to the application CR. The
apps.cozystack.io kinds are virtual: an application is stored as a
HelmRelease, so there is no object in etcd to reference. The HelmRelease
is the only real owner, and deleting the application deletes it, which
garbage-collects the projection.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@lexfrei, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 120848bc-615f-4ab7-8d8a-5cf05d2a54ee

📥 Commits

Reviewing files that changed from the base of the PR and between 789654a and d137a0a.

📒 Files selected for processing (2)
  • design-proposals/external-database-exposure/README.md
  • design-proposals/unified-tls-pki/README.md
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tls-pki-canonical-name-and-ownerref

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the design proposals for external database exposure and unified TLS PKI. It renames the canonical trust-anchor Secret from <release>-ca-cert to <release>-tenant-ca to prevent naming collisions with existing operator-created Secrets (such as Percona PSMDB). Additionally, it updates the extraction controller's design to owner-reference the HelmRelease instead of the virtual application instance CR to ensure proper garbage collection. The reviewer feedback points out that the external database exposure proposal still contains outdated text claiming redis self-publishes its CA directly, whereas under the updated design, all engines (including redis and kafka) utilize the extraction controller to project their CAs to the canonical <release>-tenant-ca Secret.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

## Scope and related proposals

- **Depends on:** `design-proposals/unified-tls-pki` — provides the `<release>-ca-cert` key-free trust anchor that external clients use to verify the endpoint. This proposal does not re-specify it. It is a companion submission under the same epic, on its own branch; the path resolves once both proposals merge. The dependency is **per-engine, not blanket**: an engine is exposable here only once its `ca.crt` is actually delivered under that contract, and the path differs by engine — redis self-publishes a key-free `<release>-ca-cert` through its forked operator, while postgres and mongodb obtain theirs through the extraction controller in `unified-tls-pki`. So SNI exposure for a given engine is gated on that engine's `unified-tls-pki` convergence, not merely on the contract existing.
- **Depends on:** `design-proposals/unified-tls-pki` — provides the `<release>-tenant-ca` key-free trust anchor that external clients use to verify the endpoint. This proposal does not re-specify it. It is a companion submission under the same epic, on its own branch; the path resolves once both proposals merge. The dependency is **per-engine, not blanket**: an engine is exposable here only once its `ca.crt` is actually delivered under that contract, and the path differs by engine — redis self-publishes a key-free `<release>-ca-cert` through its forked operator, while postgres and mongodb obtain theirs through the extraction controller in `unified-tls-pki`. So SNI exposure for a given engine is gated on that engine's `unified-tls-pki` convergence, not merely on the contract existing.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The text still states that redis self-publishes a key-free <release>-ca-cert through its forked operator, while postgres and mongodb obtain theirs through the extraction controller.

However, under the updated design, redis and kafka also require the extraction controller to project their engine-specific CA Secrets to the canonical <release>-tenant-ca Secret. This sentence should be updated to reflect that all engines now utilize the extraction controller/projection mechanism to deliver the canonical trust anchor.

For example:

- **Depends on:** `design-proposals/unified-tls-pki` — provides the `<release>-tenant-ca` key-free trust anchor that external clients use to verify the endpoint. This proposal does not re-specify it. It is a companion submission under the same epic, on its own branch; the path resolves once both proposals merge. The dependency is **per-engine, not blanket**: an engine is exposable here only once its `ca.crt` is actually delivered under that contract, and the path differs by engine — while redis self-publishes a key-free `<release>-ca-cert` and postgres/mongodb have key-bearing CAs, all of them now obtain their canonical `<release>-tenant-ca` through the extraction controller in `unified-tls-pki`. So SNI exposure for a given engine is gated on that engine's `unified-tls-pki` convergence, not merely on the contract existing.

@lexfrei Aleksei Sviridkin (lexfrei) marked this pull request as ready for review July 14, 2026 16:24
Implementation showed the source-selection label is not enough on its
own. The platform runs cert-manager with enableCertificateOwnerRef set to
false, so a cert-manager-issued Secret carries no ownerReference back to
its application and the lineage graph cannot tell which release it belongs
to. The consume contract therefore requires a second label,
internal.cozystack.io/publish-ca-cert-release, carrying the release name,
stamped alongside the opt-in label in the same secretTemplate block.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <f@lex.la>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant