feat(qdrant): add TLS support via cert-manager - #2685
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (11)
💤 Files with no reviewable changes (9)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds explicit TLS configuration and helper to compute effective TLS, cert-manager templates for certificate generation, Helm wiring to enable/mount TLS, generated deepcopy support, values/schema/docs, Makefile test target, and extensive template/unit tests. ChangesQdrant TLS Configuration and Certificate Management
Sequence Diagram(s) sequenceDiagram
participant Values as "Helm Values"
participant Templating as "Helm Templating Engine"
participant K8s as "Kubernetes API"
participant CertManager as "cert-manager"
participant Qdrant as "Qdrant Pod"
Values->>Templating: render templates (qdrant.tls.enabled, certmanager.yaml, qdrant.yaml)
Templating->>K8s: apply Issuer/Certificate resources when tls enabled
CertManager->>K8s: create Secret with issued cert and key and ca
K8s->>Qdrant: mount Secret as volume and set reloader annotation
Qdrant->>Qdrant: load cert key and ca from /qdrant/tls and enable TLS
Estimated code review effort 🎯 3 (Moderate) | ⏱️ ~20 minutes
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 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 |
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 enhances the Qdrant managed service by integrating cert-manager for automated TLS certificate management. It provides a robust configuration mechanism that defaults to secure-by-default behavior based on external access requirements, while allowing explicit overrides. The changes include updates to the API types, Helm templates, and schema definitions, accompanied by thorough unit testing to ensure correct rendering of certificates and service configurations. 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 Qdrant application by adding a tls configuration field to the API and Helm values. The changes include a new certmanager.yaml template for certificate generation, updates to the qdrant.yaml HelmRelease to configure TLS and volume mounts, and the addition of comprehensive unit tests. Feedback focuses on improving template maintainability by extracting TLS enablement logic into a common Helm helper and simplifying the volume mount logic by removing redundant empty list assignments.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/apps/qdrant/tests/qdrant_test.yaml (1)
160-247: ⚡ Quick winAdd explicit
tls.enabled: nullinheritance test cases.The suite validates unset/true/false, but the nullable mode (
null) is not covered. Adding these assertions will lock in tri-state behavior and prevent regressions.Suggested test additions
+ # (e) external: false, tls.enabled: null -> TLS OFF (null inherits) + - it: "(e) TLS is OFF when external is false and tls.enabled is null" + release: + name: test-qdrant + namespace: tenant-test + set: + external: false + tls: + enabled: null + asserts: + - equal: + path: spec.values.qdrant.config.service.enable_tls + value: false + - equal: + path: spec.values.qdrant.config.cluster.p2p.enable_tls + value: false + + # (f) external: true, tls.enabled: null -> TLS ON (null inherits) + - it: "(f) TLS is ON when external is true and tls.enabled is null" + release: + name: test-qdrant + namespace: tenant-test + set: + external: true + tls: + enabled: null + asserts: + - equal: + path: spec.values.qdrant.config.service.enable_tls + value: true + - equal: + path: spec.values.qdrant.config.cluster.p2p.enable_tls + value: true🤖 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/qdrant/tests/qdrant_test.yaml` around lines 160 - 247, Add two canonical tri-state tests that assert nullable inheritance when tls.enabled is explicitly null: one where set: { external: false, tls: { enabled: null } } should result in spec.values.qdrant.config.service.enable_tls and spec.values.qdrant.config.cluster.p2p.enable_tls being false and spec.values.qdrant.additionalVolumes/additionalVolumeMounts being empty, and another where set: { external: true, tls: { enabled: null } } should result in those enable_tls fields being true and spec.values.qdrant.additionalVolumes containing the tls secret (secretName: test-qdrant-tls); mirror the style and assertions used in the existing cases "(a)"–"(d)" to ensure tri-state null behavior is covered.
🤖 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/qdrant/templates/qdrant.yaml`:
- Around line 1-7: The template treats tls.enabled present-but-null as an
explicit value; change the assignment logic for $tlsEnabled so null falls back
to .Values.external (and then to false) instead of being used as-is. Replace the
hasKey/index branch with a single safe default expression that uses index
$tlsMap "enabled" but falls back to .Values.external (and then false) when
nil—for example use Helm's default function: set $tlsEnabled = default
(.Values.external | default false) (index $tlsMap "enabled") so null behaves
like unset.
---
Nitpick comments:
In `@packages/apps/qdrant/tests/qdrant_test.yaml`:
- Around line 160-247: Add two canonical tri-state tests that assert nullable
inheritance when tls.enabled is explicitly null: one where set: { external:
false, tls: { enabled: null } } should result in
spec.values.qdrant.config.service.enable_tls and
spec.values.qdrant.config.cluster.p2p.enable_tls being false and
spec.values.qdrant.additionalVolumes/additionalVolumeMounts being empty, and
another where set: { external: true, tls: { enabled: null } } should result in
those enable_tls fields being true and spec.values.qdrant.additionalVolumes
containing the tls secret (secretName: test-qdrant-tls); mirror the style and
assertions used in the existing cases "(a)"–"(d)" to ensure tri-state null
behavior is covered.
🪄 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: 18212de2-150e-43bd-9deb-b98a92dbbbe6
📒 Files selected for processing (11)
api/apps/v1alpha1/qdrant/types.goapi/apps/v1alpha1/qdrant/zz_generated.deepcopy.gopackages/apps/qdrant/Makefilepackages/apps/qdrant/README.mdpackages/apps/qdrant/templates/certmanager.yamlpackages/apps/qdrant/templates/qdrant.yamlpackages/apps/qdrant/tests/certmanager_test.yamlpackages/apps/qdrant/tests/qdrant_test.yamlpackages/apps/qdrant/values.schema.jsonpackages/apps/qdrant/values.yamlpackages/system/qdrant-rd/cozyrds/qdrant.yaml
bc25a7d to
75e3caf
Compare
There was a problem hiding this comment.
♻️ Duplicate comments (2)
packages/apps/qdrant/templates/qdrant.yaml (1)
1-7:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winHandle
tls.enabled: nullas inherit-from-external, not as explicit override.This segment has the same tri-state null handling bug as identified in the past review comment. When
tls.enabledis explicitly set tonull, thehasKeycheck passes andindexassignsnilto$tlsEnabled, causing lines 53 and 56 to render blank YAML (enable_tls:) instead of valid booleans.🔧 Proposed fix
{{- $tlsMap := default (dict) .Values.tls -}} {{- $tlsEnabled := false -}} -{{- if hasKey $tlsMap "enabled" -}} - {{- $tlsEnabled = index $tlsMap "enabled" -}} -{{- else -}} +{{- $tlsRaw := index $tlsMap "enabled" -}} +{{- if and (hasKey $tlsMap "enabled") (ne $tlsRaw nil) -}} + {{- $tlsEnabled = $tlsRaw -}} +{{- else -}} {{- $tlsEnabled = .Values.external | default false -}} {{- end -}}🤖 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/qdrant/templates/qdrant.yaml` around lines 1 - 7, The current logic sets $tlsEnabled to nil when .Values.tls.enabled is explicitly null because it assigns index $tlsMap "enabled" whenever hasKey returns true; update the conditional for $tlsEnabled so it only uses index $tlsMap "enabled" when that value is non-nil, otherwise fall back to .Values.external | default false. Concretely, replace the hasKey branch for $tlsEnabled with a check like: if hasKey $tlsMap "enabled" and (index $tlsMap "enabled") is not nil then set $tlsEnabled = index $tlsMap "enabled" else set $tlsEnabled = .Values.external | default false so enable_tls renders a valid boolean instead of blank when tls.enabled is null.packages/apps/qdrant/templates/certmanager.yaml (1)
5-11:⚠️ Potential issue | 🔴 Critical | ⚡ Quick winHandle
tls.enabled: nullas inherit-from-external, not as explicit override.The tri-state contract documented in the values schema requires that
tls.enabledshould inherit from.Values.externalwhen unset or null. However, the current code only checks key presence withhasKey. Whentls.enabledis explicitly set tonull, it passes thehasKeycheck, andindexassignsnilto$tlsEnabled. This breaks the inheritance semantics and could prevent cert-manager resources from rendering correctly.🔧 Proposed fix
{{- $tlsMap := default (dict) .Values.tls -}} {{- $tlsEnabled := false -}} -{{- if hasKey $tlsMap "enabled" -}} - {{- $tlsEnabled = index $tlsMap "enabled" -}} -{{- else -}} +{{- $tlsRaw := index $tlsMap "enabled" -}} +{{- if and (hasKey $tlsMap "enabled") (ne $tlsRaw nil) -}} + {{- $tlsEnabled = $tlsRaw -}} +{{- else -}} {{- $tlsEnabled = .Values.external | default false -}} {{- end -}}🤖 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/qdrant/templates/certmanager.yaml` around lines 5 - 11, The code treats the presence of tls.enabled as an override even when it's null; update the assignment for $tlsEnabled so null inherits from .Values.external by using Helm's default to coalesce nil: replace the hasKey/index branch with a single assignment that sets $tlsEnabled = default (.Values.external | default false) (index $tlsMap "enabled") (or equivalent nested default), so when index returns nil it falls back to .Values.external (and that in turn defaults to false).
🤖 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.
Duplicate comments:
In `@packages/apps/qdrant/templates/certmanager.yaml`:
- Around line 5-11: The code treats the presence of tls.enabled as an override
even when it's null; update the assignment for $tlsEnabled so null inherits from
.Values.external by using Helm's default to coalesce nil: replace the
hasKey/index branch with a single assignment that sets $tlsEnabled = default
(.Values.external | default false) (index $tlsMap "enabled") (or equivalent
nested default), so when index returns nil it falls back to .Values.external
(and that in turn defaults to false).
In `@packages/apps/qdrant/templates/qdrant.yaml`:
- Around line 1-7: The current logic sets $tlsEnabled to nil when
.Values.tls.enabled is explicitly null because it assigns index $tlsMap
"enabled" whenever hasKey returns true; update the conditional for $tlsEnabled
so it only uses index $tlsMap "enabled" when that value is non-nil, otherwise
fall back to .Values.external | default false. Concretely, replace the hasKey
branch for $tlsEnabled with a check like: if hasKey $tlsMap "enabled" and (index
$tlsMap "enabled") is not nil then set $tlsEnabled = index $tlsMap "enabled"
else set $tlsEnabled = .Values.external | default false so enable_tls renders a
valid boolean instead of blank when tls.enabled is null.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3612a096-8d01-450a-bed7-815c73bd946b
📒 Files selected for processing (11)
api/apps/v1alpha1/qdrant/types.goapi/apps/v1alpha1/qdrant/zz_generated.deepcopy.gopackages/apps/qdrant/Makefilepackages/apps/qdrant/README.mdpackages/apps/qdrant/templates/certmanager.yamlpackages/apps/qdrant/templates/qdrant.yamlpackages/apps/qdrant/tests/certmanager_test.yamlpackages/apps/qdrant/tests/qdrant_test.yamlpackages/apps/qdrant/values.schema.jsonpackages/apps/qdrant/values.yamlpackages/system/qdrant-rd/cozyrds/qdrant.yaml
✅ Files skipped from review due to trivial changes (1)
- packages/apps/qdrant/README.md
🚧 Files skipped from review as they are similar to previous changes (6)
- packages/apps/qdrant/values.yaml
- packages/system/qdrant-rd/cozyrds/qdrant.yaml
- packages/apps/qdrant/values.schema.json
- packages/apps/qdrant/tests/certmanager_test.yaml
- packages/apps/qdrant/tests/qdrant_test.yaml
- api/apps/v1alpha1/qdrant/types.go
Aleksei Sviridkin (lexfrei)
left a comment
There was a problem hiding this comment.
NOT LGTM — TLS scaffold is mostly clean (cert chain is well-shaped, leaf usages cover both server-auth and client-auth for p2p mTLS, tls.enabled tri-state via hasKey is sound), but the SAN list cannot match the short-form pod hostnames Qdrant uses for p2p bootstrap, and there's no restart trigger when cert-manager rotates the leaf — TLS will silently break at the one-year mark.
Business context: Add TLS to the managed Qdrant service for both client REST/gRPC (6333/6334) and inter-node p2p (6335) via a self-contained cert-manager chain, with tls.enabled falling back to external when unset.
Blockers
B1: SAN list does not cover Qdrant's short-form p2p peer hostnames
File: packages/apps/qdrant/templates/certmanager.yaml:61-68
Issue: When replicas > 1, the upstream Qdrant chart starts each pod with --bootstrap '<protocol>://<release>-0.<release>-headless:6335' and --uri '<protocol>://<release>-<N>.<release>-headless:6335' (see packages/system/qdrant/charts/qdrant/templates/configmap.yaml, initialize.sh). These URIs use the short form <release>-N.<release>-headless — no .<ns>.svc.<cluster> suffix. X.509 wildcards match exactly one DNS label at the leftmost position; *.<release>-headless.<ns>.svc.<cluster> cannot match <release>-0.<release>-headless (different label count).
Evidence: configmap.yaml:initialize.sh builds the URI from qdrant.fullname + -headless — no FQDN suffix. The peer TLS client (Qdrant's tonic-based p2p) verifies the cert's SAN list against the literal URI hostname, not the post-resolution FQDN. Cert SAN list at certmanager.yaml:62-68 only covers <release>{,.<ns>.svc{,.<cluster>}}, the bare headless service plus its FQDN forms, and the wildcard *.<release>-headless.<ns>.svc.<cluster> — none of which match <release>-N.<release>-headless.
Impact: Multi-replica + TLS-enabled deployments fail to form a cluster — qdrant-1/qdrant-2/… each attempt the --bootstrap URI against qdrant-0.<release>-headless and the TLS handshake fails with a hostname-mismatch error. Single-replica deployments (the chart default) happen to work because qdrant-0's self-URI is never dialed.
Fix: Add SANs for each pod's short form. The chart already has .Values.replicas, so:
{{- range $i, $_ := until (int .Values.replicas) }}
- {{ printf "%s-%d.%s-headless" $.Release.Name $i $.Release.Name | quote }}
- {{ printf "%s-%d.%s-headless.%s.svc" $.Release.Name $i $.Release.Name $.Release.Namespace | quote }}
- {{ printf "%s-%d.%s-headless.%s.svc.%s" $.Release.Name $i $.Release.Name $.Release.Namespace $clusterDomain | quote }}
{{- end }}(Scaling up later requires reissuing the cert; alternatively use a multi-label wildcard escape via the SVID/SPIFFE-style URI SAN, but the per-replica approach is simpler.)
B2: No restart trigger on cert-manager rotation — TLS breaks silently at the cert-expiry mark
File: packages/apps/qdrant/templates/qdrant.yaml:57-65 + templates/certmanager.yaml:47-48
Issue: cert-manager rotates the leaf every ~11 months (duration: 8760h, renewBefore: 720h). Qdrant reads tls.cert/tls.key/tls.ca_cert from /qdrant/tls/ at process start and does not watch the file for changes — neither actix-web (REST) nor tonic (gRPC) hot-reloads server certs in Qdrant's current configuration. After rotation:
- kubelet syncs the new Secret content into the mounted volume (the on-disk file is fresh).
- Qdrant keeps serving with the in-memory copy of the original cert.
- At month-12, the original cert hits
notAfter. Clients now reject the handshake withcertificate has expired.
Nothing in the HelmRelease re-triggers a rolling restart when the Secret content changes — Flux's helm-controller hashes the chart artifact + HelmRelease values, not the contents of side-loaded Secrets.
Evidence: packages/system/qdrant/charts/qdrant/templates/statefulset.yaml carries checksum/config and checksum/secret annotations, but they hash configmap.yaml and secret.yaml (the API-key secret) — not the cert-manager-managed TLS Secret created by templates/certmanager.yaml. No reloader.stakater.com/* annotation is set on the pod template (cozystack ships stakater/reloader at packages/system/reloader/, so the operator is available cluster-wide).
Impact: A successfully-installed TLS-enabled Qdrant instance becomes unreachable to all clients exactly 12 months after install with no warning, until an operator manually restarts the StatefulSet. The renewBefore window helps cert-manager refresh on disk early, but does nothing because Qdrant never re-reads.
Fix: Pass an annotation that the reloader operator picks up:
{{- if $tlsEnabled }}
podAnnotations:
reloader.stakater.com/auto: "true"
{{- end }}…or pin it to the TLS secret specifically:
podAnnotations:
secret.reloader.stakater.com/reload: "{{ .Release.Name }}-tls"Upstream chart supports podAnnotations in statefulset.yaml (verified). With reloader installed cluster-side, a Secret content change will trigger a rolling restart and the new cert is loaded before the old one expires.
Non-blocking follow-ups
-
qdrant.yaml:57-69— theadditionalVolumes/additionalVolumeMountsblock is unconditionally rewritten (overwriting any value coming from thecozystack-valuesSecret, including the explicit[]reset in the TLS-disabled branch). Tenants in the standard managed flow can't reach those keys via the ApplicationDefinition surface, so the practical regression is narrow, but the chart-level habit of overwriting upstream extension points instead of appending is worth flagging — if Qdrant's user values ever need an extra mount, this will silently drop it. -
certmanager.yaml:28-29: CAprivateKeyonly setsrotationPolicy: Never, leaving algorithm/size at cert-manager defaults (RSA-2048). Leaf cert has noprivateKeyblock at all. Mariadb (#2680) and other sibling PRs pin RSA-4096 for the CA — non-uniform but not a blocker; RSA-2048 is still a sound choice for a tenant-scoped CA. -
_helpers.tpl:1-13— the tri-state implementation useshasKey $tlsMap "enabled"and relies onvalues.schema.jsonrejectingnull(sinceenabledistype: boolean, not["boolean","null"]). That's correct given the current schema but tightly coupled — a future schema relaxation tonullwould letnullreach the template as the string"<nil>"and silently flip TLS on (since neither"true"nor"false"). Worth either tightening the template (treat anything other than"true"/"false"as the external fallback) or pinning the schema with a comment thatnullis intentionally rejected.
|
Addressed your review. Blockers:
Non-blocking follow-ups:
Series-wide cleanups applied here too:
Ready for re-review. |
Aleksei Sviridkin (lexfrei)
left a comment
There was a problem hiding this comment.
LGTM. Each finding from my prior NOT LGTM on this branch is addressed in a dedicated commit:
8a426487c fix(qdrant): add per-replica short-form SANs for p2p TLS hostname verification— closes the SAN gap I flagged:initialize.shconnects peers via<release>-N.<release>-headless(no FQDN), so the per-replica short form{{ printf "%s-%d.%s-headless" $.Release.Name $i $.Release.Name }}now sits in the SAN list alongside the namespaced and FQDN variants and the wildcard.3e59b8491 feat(qdrant): trigger pod restart on TLS Secret rotation via Reloader annotation—secret.reloader.stakater.com/reload: "{{ .Release.Name }}-tls"makes Stakater Reloader bounce pods when the leaf Secret rotates (cert-manager'srotationPolicy: Always). Solves the "cert rotated but pods still hold the old material" failure mode.7544cdbf8 refactor(qdrant): switch CA and leaf private keys to ECDSA P-256+1192ae69c refactor(qdrant): use kindIs invalid pattern for tri-state tls.enabled detection+fc943ddda refactor(qdrant): extract TLS enablement logic into _helpers.tpl— modernization pass consistent with the rest of the batch.
Leaf usages [digital signature, key encipherment, server auth, client auth] ✓. dashboard RBAC exposes only <release>-apikey (no TLS Secret), so the B3 pattern doesn't apply here either. Clean.
- Extend QdrantSpec with tls.enabled tri-state bool and expose it via values.yaml and JSON schema - Update cozyrds integration to pass TLS config to the operator - Add test: Makefile target and TLS parameter documentation to README Signed-off-by: Arsolitt <arsolitt@gmail.com>
- Add certmanager.yaml to provision cert-manager Certificate and Issuer for p2p and client TLS - Extend qdrant.yaml to mount TLS secrets and configure Qdrant with TLS settings when enabled - TLS activation follows a tri-state: explicit true/false or inherit from cluster external setting Signed-off-by: Arsolitt <arsolitt@gmail.com>
- Add helm-unittest suite for cert-manager resources covering all TLS mode combinations - Add helm-unittest suite for Qdrant StatefulSet verifying TLS volume mounts and p2p behavior - Cover explicit enabled/disabled and external-inherited cases; document p2p standalone behavior Signed-off-by: Arsolitt <arsolitt@gmail.com>
Signed-off-by: Arsolitt <arsolitt@gmail.com>
Address review feedback: the TLS-enablement block was duplicated in both qdrant.yaml and certmanager.yaml. Introduce a named helper template "qdrant.tls.enabled" in _helpers.tpl and replace both inline copies with a single include call. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Arsolitt <arsolitt@gmail.com>
…ification Qdrant's upstream chart constructs bootstrap/uri using short-form pod hostnames (<release>-N.<release>-headless). The existing wildcard SAN only covered FQDN form, causing TLS handshake failures in multi-replica clusters when ca_cert peer verification is enabled. Add a range loop that emits three SAN variants per replica: - short form: <release>-N.<release>-headless - svc form: <release>-N.<release>-headless.<ns>.svc - FQDN form: <release>-N.<release>-headless.<ns>.svc.<cluster-domain> Scale-up beyond initial replicas requires cert re-issue; Reloader (see next commit) will restart pods to pick up the new cert. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Arsolitt <arsolitt@gmail.com>
… annotation cert-manager rotates the leaf cert approximately every 11 months (renewBefore: 720h, duration: 8760h). Qdrant reads tls.cert/key/ca_cert at process start and does not watch for file changes, so without a restart trigger TLS would silently break at the renewal boundary. Add a targeted Reloader annotation (secret.reloader.stakater.com/reload) pointing at the specific TLS Secret. This uses the targeted form, not the auto-watch form, to limit scope to the TLS Secret only. Reloader is installed cluster-side at packages/system/reloader. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Arsolitt <arsolitt@gmail.com>
…d detection Replace the hasKey + index approach with the canonical kindIs "invalid" check. This is the standard cozystack pattern for detecting an unset *bool field, making the helper consistent with other charts in the project. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Arsolitt <arsolitt@gmail.com>
RSA keys are unnecessarily large for internal PKI. ECDSA P-256 provides equivalent security with smaller key material, faster TLS handshakes, and smaller certificates — beneficial for high-frequency p2p connections. CA retains rotationPolicy: Never (root CA stability). Leaf uses rotationPolicy: Always (new key on every renewal). Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Arsolitt <arsolitt@gmail.com>
7544cdb to
87ad834
Compare
Aleksei Sviridkin (lexfrei)
left a comment
There was a problem hiding this comment.
LGTM — TLS via cert-manager is correctly wired for client REST/gRPC and inter-node p2p, both blockers from the earlier review (p2p short-form SANs and restart-on-rotation) are fixed and test-covered, and 58 helm-unittest cases pass.
Business context: adds TLS to the managed Qdrant service for client REST/gRPC (6333/6334) and inter-node p2p (6335) via a self-contained cert-manager chain in the tenant namespace, with tls.enabled falling back to external when unset.
Non-blocking follow-ups
- p2p SANs are enumerated for the current
replicasonly (packages/apps/qdrant/templates/certmanager.yaml:75-79). On areplicas N→Mchange the Certificate re-renders and the StatefulSet scales in the same reconcile with no ordering guarantee (podManagementPolicy: Parallel), so a new pod can attempt p2p TLS before the reissued secret propagates and reloader restarts — a transient scale-up stall, not a permanent break; fresh installs are unaffected. Optional hardening: a short-form wildcard SAN"*.{{ .Release.Name }}-headless"covers future replica names without enumeration. - CA and leaf both use ECDSA P-256 (clean within this PR); a sibling cert-manager PR pins RSA-4096 for the CA. Worth a one-line confirmation that the cross-app divergence is intentional.
- The tri-state relies on
kindIs "invalid"to detect the omitted case while the schema keepstls.enablednon-nullable (a literalnullis rejected before rendering). Sound, but tightly coupled to the schema staying non-nullable — a brief comment pinning that intent would harden it against a future schema relaxation.
| - {{ .Release.Name }}-headless.{{ .Release.Namespace }}.svc | ||
| - {{ .Release.Name }}-headless.{{ .Release.Namespace }}.svc.{{ $clusterDomain }} | ||
| - "*.{{ .Release.Name }}-headless.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}" | ||
| {{- range $i, $_ := until (int .Values.replicas) }} |
There was a problem hiding this comment.
SANs are enumerated for the current replicas only. On a replicas N→M scale-up, new pod qdrant-M-1.<release>-headless can attempt p2p TLS before the reissued secret propagates and reloader restarts — a transient stall, not a permanent break. Optional: a short-form wildcard SAN "*.{{ .Release.Name }}-headless" (X.509 wildcard matches the leftmost label) covers future replica names without enumeration. Non-blocking.
What this PR does
Adds TLS support to the Qdrant managed service via cert-manager.
tls.enabledfield with tri-state semantics: when unset, defaults to the value ofexternal(auto-on for externally published services, off for cluster-internal). Explicittls.enabledalways wins..ns.svc,.ns.svc.<cluster-domain>) plus the external hostname whenexternal: true.Verified end-to-end on a sandbox cluster: cert chain reaches Ready, TLS handshake against the tenant service succeeds with the chart CA bundle.
Release note
Summary by CodeRabbit
New Features
Documentation
Tests
Chores