feat(kubernetes): let CDI trust a self-hosted Talos image factory - #3797
Fedor Batonogov (batonogov) wants to merge 1 commit into
Conversation
talos.imageFactoryURL is documented for self-hosted factories and mirrors in air-gapped, rate-limited or flaky-egress environments. Such an endpoint is normally served with a certificate from an internal CA, and CDI — which trusts only its system store — refuses the import with "x509: certificate signed by unknown authority". The DataVolume never completes, no worker joins, and the release sits in install until it times out. DataVolume.spec.source.http.certConfigMap exists for exactly this, but the chart rendered source.http.url alone and no value reached the field. Add an optional talos.imageFactoryCA taking the CA in PEM form. When set, the chart renders it into a ConfigMap in the release namespace — CDI requires certConfigMap to sit alongside the DataVolume — and references it from the worker DataVolume. When empty, nothing is rendered and the output is byte-for-byte what it was. CDI appends the bundle to the system pool rather than replacing it, so a release pulling from a publicly-trusted endpoint keeps verifying either way. The value is emitted verbatim into a ConfigMap readable by anything that can read the namespace, so the helper fails closed on private key material and on anything that is not complete PEM certificate blocks. Assisted-By: Claude <[email protected]> Signed-off-by: Fedor Batonogov <[email protected]>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughThe Kubernetes application adds an optional ChangesTalos Image Factory CA
Estimated code review effort: 3 (Moderate) | ~20 minutes Mergeability Score: ⚪ Minimal · up to This PR adds optional support for internal CA certificates while preserving existing behavior when unset. No actionable merge-blocking risk remains after normal checks and review. Sequence Diagram(s)sequenceDiagram
participant ChartValues
participant HelmTemplates
participant CAConfigMap
participant TalosDataVolume
participant CDI
ChartValues->>HelmTemplates: Provide talos.imageFactoryCA
HelmTemplates->>HelmTemplates: Validate and trim PEM certificates
HelmTemplates->>CAConfigMap: Render ca.pem
HelmTemplates->>TalosDataVolume: Set source.http.certConfigMap
TalosDataVolume->>CDI: Supply image URL and CA ConfigMap
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 |
What this PR does
Adds
talos.imageFactoryCAto thekuberneteschart, so CDI can verify a Talos Image Factory served with a certificate from an internal CA. Fixes #3796.The gap
talos.imageFactoryURLis documented for self-hosted factories and mirrors in "air-gapped, rate-limited, or flaky-egress environments". In such an environment the endpoint is normally served by the organisation's own CA, and CDI — trusting only its system store — refuses the import withx509: certificate signed by unknown authority. The DataVolume never completes, no worker joins, and the release sits in install until it times out.DataVolume.spec.source.http.certConfigMapexists for exactly this and has since the beginning. The chart just never filled it in:templates/cluster.yamlrenderedurlalone, and no value reached the field.certConfigMapappears nowhere in this repository.The change
One optional value on the existing
talosgroup:Set, it renders a ConfigMap in the release namespace and points the DataVolume at it. Empty — the default — renders no ConfigMap, no
certConfigMapkey, and no volume: I diffedhelm templateagainstmainwith the field unset and the output is identical byte for byte.Why the PEM rather than a ConfigMap name
certConfigMapmust live in the DataVolume's namespace, so a name-only field would ask the user to create an object in the tenant namespace by hand — which the dashboard offers no path for, and which splits one decision across two places in a GitOps repository. Taking the PEM keeps it inside the application's values like every other setting. A name-reference variant is a small change from here if maintainers prefer it.Why this cannot break an existing release
CDI appends the bundle to the system pool rather than replacing it —
x509.SystemCertPool()followed byAppendCertsFromPEMover every file in the mounted directory (pkg/importer/http-datasource.go). A release that also pulls from a publicly-trusted endpoint keeps verifying. This is the same distinction #3385 drew betweenSSL_CERT_DIRandAWS_CA_BUNDLE.The field is optional with an empty default, so
values.schema.jsongains a property and norequiredentry.Fail-closed guards
The value is emitted verbatim into a ConfigMap that anything able to read the namespace can read, so the helper refuses private key material and anything that is not complete PEM certificate blocks — including the realistic accident of
cat ca.pem key.pempasted into the field, where a valid leading certificate must not carry a trailing key through.Those rules restate the ones in
cozy-lib.tls.caCertSecret. I kept them local so the failure namestalos.imageFactoryCArather than that helper'scaCertparameter, and because the object here is a ConfigMap consumed by CDI in-namespace rather than a tenant-published trust anchor. If you would rather have one shared guard incozy-lib, say so and I will extract it.A non-string value is not guarded in the template —
values.schema.jsonrejects it before rendering starts.Testing
tests/talos_image_factory_ca_test.yaml, 11 cases: unset renders nothing on both sides; set renders the ConfigMap and acertConfigMapnaming it; a whitespace-only value counts as unset; multi-certificate chains work; and each guard is pinned on the input that trips it. Full suite for the package: 216 passed.make generaterun in the package; regeneratedvalues.schema.json,README.md,api/apps/v1alpha1/kubernetes/types.goand thekubernetes-rdCRD are committed.Not yet exercised end-to-end against a live internal factory — I can report back once it has been.
Not in this PR
packages/apps/vm-disk/templates/dv.yamlrenderssource.http.urlwith the same gap. Left alone to keep this reviewable; happy to follow up if this shape is accepted.Screenshots
Not a UI change.
Downstream repositories
Walked the trigger map against the diff:
packages/apps/kubernetes/values.schema.json, which the trigger map names directly ("Add, remove or rename a field in an app'svalues.schema.json→ the schema, the model, and the expand/flatten pair"). Filed as an issue rather than a PR there, matching the existing Move kubeapps cache reloading logic out ofinstaller.sh#19 / Rolling update for Talos nodes #20 / Fix gitignore #26 pattern for upstream field additions.README.mdby the release bot, and thatREADME.mdis regenerated and committed here.hack/move, noApplicationDefinitionchange, no namespace or variant rename, no installer or platform values key, no telemetry metric, no annotation or label contract.Release note
Summary by CodeRabbit
New Features
talos.imageFactoryCAconfiguration for providing PEM CA certificates.Tests