Skip to content

feat(postgres): add TLS support via CNPG operator-managed certificates - #2686

Merged
Arsolitt (Arsolitt) merged 13 commits into
mainfrom
feat/tls-postgres
May 29, 2026
Merged

feat(postgres): add TLS support via CNPG operator-managed certificates#2686
Arsolitt (Arsolitt) merged 13 commits into
mainfrom
feat/tls-postgres

Conversation

@Arsolitt

@Arsolitt Arsolitt (Arsolitt) commented May 19, 2026

Copy link
Copy Markdown
Contributor

What this PR does

Adds TLS support to the Postgres managed service via the CNPG operator's built-in cert management.

  • Introduces a nullable tls.enabled field with tri-state semantics: when unset, defaults to the value of external (auto-on for externally published services, off for cluster-internal). Explicit tls.enabled always wins.
  • Uses CNPG's operator-managed TLS chain — the chart no longer renders its own cert-manager chain. The operator auto-generates a self-signed CA and signs server, client, and replication certs from it. The operator's default SAN list already covers the three built-in services (rw/r/ro) in four DNS forms each (bare, .ns, .ns.svc, .ns.svc.<cluster-domain>).
  • When external: true and TLS is on, the chart sets spec.certificates.serverAltDNSNames so the operator appends the external hostname <release>.<tenant-host> to the auto-generated leaf cert. In all other cases the chart leaves spec.certificates absent and the operator uses its default SAN set.
  • Trust anchor for clients: the operator-managed <release>-ca Opaque Secret (key ca.crt). Mount that key into client pods to verify TLS.

Why operator-managed instead of a chart-side cert-manager chain: an earlier iteration that supplied serverCASecret and serverTLSSecret from a chart-rendered cert-manager chain failed the CNPG admission webhook with missing ca.key secret data. CNPG expects a ca.key field on serverCASecret, while cert-manager writes the private key under tls.key. Operator-managed mode avoids the schema fight entirely.

Verified end-to-end on a sandbox cluster: cert chain is created by the operator within ~60 seconds, leaf cert's SAN list includes both the standard service forms and the external hostname, TLSv1.3 handshake via openssl s_client -starttls postgres against the rw service with the operator CA returns verify code 0.

Release note

feat(postgres): add TLS support via CNPG operator-managed certificates with tri-state tls.enabled

Summary by CodeRabbit

  • New Features

    • TLS configuration added for PostgreSQL with a tri-state tls.enabled to control operator-managed certificate behavior and optional injection of the external hostname into server certificate SANs.
  • Documentation

    • Added TLS configuration guide, client CA retrieval and psql verification examples, and updated parameters reference.
  • Tests

    • Added integration tests covering tri-state TLS behavior and external-hostname injection scenarios.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds tri-state TLS enablement to PostgreSQL CRD types and Helm chart surfaces, updating deepcopy, values/schema, templates, tests, README, and ApplicationDefinition metadata to control CNPG operator-managed certificate SAN injection.

Changes

PostgreSQL TLS Configuration

Layer / File(s) Summary
CRD TLS Type & DeepCopy
api/apps/v1alpha1/postgresql/types.go, api/apps/v1alpha1/postgresql/zz_generated.deepcopy.go
Introduce TLS struct with Enabled *bool and add Tls TLS to ConfigSpec; add autogenerated deepcopy methods to copy the pointer.
Helm Values & JSON Schema
packages/apps/postgres/values.yaml, packages/apps/postgres/values.schema.json
Add tls: {} values block and tls.enabled boolean with tri-state semantics documented in the JSON schema.
Helm Template Implementation
packages/apps/postgres/templates/_tls.tpl, packages/apps/postgres/templates/db.yaml
Add postgres.tls.enabled helper to normalize tri-state for comparisons; render spec.certificates.serverAltDNSNames when TLS is enabled and external is set.
Tests & Documentation
packages/apps/postgres/tests/tls_test.yaml, packages/apps/postgres/README.md
Add Helm integration tests covering external × tls.enabled combinations and update README with TLS usage, CA retrieval, and parameter reference.
ApplicationDefinition Integration
packages/system/postgres-rd/cozyrds/postgres.yaml
Update embedded Chart Values schema and insert spec.tls into spec.application.keysOrder.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🐰 A tri-state toggle, snug and bright,
The CNPG certs now hop on sight,
External names tucked in the SAN,
Hops of joy from rabbit clan,
Charts and types now sleep at night.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the main change: adding TLS support via CNPG operator-managed certificates, which is the primary objective throughout all code changes including the new tls configuration, Helm templates, and documentation.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tls-postgres

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 and usage tips.

@github-actions github-actions Bot added area/database Issues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse) kind/feature Categorizes issue or PR as related to a new feature size/L This PR changes 100-499 lines, ignoring generated files labels May 19, 2026
@Arsolitt
Arsolitt (Arsolitt) marked this pull request as ready for review May 19, 2026 13:03
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 integrates native TLS support for PostgreSQL managed services by leveraging the CNPG operator's built-in certificate management. By shifting from a chart-rendered cert-manager chain to operator-managed certificates, the implementation avoids previous admission webhook conflicts and simplifies the certificate lifecycle. The changes include a flexible tri-state configuration for TLS, updated schema definitions, and robust validation via new test suites.

Highlights

  • TLS Support: Introduced operator-managed TLS support for Postgres using the CNPG operator, replacing the previous chart-side cert-manager implementation.
  • Tri-state TLS Configuration: Added a new tls.enabled field with tri-state semantics: unset (default) auto-enables TLS if external is true, while explicit true/false values override this behavior.
  • Documentation and Testing: Updated documentation with TLS configuration details and added comprehensive test cases to verify TLS behavior across different configuration states.
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
  • Ignored by pattern: **/zz_generated.*.go (1)
    • api/apps/v1alpha1/postgresql/zz_generated.deepcopy.go
Using Gemini Code Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

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

Copy link
Copy Markdown
Contributor

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 introduces a tri-state TLS configuration for the PostgreSQL package, enabling automatic TLS for external connections while allowing users to explicitly force the setting. The feedback highlights a documentation error regarding the certificate management mechanism and notes that the implementation for forcing TLS off is currently incomplete, as it lacks the necessary PostgreSQL parameter overrides. Additionally, a naming convention update was requested for the Go API types to correctly use the TLS initialism.

Comment thread packages/apps/postgres/README.md Outdated
Comment thread packages/apps/postgres/templates/db.yaml
Comment thread api/apps/v1alpha1/postgresql/types.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/postgres/README.md`:
- Around line 163-171: Update the README text to remove references to
cert-manager resources and the CNPG fields spec.certificates.serverCASecret and
spec.certificates.serverTLSSecret (these describe the old cert-manager flow) and
instead document the current operator-managed certificate flow: state that the
operator manages the CA and leaf certificates internally, that the chart no
longer creates <release>-selfsigned / <release>-ca / <release>-tls cert-manager
resources, and that when external TLS is enabled the operator injects only
spec.certificates.serverAltDNSNames; also adjust verification guidance to show
how to validate the operator-managed chain (e.g., inspect the CNPG Cluster
status/conditions or the operator logs) rather than looking for cert-manager
Secrets.
🪄 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: ba298fb0-b458-4b59-a5c8-7a6e0c5b6c52

📥 Commits

Reviewing files that changed from the base of the PR and between c5e9287 and 5b9c4f9.

📒 Files selected for processing (10)
  • api/apps/v1alpha1/postgresql/types.go
  • api/apps/v1alpha1/postgresql/zz_generated.deepcopy.go
  • packages/apps/postgres/Makefile
  • packages/apps/postgres/README.md
  • packages/apps/postgres/templates/_tls.tpl
  • packages/apps/postgres/templates/db.yaml
  • packages/apps/postgres/tests/tls_test.yaml
  • packages/apps/postgres/values.schema.json
  • packages/apps/postgres/values.yaml
  • packages/system/postgres-rd/cozyrds/postgres.yaml

Comment thread packages/apps/postgres/README.md Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/apps/postgres/README.md (1)

163-171: ⚠️ Potential issue | 🟠 Major

TLS documentation describes the old cert-manager flow, not the current operator-managed flow.

Lines 163-171 state that the chart creates cert-manager resources (<release>-selfsigned, <release>-ca, <release>-tls) and that the CNPG Cluster references spec.certificates.serverCASecret and spec.certificates.serverTLSSecret. This contradicts the implemented operator-managed certificate flow where the CNPG operator auto-generates the CA and leaf certificates, and the chart only sets spec.certificates.serverAltDNSNames when external TLS is enabled.

🤖 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/postgres/README.md` around lines 163 - 171, Update the README
section that currently claims the chart creates cert-manager resources and that
the CNPG Cluster references spec.certificates.serverCASecret and
spec.certificates.serverTLSSecret: change it to describe the operator-managed
flow where the CNPG operator auto-generates the CA and leaf certificates (so
cert-manager resources like <release>-selfsigned / <release>-ca / <release>-tls
are not created by the chart), and note that the chart only sets
spec.certificates.serverAltDNSNames when external TLS is enabled; replace
references to serverCASecret/serverTLSSecret with the operator auto-generation
behavior and the use of spec.certificates.serverAltDNSNames.
🤖 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/postgres/Makefile`:
- Around line 5-8: Add a precondition check that validates the generator's
original output before mutating values.schema.json: use jq -e to assert that
.properties.tls.properties.enabled.type is exactly ["boolean"] (the expected
cozyvalues-gen output) and fail early if not, then perform the jq assignment
that changes it to ["boolean","null"], and finally keep the existing post-patch
equality check; refer to the jq expression
'.properties.tls.properties.enabled.type' and the file values.schema.json to
locate where to insert the precondition check.

---

Duplicate comments:
In `@packages/apps/postgres/README.md`:
- Around line 163-171: Update the README section that currently claims the chart
creates cert-manager resources and that the CNPG Cluster references
spec.certificates.serverCASecret and spec.certificates.serverTLSSecret: change
it to describe the operator-managed flow where the CNPG operator auto-generates
the CA and leaf certificates (so cert-manager resources like
<release>-selfsigned / <release>-ca / <release>-tls are not created by the
chart), and note that the chart only sets spec.certificates.serverAltDNSNames
when external TLS is enabled; replace references to
serverCASecret/serverTLSSecret with the operator auto-generation behavior and
the use of spec.certificates.serverAltDNSNames.
🪄 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: caa4178d-7dd4-4cf9-b64c-72e89c006a2b

📥 Commits

Reviewing files that changed from the base of the PR and between 5b9c4f9 and 2ccc31a.

📒 Files selected for processing (10)
  • api/apps/v1alpha1/postgresql/types.go
  • api/apps/v1alpha1/postgresql/zz_generated.deepcopy.go
  • packages/apps/postgres/Makefile
  • packages/apps/postgres/README.md
  • packages/apps/postgres/templates/_tls.tpl
  • packages/apps/postgres/templates/db.yaml
  • packages/apps/postgres/tests/tls_test.yaml
  • packages/apps/postgres/values.schema.json
  • packages/apps/postgres/values.yaml
  • packages/system/postgres-rd/cozyrds/postgres.yaml

Comment thread packages/apps/postgres/Makefile Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — postgres now extends the CNPG operator-managed cert with the external hostname via spec.certificates.serverAltDNSNames when external+TLS; tri-state tls.enabled is well-tested; the chart correctly does NOT expose the operator-managed <release>-ca Secret (which holds the CA private key) to tenant use access. Two non-blocking follow-ups below — neither is unique to this PR.

Business context: the earlier iteration tried supplying serverCASecret / serverTLSSecret from a chart-rendered cert-manager chain, which failed the CNPG admission webhook (missing ca.key — cert-manager writes the private key under tls.key, not ca.key). This PR shifts to operator-managed mode, where the chart only contributes the external hostname SAN. CNPG keeps its built-in TLS on the wire regardless of tls.enabled; the toggle controls SAN injection only, which is correctly documented in values.yaml and the new README section.

Verified:

  • Tri-state evaluation in templates/_tls.tpl:11-17 uses kindIs "invalid" for null-detection and inherits from .Values.external. tests/tls_test.yaml covers all four cells of the truth table.
  • templates/db.yaml:9 correctly gates the certificates block on both tlsEnabled and external — without an external hostname there is nothing to append to the SAN list, and the operator's default SAN set already covers the rw/r/ro DNS forms.
  • templates/dashboard-resourcemap.yaml intentionally does NOT grant read access on <release>-ca. The operator-managed CA Secret carries both ca.crt and ca.key; exposing it to tenant use access would leak the CA private key (the inverse of the mariadb #2680 blocker). README directs users to retrieve the CA via kubectl get secret <release>-ca, which is the right path.
  • README's sslmode=verify-full + sslrootcert=ca.crt example matches CNPG's documented client-trust workflow.
  • All CodeRabbit / Gemini threads on this PR are resolved.

Non-blocking follow-ups (both apply across the TLS series, not just here):

  1. packages/system/postgres-rd/cozyrds/postgres.yaml:42 lists postgres-{{ .name }}-ca under secrets.include, but the chart's dashboard-resources Role does not grant read access on it. The dashboard will advertise the secret name and tenant users will get RBAC-denied on read. The chart's restrictive RBAC is the right call — drop -ca from cozyrds's secrets.include so the discovery layer stops promising a read that the chart deliberately doesn't grant.

  2. Both values.schema.json and the cozyrds openAPISchema use "type":["boolean","null"] for tls.enabled. pkg/registry/apps/application/rest.go:103-105 unmarshals the schema into apiextv1.JSONSchemaProps, whose Type field is a single string — I reproduced json: cannot unmarshal array into Go struct field JSONSchemaProps.properties.type of type string against v0.34.1. The error is logged and specSchema stays nil, so server-side defaulting via rest_defaulting.go is silently disabled for this app; Helm-side defaults still apply, so user-visible breakage is minimal but the app loses schema-driven defaulting. Same pattern in #2681 kafka and likely the rest of the TLS series. Worth a separate fix to switch to the apiextv1 idiom (nullable: true) or to drop type entirely on the tri-state property.

@Arsolitt

Copy link
Copy Markdown
Contributor Author

Addressed your non-blocking follow-ups:

  • FU1 (postgres-<name>-ca listed in cozyrds secrets.include but dashboard Role doesn't grant on it — broken discovery UX) — fixed in edcb656bb. Dropped the -ca entry from cozyrds. Tenants retrieve ca.crt from CNPG user-credentials Secrets (the chart already grants use access to those via dashboard RBAC), which bundle ca.crt alongside the user cert per CNPG convention. README updated with the corrected retrieval path.
  • FU2 (["boolean","null"] schema breaks apiextv1 unmarshal) — fixed in 184be891d. Schema now emits plain "type": "boolean"; tri-state null-detection moves to the Helm template via kindIs "invalid". Same cleanup applied across the TLS series.

No cert-manager changes (CNPG operator-managed certs).

Ready for re-review.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/postgres/tests/tls_test.yaml`:
- Around line 7-10: Update the commented test header to accurately reflect
behavior: change the `tls.enabled: true` bullet to note that while TLS is forced
on, chart-side SAN injection into `spec.certificates` only occurs when an
`external` hostname is present, and clarify that `tls.enabled: false` forces TLS
off regardless of `external`; reference the keys `tls.enabled`, `external`,
`spec.certificates`, and the phrase “chart-side SAN injection” so the comment
matches the actual assertions in the test.

In `@packages/apps/postgres/values.schema.json`:
- Around line 127-128: The schema description for the boolean property
incorrectly mentions “null” while the generated "type": "boolean" disallows
null; update the source text used by cozyvalues-gen to replace “omitted (null)”
with “omitted/absent” (or similar non-null wording) for that property’s
description, then re-run the cozyvalues-gen pipeline and `make generate` so the
values.schema.json is regenerated consistently; locate the original description
string in the values source used by cozyvalues-gen (the property whose generated
schema contains the shown description) and change only the wording, not the
schema type.
🪄 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: eb159f45-6eaf-4af6-99af-a3063a3c8030

📥 Commits

Reviewing files that changed from the base of the PR and between d63f82e and 184be89.

📒 Files selected for processing (5)
  • packages/apps/postgres/README.md
  • packages/apps/postgres/templates/db.yaml
  • packages/apps/postgres/tests/tls_test.yaml
  • packages/apps/postgres/values.schema.json
  • packages/system/postgres-rd/cozyrds/postgres.yaml
✅ Files skipped from review due to trivial changes (1)
  • packages/apps/postgres/README.md

Comment thread packages/apps/postgres/tests/tls_test.yaml
Comment thread packages/apps/postgres/values.schema.json Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM on the new SHA. Both non-blocking follow-ups from my prior LGTM are now closed:

  • edcb656bb fix(postgres): drop CA Secret from cozyrds — tenant retrieves ca.crt from user-credentials Secretpackages/system/postgres-rd/cozyrds/postgres.yaml now lists only postgres-{{ .name }}-credentials under secrets.include, and packages/apps/postgres/templates/dashboard-resourcemap.yaml matches (only <release>-credentials). The dashboard no longer advertises a CA Secret that RBAC didn't actually grant, AND CNPG's operator-managed <release>-ca (which would carry ca.key) stays unexposed to tenant use. Both layers consistent now.
  • 184be891d refactor(postgres): drop null from tls.enabled schema, use kindIs invalid pattern — same schema convention as the rest of the batch; "type":["boolean","null"] would fail apiextv1.JSONSchemaProps unmarshal. Resolved.

d63f82ed9 build(postgres): assert schema shape before patching tls.enabled.type adds a defensive grep before the jq patch in the Makefile so a future cozyvalues-gen format change fails the build loud instead of producing a malformed schema silently. Good belt-and-suspenders.

Operator-managed CNPG chain still owns the cert lifecycle end-to-end; chart only injects external-hostname SAN when external+TLS — same shape as before, just cleaner cozyrds advertisement.

- Extend PostgresSpec with nullable Tls.Enabled (*bool) for tri-state control
- Regenerate deepcopy and update go.mod with k8s.io/utils as direct dep
- Add TLS fields to values.yaml, values.schema.json (with nullable support)
- Update README and Makefile; propagate TLS field to cozyrds postgres.yaml

Signed-off-by: Arsolitt <arsolitt@gmail.com>
- Add _tls.tpl helper with tri-state resolution logic (nil/false/true)
- Add certmanager.yaml to provision CA and leaf Certificate resources
- Wire TLS listener configuration into db.yaml when TLS is enabled

Signed-off-by: Arsolitt <arsolitt@gmail.com>
- Add helm-unittest suite covering tri-state TLS (nil/false/true), CA/leaf cert
  properties, external SAN injection, and cert-manager resource absence when disabled

Signed-off-by: Arsolitt <arsolitt@gmail.com>
…ection

CNPG admission webhook rejects spec.certificates that combines a
serverTLSSecret with serverAltDNSNames, and the operator's internal
client-CA generation step expects ca.key on the secret bound to
serverCASecret — a field cert-manager does not produce, since it stores
the private key as tls.key. The previous chart configuration triggered
exactly this path and left the Cluster stuck on
"generating client CA certificate: missing ca.key secret data".

Drop the chart-rendered cert-manager Issuer/Certificate chain and the
spec.certificates.serverCASecret/serverTLSSecret references. CNPG now
auto-generates the self-signed CA and signs server, replication, and
client certs from it, producing the expected per-purpose secrets
(<release>-ca, <release>-server, <release>-replication). The operator's
default SAN list already covers the three built-in services
(rw, r, ro) in four DNS forms each.

The chart still needs to inject the external LoadBalancer hostname when
external=true, since that name lives outside the operator's auto-derived
set. Emit spec.certificates.serverAltDNSNames with that single entry
under that condition only.

End-to-end test on dev13: Cluster reaches "healthy state", probe pod
with PGSSLMODE=verify-full against the operator-managed CA succeeds and
SHOW ssl reports on.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
Drop the templates/certmanager.yaml suite entirely (the file no longer
exists) and rewrite the spec.certificates assertions to match the new
operator-managed flow: certificates block emitted only when both TLS is
on AND external is true, with serverAltDNSNames carrying just the
external hostname.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
…direct

Signed-off-by: Arsolitt <arsolitt@gmail.com>
The README still described the chart-side cert-manager chain that was
replaced when the chart switched to CNPG operator-managed TLS via
spec.certificates.serverAltDNSNames. Rewrite the section to explain the
actual cert ownership boundary (CNPG owns the chain, chart only injects
the external hostname), the trust anchor location (operator-managed
<release>-ca Secret, key ca.crt), and the chart-side semantics of the
tri-state tls.enabled flag. The values.yaml @field comment is updated
in the same direction, with regenerated schema/types.go/cozyrds.

Clarifies that tls.enabled=false only skips the chart-side SAN
injection - CNPG retains its built-in TLS on the wire regardless of
this flag. To force PostgreSQL TLS off entirely, the caller would set
postgresql.parameters.ssl="off" at the CNPG layer.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
Add a precondition that fails early if cozyvalues-gen no longer emits
tls.enabled.type as the bare "boolean" string the patch step expects.
Without the guard, a generator output that drops or moves the field
would silently create it via the assignment, and the post-patch
equality check would still pass against the synthetic value.

Signed-off-by: Arsolitt <arsolitt@gmail.com>
…from user-credentials Secret

The dashboard RBAC intentionally does not grant access to the operator-managed
<release>-ca Secret (it contains ca.key, which would leak the private key).
Advertising it in cozyrds secrets.include created a UX gap: the dashboard
showed a Secret the tenant could never read.

CNPG bundles ca.crt in every user-credentials Secret it creates, so tenants
already have the trust anchor they need via the <release>-credentials Secret
which is covered by RBAC. Update README and the db.yaml comment to point there.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
…alid pattern

Remove the jq post-processing patch that widened tls.enabled type to
["boolean","null"] in values.schema.json and the openAPISchema embedded
in the cozyrds CRD. Plain "type":"boolean" is emitted directly by
cozyvalues-gen and is the correct form.

The cozystack-api server unmarshals openAPISchema into
apiextv1.JSONSchemaProps whose Type field is a single string; an array
value silently zeros the field and disables server-side defaulting for
the entire app.

Tri-state semantics are preserved on the Helm template side via
kindIs "invalid": omitting tls.enabled triggers the external-based
fallback; null is no longer a valid input and is rejected by the schema.

Remove two helm-unittest cases that injected tls.enabled: null (now
intentionally rejected) and update the suite comment to match.

Signed-off-by: Arsolitt <arsolitt@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/postgres/README.md`:
- Line 217: The `version` parameter is incorrectly listed under the TLS table in
packages/apps/postgres README; update the source that generates the `##
Parameters` block so `version` is defined in the general/app parameters section
(not in the TLS group), then run the doc generator (cozyvalues-gen via `make
generate`) to regenerate the `## Parameters` block in README.md; target the
parameter named `version` and the README's `## Parameters` generation logic so
the entry appears in the general parameters table rather than the TLS table.
🪄 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: c856b0cb-228e-419e-abc8-fa14454507db

📥 Commits

Reviewing files that changed from the base of the PR and between 184be89 and 0c7c393.

📒 Files selected for processing (9)
  • api/apps/v1alpha1/postgresql/types.go
  • api/apps/v1alpha1/postgresql/zz_generated.deepcopy.go
  • packages/apps/postgres/README.md
  • packages/apps/postgres/templates/_tls.tpl
  • packages/apps/postgres/templates/db.yaml
  • packages/apps/postgres/tests/tls_test.yaml
  • packages/apps/postgres/values.schema.json
  • packages/apps/postgres/values.yaml
  • packages/system/postgres-rd/cozyrds/postgres.yaml
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/apps/postgres/values.yaml
  • api/apps/v1alpha1/postgresql/zz_generated.deepcopy.go
  • packages/apps/postgres/values.schema.json
  • api/apps/v1alpha1/postgresql/types.go
  • packages/system/postgres-rd/cozyrds/postgres.yaml
  • packages/apps/postgres/templates/_tls.tpl
  • packages/apps/postgres/tests/tls_test.yaml

Comment thread packages/apps/postgres/README.md Outdated
The generated JSON schema types tls.enabled as a scalar boolean, which
rejects an explicit null value; describe the tri-state unset case as
"omitted" so the wording matches what the schema actually accepts.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
version is a general deployment parameter, not a TLS setting; relocate
its @param/@enum block back into Common parameters so the generated
parameter reference groups it correctly instead of under TLS.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Resolve the conflict in the generated packages/system/postgres-rd/cozyrds/postgres.yaml by regenerating openAPISchema and keysOrder from the merged values. The CRD now carries both the chart's tls.enabled field and main's backup useSystemBucket / BackupClass-driven fields.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM — operator-managed CNPG TLS is correctly wired, the tri-state toggle is honestly documented as controlling SAN injection rather than on-the-wire TLS, generated artifacts are in sync, and tests pass.

Business context: managed Postgres on CNPG already serves TLS by default; this PR's tls.enabled tri-state does not turn TLS on or off — it controls whether the chart appends the external hostname (<release>.<_namespace.host>) to the operator-generated server cert via spec.certificates.serverAltDNSNames, replacing an earlier cert-manager chain that failed CNPG's admission webhook (missing ca.key).

Non-blocking follow-ups

  1. _namespace.host is dereferenced unconditionally when external=true and tls.enabled is unset (packages/apps/postgres/templates/db.yaml:25). This matches the platform contract every tenant app relies on (harbor, kubernetes, vpn all read .Values._namespace.host unconditionally), and the chart cannot render under bare helm template regardless — not a real-path regression. The genuine residual: when a tenant has no apex domain, _namespace.host is empty and the SAN renders as <release>. (trailing dot) rather than failing. The gateway package fails on empty host; a required/fail guard here would match that precedent.
  2. The field is named tls.enabled but its effect is "inject external hostname into the cert SAN", not an on/off TLS switch. Now thoroughly documented (values.yaml, schema, README each spell out that CNPG keeps TLS on the wire regardless and point to postgresql.parameters.ssl=off for a true disable). Noting as a design observation.

# client pods to verify TLS.
certificates:
serverAltDNSNames:
- {{ printf "%s.%s" .Release.Name .Values._namespace.host }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

When external: true and a tenant has no apex domain, _namespace.host is the empty string and this renders a malformed SAN <release>. (trailing dot). The gateway package fails on empty _namespace.host; a required-gate on a non-empty host here would match that precedent. Bare-helm template nil-pointer is not a real-path regression (the chart already requires platform-injected _namespace/_cluster, same as harbor/kubernetes/vpn), so this is non-blocking.

@Arsolitt
Arsolitt (Arsolitt) merged commit 94f463d into main May 29, 2026
13 of 14 checks passed
@Arsolitt
Arsolitt (Arsolitt) deleted the feat/tls-postgres branch May 29, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/database Issues or PRs related to managed databases (postgres, mariadb, redis, etcd, kafka, clickhouse) kind/feature Categorizes issue or PR as related to a new feature size/L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants