Repository navigation
feat(mongodb): add TLS support via PSMDB operator-managed certificates - #2692
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe MongoDB chart now configures Percona Operator-managed TLS with ChangesMongoDB TLS and Secret Handling
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
4f778b6 to
57c345d
Compare
There was a problem hiding this comment.
NOT LGTM — re-review on head 0d729e52. Two of my three prior blockers are resolved (the <release>-ca name mismatch is fixed, and the misleading toggle is gone — the latest commit drops the tri-state field entirely and makes operator-managed TLS unconditionally on, which is the honest design). One security blocker remains.
Business context: PSMDB always serves TLS once spec.secrets.ssl is set; the operator owns the cert-manager chain. This PR makes TLS unconditionally on (spec.tls.mode: preferTLS) and folds external hostnames into the leaf cert SANs via replsets[].splitHorizons (gated on PSMDB ≥ 1.22.0). There is no longer a toggle pretending to enable/disable TLS — good.
Blockers
B1: operator-managed TLS Secrets (carrying private keys) are exposed to tenant use access
Files: packages/apps/mongodb/templates/dashboard-resourcemap.yaml:21-22, packages/system/mongodb-rd/cozyrds/mongodb.yaml:40-41
Issue: both files grant tenant use subjects read on <release>-ca-cert and <release>-ssl. Both are cert-manager Certificate objects, so cert-manager writes each as a kubernetes.io/tls Secret containing tls.key: <release>-ssl is the leaf server/client private key; <release>-ca-cert is the CA private key (isCA: true).
Evidence: PSMDB issues both as Certificates; the dashboard Role grant at dashboard-resourcemap.yaml:21-22 bound to "use" (:37), and the cozyrds secrets.include at mongodb.yaml:40-41. RBAC is per-Secret and cannot scope to ca.crt alone.
Impact: any tenant principal at use can read the leaf private key (impersonate the server, MITM clients, decrypt non-PFS sessions) and the CA private key (mint any cert the cluster trusts — full TLS trust compromise). To verify a TLS connection a client needs only ca.crt, never tls.key.
Fix: remove <release>-ssl and <release>-ca-cert from both the dashboard Role and the cozyrds secrets.include; expose a ca.crt-only trust anchor instead (a private-key-stripped Secret/ConfigMap, e.g. via trust-manager). Update the dashboard-resourcemap test fixture (tests/dashboard-resourcemap_test.yaml:111-138), which currently asserts test-mongodb-ssl presence and locks in the insecure state. This is the same defect as the sibling mariadb/rabbitmq TLS PRs — a single shared fix would close it across the series.
Non-blocking follow-ups
- README documents that TLS is always on and that the secrets exist, but shows no tenant-facing CA-retrieval / verifying-connection example (
tlsCAFile/mongodb://...tls=true). Once B1 lands on aca.crt-only object, add a short retrieval + connection example. preferTLS(notrequireTLS) means plaintext is still accepted on the wire; the README flags this as a deliberate interim state pending backup-CronJob TLS support, with NetworkPolicy as the stopgap. Acceptable, but the posture is "TLS available," not "TLS enforced."mongos/sharding SAN coverage is documented as possibly incomplete and untested on-cluster. Fine to defer; flagged.
|
Parking in draft — blocked on PSMDB operator 1.22+ upgrade. After verifying against PSMDB v1.21.1 source ( The real value-add this PR was meant to deliver — external-DNS SAN injection — requires PSMDB 1.22+ for the Outstanding work before this PR can land:
All future commits will be squashed into a single feature commit when the operator bump lands. |
57c345d to
ce53e49
Compare
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request enables native TLS support for the managed MongoDB service by utilizing the PSMDB operator's built-in cert-manager integration. By upgrading the operator to version 1.22.0 and implementing a tri-state configuration for TLS, the changes allow for secure internal and external communication. The implementation ensures that external hostnames are correctly propagated to certificate SANs, improving verification for external clients while maintaining compatibility with existing backup workflows. Highlights
New Features🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Ignored Files
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces TLS support for the MongoDB application. It adds a tri-state TLS configuration option (tls.enabled) that can be explicitly enabled, disabled, or automatically resolved based on the external access setting. It updates the PerconaServerMongoDB CR to version 1.22.0, implements split-horizon DNS for external TLS, and updates the dashboard resource map, Helm values, and schemas accordingly. The review feedback points out a potential nil pointer evaluation error in the mongodb.tls.enabled template helper if .Values.tls is explicitly set to null or omitted, suggesting a defensive dictionary assignment guard.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml (1)
141-165: ⚡ Quick winAdd
-sslassertions to auto-on and override-off RBAC tests.These cases currently validate only
test-mongodb-ca-cert; they should also asserttest-mongodb-sslpresence/absence to catch partial secret RBAC regressions.Proposed test additions
- it: Role includes TLS secrets when external=true (auto-on tri-state) @@ asserts: - contains: path: rules[1].resourceNames content: test-mongodb-ca-cert documentIndex: 0 + - contains: + path: rules[1].resourceNames + content: test-mongodb-ssl + documentIndex: 0 - it: Role excludes TLS secrets when external=true but tls.enabled=false (override) @@ asserts: - notContains: path: rules[1].resourceNames content: test-mongodb-ca-cert documentIndex: 0 + - notContains: + path: rules[1].resourceNames + content: test-mongodb-ssl + documentIndex: 0🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml` around lines 141 - 165, Update the two RBAC test cases named "Role includes TLS secrets when external=true (auto-on tri-state)" and "Role excludes TLS secrets when external=true but tls.enabled=false (override)" to also assert the presence/absence of the test-mongodb-ssl secret: for the first test add a contains assertion with path rules[1].resourceNames and content test-mongodb-ssl (documentIndex: 0); for the second test add a notContains assertion with the same path/content/documentIndex to ensure both CA and SSL secrets are validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/apps/mongodb/README.md`:
- Around line 42-43: Remove the blank quoted separator line in the README
blockquote: locate the two adjacent quoted paragraphs in
packages/apps/mongodb/README.md and delete the empty line that creates an extra
">" line between them so the two quoted paragraphs form a single continuous
blockquote (no code changes, just remove the stray ">" line).
---
Nitpick comments:
In `@packages/apps/mongodb/tests/dashboard-resourcemap_test.yaml`:
- Around line 141-165: Update the two RBAC test cases named "Role includes TLS
secrets when external=true (auto-on tri-state)" and "Role excludes TLS secrets
when external=true but tls.enabled=false (override)" to also assert the
presence/absence of the test-mongodb-ssl secret: for the first test add a
contains assertion with path rules[1].resourceNames and content test-mongodb-ssl
(documentIndex: 0); for the second test add a notContains assertion with the
same path/content/documentIndex to ensure both CA and SSL secrets are validated.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 395bcf62-2f45-41a8-9a48-9e40c2122e93
📒 Files selected for processing (23)
api/apps/v1alpha1/mongodb/types.goapi/apps/v1alpha1/mongodb/zz_generated.deepcopy.gopackages/apps/mongodb/Makefilepackages/apps/mongodb/README.mdpackages/apps/mongodb/templates/_tls.tplpackages/apps/mongodb/templates/dashboard-resourcemap.yamlpackages/apps/mongodb/templates/mongodb.yamlpackages/apps/mongodb/tests/dashboard-resourcemap_test.yamlpackages/apps/mongodb/tests/mongodb_test.yamlpackages/apps/mongodb/tests/tls_test.yamlpackages/apps/mongodb/values.schema.jsonpackages/apps/mongodb/values.yamlpackages/system/mongodb-operator/charts/psmdb-operator/Chart.yamlpackages/system/mongodb-operator/charts/psmdb-operator/README.mdpackages/system/mongodb-operator/charts/psmdb-operator/crds/crd.yamlpackages/system/mongodb-operator/charts/psmdb-operator/templates/NOTES.txtpackages/system/mongodb-operator/charts/psmdb-operator/templates/_helpers.tplpackages/system/mongodb-operator/charts/psmdb-operator/templates/deployment.yamlpackages/system/mongodb-operator/charts/psmdb-operator/templates/role-binding.yamlpackages/system/mongodb-operator/charts/psmdb-operator/templates/role.yamlpackages/system/mongodb-operator/charts/psmdb-operator/values.yamlpackages/system/mongodb-rd/cozyrds/mongodb.yamlpackages/system/mongodb-rd/tests/cozyrds_test.yaml
2082b5b to
e6fe8df
Compare
Signed-off-by: Arsolitt <[email protected]> Assisted-By: Claude <[email protected]>
Signed-off-by: Arsolitt <[email protected]> Assisted-By: Claude <[email protected]>
Address review feedback from lexfrei (B3): the tri-state tls.enabled field could not actually disable TLS. The PSMDB operator defaults spec.tls to preferTLS whenever it is unset, so tls.enabled: false rendered no spec.tls while the operator still served TLS — a misleading no-op. Remove the field and unconditionally render spec.secrets.ssl and spec.tls.mode: preferTLS to match operator behaviour. splitHorizons SAN injection now keys off external alone. Also drop the Makefile jq patch that re-injected the tls schema property. Assisted-By: Claude <[email protected]> Signed-off-by: Arsolitt <[email protected]>
The tenant-facing paths handed over both Secrets the PSMDB operator creates for TLS. <release>-ca-cert holds the CA private key, so read access is a full trust-chain compromise; <release>-ssl holds the server private key, so read access allows impersonation. A client verifying the endpoint needs ca.crt and nothing else, so neither object belongs on a tenant-facing path. Declare the trust anchor by name instead. The operator creates its CA Secret itself and offers no way to label it, so the ApplicationDefinition names it and the CA-extraction controller lifts ca.crt alone into the key-free projection. The include selector matches that projection by label, and the dashboard Role drops both key-bearing names without gaining the projection by name: a name grant conveys whatever occupies the name, while the label path conveys only what the platform vouched for. Witness both delivery paths against a running cluster, since the two that matter are separate. The Role is asserted as an exact grant with bounded rule counts, because a rule with no resourceNames — or one granting every resource — would otherwise pass an absence check while conveying every Secret in the namespace. The label path is asserted as a negative on all three key-bearing Secrets. A bats check pins the declaration's names and keys, which nothing else covers: the field is pruned at admission until the controller ships, so drift there would surface as an empty trust anchor with nothing red. Drop the mongodb-rd unit test. That package has no test target, so the file never ran, and what it asserted was the leak. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
With no external hostname to advertise — zero replicas, or a tenant host the controller has not populated yet — the horizons range produced nothing and the key was emitted with a null value. The CRD types it as an object without nullable, so the API server rejected the whole PerconaServerMongoDB and the HelmRelease with it. The values schema permits zero replicas, so this was reachable. Guard on both and omit the key entirely. Pin the surrounding invariants, which were asserted in comments and enforced nowhere. The chart must render no cert-manager objects of its own, since the operator owns the chain and anything rendered here would be orphaned while looking like it participated. It must set neither of the two fields that switch TLS off at defaulting time while the rendered mode still reads preferTLS. And the external-access case now supplies a tenant host, so it isolates the flag it names rather than passing on the host guard. Correct the header comment, which fused two false claims: that setting spec.secrets.ssl is what keeps TLS on, and that it is what engages the cert-manager integration. The operator defaults that name unconditionally and runs the cert-manager path regardless. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The unit-test runner discovers charts by probing for a test target, and this chart had none — so its suites had never run in CI. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
…impact The TLS notes made several claims the operator's own behaviour contradicts. The CA is issued for a year and renewed about a month early, not for a decade with rotation disabled — so a bundle copied once stops verifying, and the retrieval steps now say to re-read it. Sharded mongos SANs are complete, because the operator emits them for every topology; the real gap is that no SAN covers the single external LoadBalancer fronting mongos, so external hostname verification is unsupported there. preferTLS is the operator's own default rather than a posture adopted to accommodate backups, which run under the same certificates. External access in replica set mode is one LoadBalancer per member with driver-side primary discovery, not a single load-balanced endpoint — the old description contradicted the external SAN note. And the posture section named only one of its two inherited weaknesses: unverified clients are accepted as well as plaintext ones. The lifecycle section was wrong in both directions. The operator owns its TLS Secrets and its cert-manager objects through the CR, so they are collected on uninstall rather than left behind. The rotation snapshots are the opposite of what was written: the operator deletes them itself once the merged CA has landed, and reads the previous CA back out of them while a rotation is in flight — so the advice to delete them by hand could destroy the only copy of the old CA. Only an interrupted rotation strands them. Document what an upgrade actually does to a release already running with external access: the new hostnames become certificate SANs, the leaf is reissued, and the replica set rolls. Gate the retrieval steps on the component that publishes the trust anchor and on cert-manager, without which the declared source does not exist and the command returns nothing. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The uninstall section promised that no manual cleanup of the TLS Secrets is needed, reversing the instruction it replaced. That promise rests on an ownerReference the operator patches on at reconcile time rather than sets at creation, and two paths skip the patch: a dry-run reconcile returns before it, and a Secret already present under the same name with a mismatched cert-manager.io/certificate-name annotation is counted toward success and returned on unpatched. The deletion finalizer does not cover the gap — it enumerates only the users, internal-<release>, internal-<release>-users and encryption-key Secrets. So a Secret predating the release at one of these names can stay unowned and survive uninstall, and for <release>-ca-cert that orphans the CA private key. State the reconcile-time mechanism and tell operators to confirm the CA Secret is gone. Pin the outcome with a chainsaw step asserting the CR owns all three TLS Secrets on a normal install, so the claim goes red if the operator stops patching instead of rotting as prose. The external-hostname note described a permanently empty _namespace.host as a bootstrap window that self-heals. A tenant with no host of its own and no ancestor supplying one resolves to an empty host for good, leaving external TLS hostname verification silently unavailable. Name that case alongside the transient one, and say why the render is not failed closed: it would break existing hostless tenants already running external access over IP. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
Every assertion in the suite passed while checking nothing. containsDocument without `any: true` asserts that EVERY rendered document matches, so negating it asks whether "not every document is a Certificate" — true of any chart rendering more than one object, and this one renders eight. A cert-manager Certificate appended to templates/mongodb.yaml, the most plausible place for one to appear, left the suite fully green. Add `any: true` to each containsDocument so the negation means "no document anywhere is of this kind". Unscoped assertions are ANDed across template files, which is what makes the negatives correct: they go red if any file renders the forbidden kind. Add a positive control asserting the chart does render the PerconaServerMongoDB CR through the same matcher shape, scoped to the one template that emits it. The four negatives are all satisfied by a matcher that never matches, which is exactly how this suite failed; the control fails if that returns. Verified by injecting a Certificate into the chart: the suite now fails and previously passed. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
…etime The external-hostname note claimed the operator and the CR version were "both shipped by this chart". Only crVersion is: the PSMDB operator is a separate platform component with its own lifecycle, and the SAN fold is gated on both. On a platform carrying an older operator nothing reports the unmet gate — the chart still renders splitHorizons, the CR is still accepted and the cluster still comes up healthy, while the external hostnames never enter the SAN list and a verifying client fails the handshake. State which half the chart owns and point at the operator version as the thing to check. The leaf certificate lifetime was stated as a flat 90 days. It is an operator default this chart deliberately does not pin: nothing in the tenant contract keys off it, the operator reissues without client action, and pinning would freeze the chart against upstream shortening it. Attribute the number to the operator version and pin the field's absence, so "inherited rather than chosen" stays falsifiable — the same treatment allowInvalidCertificates already gets. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The CA retrieval command was documented without the other half: what to do with the bundle once it is in hand. A tenant reading only the retrieval step has the certificate and no worked example of a verified connection. Pass the two TLS inputs as mongosh flags rather than folding tls=true into the connection string, because the correct separator differs by topology -- the replica-set URI already carries a ?replicaSet=rs0 query and the sharded one carries none, so a single copyable form would be wrong for one of them. Call out that omitting the flags is silent. Under preferTLS the server accepts the plaintext connection and nothing reports the downgrade, so a working connection is not evidence that TLS was negotiated. Signed-off-by: Aleksei Sviridkin <[email protected]>
… sizes The upgrade-restart note said the replica set stays available through the rollout. That holds at three members and fails below them, and the chart permits both smaller sizes: replicas 1 and 2 render unsafeFlags.replsetSize and are not excluded from the SAN change, so they gain horizons and roll on upgrade exactly as a three-member release does. At one replica the rollout takes the only mongod down; at two the write majority is still two, so restarting either member stalls writes until it returns. An operator running a single-replica external release would have read the old text and declined to book a window. Cover the two replicas case, which was untested, and assert horizons and the sub-quorum marker together at both sizes, so gating horizons to sizes that can absorb a restart turns the tests red and sends someone back to this paragraph. The default-size case carries the pair as a positive control: the marker proves nothing unless it is absent where a restart is survivable. Signed-off-by: Aleksei Sviridkin <[email protected]>
A tenant verifying a MongoDB endpoint needs the CA certificate, and every Secret that holds one also holds a private key: the operator's <release>-ca-cert carries the CA key, the leaf <release>-ssl the server key. Granting either would hand over the key along with the anchor. Render a TenantProjection naming the source, so the CA-extraction controller can publish the key-free <release>.tenant-ca, and select that projection by label from the managed-service definition. The sentinel carries no ownerReferences: it is resolved back to its release through the label Flux stamps, and an owner reference short-circuits that walk and silently costs the tenant its anchor. The sentinel is ungated. The operator issues the certificate chain whatever the chart asks for, so the source exists for every release and there is no plaintext leg to skip. The source is <release>-ssl rather than <release>-ca-cert. It is the name this chart itself sets in spec.secrets.ssl, so the reference cannot drift from the CR; the operator writes it on both its cert-manager path and the self-signed fallback it uses when cert-manager is absent, where no <release>-ca-cert exists at all; and it holds the merged old and new CA through a rotation, where <release>-ca-cert holds only the new one and would stop verifying pods still serving the previous leaf. Withhold the key-bearing Secrets from the tenant explicitly as well. The label selector matches on no name, so a single mis-stamp would promote a private key; the exclude list is evaluated first and closes the enumerable set. Signed-off-by: Aleksei Sviridkin <[email protected]>
The existing steps only assert that key-bearing Secrets are NOT promoted to the tenant, and every one of those is satisfied by an absent label — they hold just as well if nothing was ever published. Add the positive: the projection exists, carries exactly ca.crt, matches the source certificate by fingerprint, and is reachable through the tenantsecrets registry rather than only as a raw Secret. Signed-off-by: Aleksei Sviridkin <[email protected]>
The cert-manager exclusion suite justified its `any: true` requirement with a specific number of rendered documents. The argument only needs "more than one"; the number was already tied to one value set and the sentinel adds another document. Signed-off-by: Aleksei Sviridkin <[email protected]>
The README said the sentinel would sit inert with nothing else affected. The CRD is a template of the controller's own chart, so a cluster without the controller has no TenantProjection kind and the release fails to render at all. The caveat also guarded a state that cannot occur, since the controller is a mandatory platform component — drop it rather than restate it, matching the postgres chart, and keep the paragraph explaining the choice of source Secret. Enumerate all three key-bearing Secrets in the registry negative. Two of the three were listed, which leaves the third free to acquire the label and leak a key, the exact reasoning the step above it already spells out. Collect TenantProjection status on failure. The controller reports SourceNotFound and its siblings there, and without it a failed projection surfaces only as an absent Secret with no reason given. Rename the source-shape step, which no longer looks at the CA Secret, and cross-reference the two halves of the leaf Secret's name. Signed-off-by: Aleksei Sviridkin <[email protected]>
The name-clash note claimed the shared TLS helper documents <release>-ca-cert as the conventional key-free anchor. It documents the opposite: the canonical name is <release>.tenant-ca, and it names this engine as the reason, because MongoDB already claims <release>-ca-cert with a key-bearing Secret. There is no clash to warn about and the chart follows the convention rather than deviating from it. The paragraph above already says <release>-ca-cert holds the CA private key, so drop the note instead of inverting it. Guard the ownerReference assertions against an absent list. length() of null is a type error rather than a failed comparison, and the harness returns it as an error, which aborts the poll instead of retrying — so the timeout never applies while the operator is still patching the reference on. Restore the two-variable form of the fingerprint comparison. Inlining both command substitutions into the test swallows a non-zero exit: with no openssl on PATH both sides are empty, they compare equal, and the check passes having compared nothing. Signed-off-by: Aleksei Sviridkin <[email protected]>
The assertions withholding the key-bearing TLS Secrets from the tenant Role addressed it as document 0 and, in two cases, asserted only with notContains. Neither survives a rearrangement. notContains passes when its path does not resolve, so a test built from it alone goes green against the wrong document. Reversing the order of the two documents in the template moved the RoleBinding into position 0, and "does not grant the key-bearing TLS secrets when external is enabled" and "does not grant the tenant-ca projection by name" both stayed green while the Role granted <release>-ca-cert by name — the Secret holding the CA private key. Select the Role by kind, and pair every notContains with a positive assertion on the same path so a rule reordering that moves rules[1] reddens too. Indexing survives neither rearrangement; selecting survives the first; the positive anchor catches the second. Signed-off-by: Aleksei Sviridkin <[email protected]>
Every object this chart creates is named after the Helm release, not after the MongoDB resource, so a MongoDB named catest yields mongodb-catest.tenant-ca. The retrieval commands used a bare <release> placeholder, which reads as the resource name and produces a command that returns nothing. Spell the prefix out in the two commands meant to be copied, and define the placeholder once for the prose. Split the sentinel's shape test in two. The absence of ownerReferences is the invariant — it breaks the walk from the projection back to the release, and the tenant stops receiving the anchor. An explicit namespace or a chart-added label breaks nothing by itself; grouping all three under one name presented them as equally load-bearing. Signed-off-by: Aleksei Sviridkin <[email protected]>
e6fe8df to
8d386c2
Compare
myasnikovdaniil
left a comment
There was a problem hiding this comment.
LGTM on the code, please fix the description before merging. It describes an earlier revision of this branch.
- "Both were previously reachable", and the release note "stop exposing TLS private key material to tenants". Neither secret was reachable by a tenant before this branch. On main the cozyrds carries
exclude: []and an include naming onlymongodb-{{ .name }}-credentials, and include is a whitelist (internal/lineagecontrollerwebhook/matcher.go:64-72), so a secret matching nothing never gets stamped and tenantsecrets serves onlytenantresource=true. Dashboard Role on main grants<release>-credentialsand nothing else, the diff to that file here is +13/-0 and adds a comment. The exposure existed in intermediate revisions of this branch, not in a release. Changelog generation reads PR bodies, so as written this ships as a claim that cozystack was handing tenants CA private keys. spec.caCertis gone, the chart renders a TenantProjection now and there is no caCert field inapi/v1alpha1/applicationdefinitions_types.go.- Merge is not blocked on #3299. It is closed, what it carried is on main, and this branch is current with main.
I ran helm unittest (130/130) and the new bats suite, and checked the jmespath guards in the new e2e steps against the rendered Role and against widened variants, each one discriminates. My own concern about sourcing the projection from <release>-ssl during CA rotation was wrong, the extraction controller takes a multi-cert bundle and re-encodes every block.
Not blocking, two things worth knowing. External replica set releases will roll on upgrade because the leaf is reissued with new SANs, README covers that including the outage below 3 replicas. And nothing publishes <release>-rs0-<i>.<host>, replsets[].expose.serviceAnnotations is a single map shared by all per-pod services so per-pod external-dns hostnames cannot be expressed through the operator, SANs stay inert until someone creates the records by hand. Worth putting that in the release note and not only the README.
postgres-rd still has exclude: [] with the same label-only include if you want to converge them later.
#2692) ## What this PR does Enables operator-managed TLS for MongoDB and stops handing tenants any Secret that carries private key material. - Percona Server for MongoDB serves TLS unconditionally (`mode: preferTLS`), so this PR drops the misleading `tls.enabled` toggle rather than pretending the chart controls it. - The tenant no longer receives the operator's CA Secret (`<release>-ca-cert`, which holds `ca.key`) or the leaf (`<release>-ssl`). Both were previously reachable, and either one is a private key in tenant hands, the CA one is a full trust-chain compromise. - The chart declares a `TenantProjection` sentinel naming its CA source Secret (`<release>-ssl`, the operator-managed leaf, which carries `ca.crt`), and the ResourceDefinition selects the resulting key-free `<release>.tenant-ca` projection by the engine-agnostic `internal.cozystack.io/tenant-ca` label. The CA-extraction controller reads the sentinel and publishes the projection holding only `ca.crt`. The tenant gets what it needs to verify the server and nothing else. ### Why the include also carries an exclude list The trust-anchor selector matches by label with no name constraint, so any Secret in the namespace that acquired that label would be promoted with its data copied verbatim. The enumerable dangerous set is therefore excluded explicitly: the CA, both leaves, the rotation snapshots (`-ssl-old`, `-ssl-internal-old`, same server keys as the leaves, and unlike them they carry no owner reference, so an interrupted rotation can leave them behind after the release is gone), the system-user passwords, the at-rest encryption key, the keyfile, the object-storage credentials, and both forms of the operator's internal Secret. That backstop is bounded, and the comment says so: matching is by exact name with no globs, so a Secret a future operator version introduces, or a transient object an issuer creates mid-renewal, stays in scope of the label-only include. The per-user Secrets cannot be enumerated at all, since their names carry the username. The primary defence remains that the controller stamps only its own projection; this closes the enumerable set, not the whole surface. ### Release note ```release-note feat(mongodb): stop exposing TLS private key material to tenants and publish the CA as a key-free trust anchor ```
What this PR does
Enables operator-managed TLS for MongoDB and stops handing tenants any Secret that carries private key material.
mode: preferTLS), so this PR drops the misleadingtls.enabledtoggle rather than pretending the chart controls it.<release>-ca-cert, which holdsca.key) or the leaf (<release>-ssl). Both were previously reachable, and either one is a private key in tenant hands, the CA one is a full trust-chain compromise.TenantProjectionsentinel naming its CA source Secret (<release>-ssl, the operator-managed leaf, which carriesca.crt), and the ResourceDefinition selects the resulting key-free<release>.tenant-caprojection by the engine-agnosticinternal.cozystack.io/tenant-calabel. The CA-extraction controller reads the sentinel and publishes the projection holding onlyca.crt. The tenant gets what it needs to verify the server and nothing else.Why the include also carries an exclude list
The trust-anchor selector matches by label with no name constraint, so any Secret in the namespace that acquired that label would be promoted with its data copied verbatim. The enumerable dangerous set is therefore excluded explicitly: the CA, both leaves, the rotation snapshots (
-ssl-old,-ssl-internal-old, same server keys as the leaves, and unlike them they carry no owner reference, so an interrupted rotation can leave them behind after the release is gone), the system-user passwords, the at-rest encryption key, the keyfile, the object-storage credentials, and both forms of the operator's internal Secret.That backstop is bounded, and the comment says so: matching is by exact name with no globs, so a Secret a future operator version introduces, or a transient object an issuer creates mid-renewal, stays in scope of the label-only include. The per-user Secrets cannot be enumerated at all, since their names carry the username. The primary defence remains that the controller stamps only its own projection; this closes the enumerable set, not the whole surface.
Release note