Documentation
¶
Overview ¶
Package certificate provides pluggable TLSBackend abstractions for certificate management in Kubernetes operators.
It supports three backends:
- selfmanaged: generates and rotates CA + leaf certificates using Go's crypto/x509, returning them as Kubernetes Secrets for SSA apply.
- byo (bring-your-own): references an existing user-managed Secret, emitting no child objects.
- certmanager (optional subpackage): emits cert-manager Issuer/Certificate CRs and relies on cert-manager to produce the Secret.
The selfmanaged backend supports ECDSA curve selection (P-256/P-384/P-521), IP SANs, an optional CA CRL, and a renewal window; the reusable rotation saga lives in pkg/controller/certificate/rotation.
Index ¶
- Constants
- func GetValidCADays(spec TLSSpec) int
- func GetValidLeafDays(spec TLSSpec) int
- func GetValidRenewalDays(spec TLSSpec) int
- func RolloutAnnotation(shouldRollout bool, secret *corev1.Secret, currentHash string) (map[string]string, error)
- func SecretHash(secret *corev1.Secret) (string, error)
- func SecretHashAnnotation(secret *corev1.Secret) (map[string]string, error)
- func ShouldRollout(policy RolloutPolicy, sig *LayerSignals) bool
- type LayerSignals
- type LeafChange
- type LeafChangeReason
- type LeafManager
- type NodeSetTLSBackend
- type RolloutPolicy
- type TLSBackend
- type TLSSpec
- type TLSSpecProvider
- type TLSSpecProviderFunc
Constants ¶
const ( // CurveP256 is the default ECDSA curve (secp256r1). CurveP256 = "P-256" // CurveP384 selects ECDSA P-384 (secp384r1). CurveP384 = "P-384" // CurveP521 selects ECDSA P-521 (secp521r1). CurveP521 = "P-521" // DefaultRenewalDays is the renewal window before NotAfter when renewal // is triggered, used when TLSSpec.RenewalDays is not set. DefaultRenewalDays = 30 // MaxRenewalDays is the largest accepted renewal window. Values above // this are clamped down to it. This prevents integer overflow when // computing `RenewalDays * 24 * time.Hour` (a time.Duration in int64 // nanoseconds overflows around 106_752 days, which would produce a // negative window and silently disable renewal — or a huge positive // window causing perpetual renewal). 100 years is well below the // overflow threshold and far exceeds any legitimate cert validity. MaxRenewalDays = 36500 // MaxValidityDays is the largest accepted certificate validity (leaf or // CA) in days. It mirrors MaxRenewalDays: `ValidityDays * 24 * time.Hour` // (a time.Duration in int64 nanoseconds) overflows around 106_752 days, // which would either fail certificate creation or wrap to a small negative // (already-expired) NotAfter and trigger a perpetual renewal loop. 100 // years is safely below the overflow threshold and exceeds any legitimate // certificate validity. MaxValidityDays = 36500 )
const ( // AnnotationSecretHash is the annotation key used to store a stable // hash of the certificate Secret contents on pod templates. When the // Secret changes, the hash changes, triggering a natural rolling restart. AnnotationSecretHash = "operator-sdk-extra.webcenter.fr/certificate-hash" // AnnotationForceRegenerateAll triggers a full CA+leaf rotation + rollout. // Read as == "true" (the ignoreReconcile convention). Overridable via // rotation.WithForceRegenerateAllAnnotation. AnnotationForceRegenerateAll = "operator-sdk-extra.webcenter.fr/force-regenerate-tls" // AnnotationForceRegenerateLeaf triggers a leaf-only regen + rollout. AnnotationForceRegenerateLeaf = "operator-sdk-extra.webcenter.fr/force-regenerate-certificates" )
Variables ¶
This section is empty.
Functions ¶
func GetValidCADays ¶ added in v3.0.4
GetValidCADays returns the CA certificate validity in days, defaulting to 2× GetValidLeafDays when CAValidityDays <= 0. Values above MaxValidityDays are clamped down to it (see MaxValidityDays).
func GetValidLeafDays ¶ added in v3.0.4
GetValidLeafDays returns the leaf certificate validity in days, defaulting to 365 when LeafValidityDays <= 0. Values above MaxValidityDays are clamped down to it to prevent time.Duration overflow in downstream `LeafValidityDays * 24 * time.Hour` math (see MaxValidityDays).
func GetValidRenewalDays ¶ added in v3.0.4
GetValidRenewalDays returns the renewal window in days, defaulting to DefaultRenewalDays (30) when RenewalDays is not set or invalid (<= 0). Values above MaxRenewalDays are clamped to MaxRenewalDays to prevent time.Duration overflow in downstream `RenewalDays * 24 * time.Hour` math (see MaxRenewalDays).
func RolloutAnnotation ¶ added in v3.0.4
func RolloutAnnotation(shouldRollout bool, secret *corev1.Secret, currentHash string) (map[string]string, error)
RolloutAnnotation builds the pod-template annotation map entry.
- shouldRollout=true: fresh hash of secret (SecretHashAnnotation).
- shouldRollout=false and currentHash!="": keep currentHash (no restart).
- shouldRollout=false and currentHash=="" (first run): initialize hash.
func SecretHash ¶
SecretHash computes a stable SHA-256 hash of a Secret's data fields. This hash is used as a pod-template annotation so that any change to the certificate Secret forces a rolling restart of the consuming workload.
This decouples "certificate changed" from "must restart" without bespoke polling of StatefulSet.Status.CurrentReplicas.
func SecretHashAnnotation ¶
SecretHashAnnotation builds the annotation map entry for the certificate hash. The returned map is suitable for merging into a pod template's metadata.annotations.
func ShouldRollout ¶ added in v3.0.4
func ShouldRollout(policy RolloutPolicy, sig *LayerSignals) bool
ShouldRollout decides whether a pod rollout is needed for one layer's signals. Forced overrides everything, including RolloutNever.
Types ¶
type LayerSignals ¶ added in v3.0.4
type LayerSignals struct {
CARotated bool // a CA-saga started this cycle
LeafRegenerated bool // leaf regenerated (CA saga OR leaf-only)
LeafChange *LeafChange // drift/expiry detail (SAN/IP/node deltas)
Forced bool // a force annotation was honored this cycle
}
LayerSignals is the per-layer change-delta signal a TLS step publishes under data["tls.<phaseName>"] for the STS step to gate rollout.
type LeafChange ¶ added in v3.0.4
type LeafChange struct {
Reason LeafChangeReason
SANsAdded []string
SANsRemoved []string
IPsAdded []string
IPsRemoved []string
NodesAdded []string
NodesRemoved []string
}
LeafChange describes leaf drift vs spec at `now`. Delta slices are always populated (independent of Reason) so consumers can compute additive-only rollout decisions.
func (LeafChange) IsZero ¶ added in v3.0.4
func (c LeafChange) IsZero() bool
IsZero reports whether no regeneration is needed.
type LeafChangeReason ¶ added in v3.0.4
type LeafChangeReason string
LeafChangeReason is the dominant reason a leaf needs regeneration.
const ( LeafNone LeafChangeReason = "" LeafMissing LeafChangeReason = "Missing" LeafExpiring LeafChangeReason = "Expiring" LeafCNChanged LeafChangeReason = "CNChanged" LeafOrgChanged LeafChangeReason = "OrgChanged" LeafSANsChanged LeafChangeReason = "SANsChanged" LeafIPsChanged LeafChangeReason = "IPsChanged" LeafNodesChanged LeafChangeReason = "NodesChanged" LeafForceRegen LeafChangeReason = "Forced" )
type LeafManager ¶ added in v3.0.4
type LeafManager[T object.MultiPhaseObject] interface { // DesiredLeafWithCA re-issues the leaf signed by the CA in caSecret, // reusing that CA's key/cert (no new CA). The returned Secret's ca.crt // equals caSecret's ca.crt (single CA, no bundle). DesiredLeafWithCA(ctx context.Context, o T, spec TLSSpec, caSecret *corev1.Secret) (*corev1.Secret, error) // LeafNeedsChange reports whether the leaf Secret needs regeneration vs // spec at now. leafSecret may be nil (treated as LeafMissing). LeafNeedsChange(ctx context.Context, o T, leafSecret *corev1.Secret, spec TLSSpec, now time.Time) (LeafChange, error) }
LeafManager is the optional capability for saga backends that own their leaf Secret and can (a) regenerate it against an existing CA and (b) report drift. Implemented by selfmanaged (single-leaf) and selfmanaged/pernode. The rotation step type-asserts this; when absent (cert-manager/BYO) leaf-only regen is skipped and drift falls back to the full CA saga.
type NodeSetTLSBackend ¶ added in v3.0.4
type NodeSetTLSBackend[T object.MultiPhaseObject] interface { TLSBackend[T] // ExpectedNodeNames returns the node names that should have a certificate. ExpectedNodeNames(o T) ([]string, error) // NodeSecretKeys returns the Data-key suffixes for a node's cert and key // (e.g. ".crt", ".key"); a node's Data keys are name+certSuffix and // name+keySuffix. NodeSecretKeys() (certSuffix, keySuffix string) }
NodeSetTLSBackend marks per-node (multi-cert) saga backends. Its presence changes rotation data publishing (omit tlsSecret/leafCert).
type RolloutPolicy ¶ added in v3.0.4
type RolloutPolicy string
RolloutPolicy selects which change-delta signals trigger a rollout.
const ( RolloutAlways RolloutPolicy = "Always" RolloutOnCAChange RolloutPolicy = "OnCAChange" RolloutOnAdditive RolloutPolicy = "OnAdditive" // recommended default RolloutNever RolloutPolicy = "Never" )
type TLSBackend ¶
type TLSBackend[T object.MultiPhaseObject] interface { // DesiredObjects returns the child objects that the reconciler should // manage via SSA. These may be Secrets (self-managed) or cert-manager // CRs (cert-manager backend). DesiredObjects(ctx context.Context, o T, spec TLSSpec) ([]client.Object, error) // CertificateSecretName returns the name of the Secret that consumers // should mount or hash for rolling restart. CertificateSecretName(o T, spec TLSSpec) string // RequiresRotationSaga reports whether the multi-cycle CA-rotation // workflow is needed. Only the self-managed mutual-TLS backend returns // true; cert-manager and BYO backends return false. RequiresRotationSaga() bool }
TLSBackend defines the interface for pluggable certificate providers.
Each backend returns the child objects it wants the reconciler to manage via SSA, the name of the resulting certificate Secret, and whether a multi-cycle CA-rotation saga is needed.
- selfmanaged backend: returns Secret objects (CA + leaf), needs saga.
- cert-manager backend: returns Issuer/Certificate CRs, no saga needed.
- BYO backend: returns nothing, no saga needed.
type TLSSpec ¶
type TLSSpec struct {
// SecretName is the name of the Secret that will hold the certificate
// and key. Consumers mount this Secret or hash it for rollout.
SecretName string `json:"secretName,omitempty"`
// IssuerRef references an existing Issuer or ClusterIssuer for the
// cert-manager backend (existing-CA mode). When empty, a self-signed
// Issuer is created (dedicated-CA mode).
IssuerRef string `json:"issuerRef,omitempty"`
// CommonName is the CN for the generated certificate.
CommonName string `json:"commonName,omitempty"`
// DNSNames lists the SAN DNS names for the certificate.
DNSNames []string `json:"dnsNames,omitempty"`
// Organization is the O field for the certificate.
Organization string `json:"organization,omitempty"`
// LeafValidityDays is the leaf certificate validity in days.
// Defaults to 365 if not set (see GetValidLeafDays).
LeafValidityDays int `json:"leafValidityDays,omitempty"`
// CAValidityDays is the CA certificate validity in days.
// Defaults to 2× LeafValidityDays when <= 0 (see GetValidCADays).
CAValidityDays int `json:"caValidityDays,omitempty"`
// Curve selects the ECDSA curve for the selfmanaged backend.
// One of P-256 (default), P-384, P-521. Unknown values are rejected by
// the selfmanaged backend. Ignored by cert-manager.
Curve string `json:"curve,omitempty"`
// IPAddresses lists the SAN IPs for the generated certificate.
// Each entry must parse via net.ParseIP.
IPAddresses []string `json:"ipAddresses,omitempty"`
// RenewalDays is the window before expiry during which renewal is
// triggered. Defaults to 30 (see GetValidRenewalDays).
RenewalDays int `json:"renewalDays,omitempty"`
// GenerateCRL, when true, adds a ca.crl key (DER-encoded revocation
// list) to the CA Secret (selfmanaged only).
GenerateCRL bool `json:"generateCRL,omitempty"`
}
TLSSpec defines the desired (computed) TLS configuration for a component. Operators embed a SLIMMED version in their CRD spec and pass computed values to the library via a TLSSpecProvider. Backend selection is an operator decision (which backend type to construct), NOT spec data — the old SelfSigned/CertManager booleans are removed.
type TLSSpecProvider ¶ added in v3.0.4
type TLSSpecProvider[T object.MultiPhaseObject] interface { TLSSpec(o T) TLSSpec }
TLSSpecProvider supplies the computed TLSSpec for an object. The operator implements this (or uses TLSSpecProviderFunc) instead of passing a bare func to NewTLSStep.
type TLSSpecProviderFunc ¶ added in v3.0.4
type TLSSpecProviderFunc[T object.MultiPhaseObject] func(o T) TLSSpec
TLSSpecProviderFunc adapts a func(o T) TLSSpec to TLSSpecProvider.
func (TLSSpecProviderFunc[T]) TLSSpec ¶ added in v3.0.4
func (f TLSSpecProviderFunc[T]) TLSSpec(o T) TLSSpec
Directories
¶
| Path | Synopsis |
|---|---|
|
Package byo provides a TLSBackend that references an existing user-managed Secret.
|
Package byo provides a TLSBackend that references an existing user-managed Secret. |
|
Package certmanager provides a TLSBackend that emits cert-manager Issuer and Certificate custom resources.
|
Package certmanager provides a TLSBackend that emits cert-manager Issuer and Certificate custom resources. |
|
Package rotation provides a reusable multi-cycle TLS rotation saga step built on workflow.WorkflowStepReconcilerActionWithDiff.
|
Package rotation provides a reusable multi-cycle TLS rotation saga step built on workflow.WorkflowStepReconcilerActionWithDiff. |
|
Package selfmanaged provides a TLSBackend that generates and manages CA and leaf certificates using Go's crypto/x509 standard library.
|
Package selfmanaged provides a TLSBackend that generates and manages CA and leaf certificates using Go's crypto/x509 standard library. |
|
pernode
Package pernode provides a TLSBackend that keeps one certificate per node in a single Secret (multi-cert transport TLS, e.g.
|
Package pernode provides a TLSBackend that keeps one certificate per node in a single Secret (multi-cert transport TLS, e.g. |