certmanager

package
v1.2.0-main Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 29, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

certificate_reconciler.go

Index

Constants

View Source
const (
	DefaultRequeueDelay = 10 * time.Second
	DefaultBundleName   = "default"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type BundleOption

type BundleOption func(*bundle) error

func WithConfigProvider

func WithConfigProvider(cp ConfigProvider) BundleOption

WithConfigProvider registers a ConfigProvider in the bundle.

func WithProvisionerFactory

func WithProvisionerFactory(pf ProvisionerFactory) BundleOption

WithProvisionerFactory registers a provisioner factory.

func WithRenewalDisabled

func WithRenewalDisabled() BundleOption

WithRenewalDisabled disables time-based renewal for all certificates in the bundle. Initial provisioning and reconciliation on config changes still occur.

func WithStorageFactory

func WithStorageFactory(sf StorageFactory) BundleOption

WithStorageFactory registers a storage factory.

type BundleProvider

type BundleProvider interface {
	// Name returns the unique, stable identifier of the bundle.
	Name() string

	// Configs returns the configuration sources that belong to this bundle.
	Configs() map[string]ConfigProvider

	// Provisioners returns the provisioner factories allowed for this bundle,
	// keyed by provisioner type.
	Provisioners() map[string]ProvisionerFactory

	// Storages returns the storage factories allowed for this bundle,
	// keyed by storage type.
	Storages() map[string]StorageFactory

	// DisableRenewal disables time-based renewal for all certificates produced by
	// config providers in this bundle.
	DisableRenewal() bool
}

BundleProvider defines a capability boundary for certificate management.

A bundle groups one or more configuration sources together with the provisioner and storage factories those configurations are allowed to reference.

All CertificateConfig objects returned by the bundle's ConfigProviders must reference only provisioner and storage types that are present in the same bundle.

Bundles are immutable by contract: implementations must return stable data for the lifetime of the bundle.

func NewBundle

func NewBundle(name string, opts ...BundleOption) (BundleProvider, error)

NewBundle constructs a bundle with the given name and options.

type CertManager

type CertManager struct {
	// contains filtered or unexported fields
}

CertManager manages the complete certificate lifecycle for flight control agents.

func NewManager

func NewManager(ctx context.Context, log Logger, opts ...ManagerOption) (*CertManager, error)

NewManager creates and initializes a new CertManager with the provided options.

func (*CertManager) Run

func (cm *CertManager) Run(ctx context.Context, interval time.Duration)

Run is an OPTIONAL convenience helper that periodically calls Sync(ctx) until the context is canceled.

Typical usage:

go cm.Run(ctx, 30*time.Second)

Or manual control:

_ = cm.Sync(ctx)
_ = cm.SyncBundle(ctx, "default")

func (*CertManager) Sync

func (cm *CertManager) Sync(ctx context.Context) error

Sync performs a full synchronization of all certificate providers.

func (*CertManager) SyncBundle

func (cm *CertManager) SyncBundle(ctx context.Context, bundleName string) error

SyncBundle performs a synchronization for a single bundle by name.

type CertificateConfig

type CertificateConfig struct {
	// Unique certificate identifier
	Name string `json:"name"`
	// Provisioner configuration
	Provisioner ProvisionerConfig `json:"provisioner"`
	// Storage configuration
	Storage StorageConfig `json:"storage"`
	// RenewBefore controls how long before NotAfter we should renew
	//
	// If set and valid (0 < RenewBefore < cert lifetime), it takes precedence over RenewBeforePercentage.
	// If invalid, it is ignored and RenewBeforePercentage (if valid) may be used.
	RenewBefore *time.Duration `json:"renewBefore,omitempty"`
	// RenewBeforePercentage controls how far through the certificate lifetime we renew, expressed
	// as a percentage of the lifetime. Valid range: (0,100)
	//
	// Example: 50 means renew when 50% of the lifetime remains (i.e., halfway through lifetime).
	// If RenewBefore is set and valid, RenewBeforePercentage is ignored.
	RenewBeforePercentage *int32 `json:"renewBeforePercentage,omitempty"`
}

CertificateConfig defines the complete configuration for a managed certificate. It includes provisioner settings, storage configuration, and renewal policies.

func (CertificateConfig) Equal

func (c CertificateConfig) Equal(other CertificateConfig) bool

Equal compares two CertificateConfig instances for semantic equality.

Two configs are considered equal if they describe the same certificate intent:

  • Same certificate name
  • Same provisioner type and configuration
  • Same storage type and configuration

Note: Renewal policy fields (e.g. RenewBeforeExpiry) are intentionally ignored; they affect *when* to renew, not whether provisioner/storage intent changed.

func (CertificateConfig) IsEmpty

func (c CertificateConfig) IsEmpty() bool

IsEmpty reports whether this CertificateConfig is the zero-value configuration.

type CertificateInfo

type CertificateInfo struct {
	// Certificate validity start time
	NotBefore *time.Time `json:"not_before,omitempty"`
	// Certificate validity end time (expiration)
	NotAfter *time.Time `json:"not_after,omitempty"`
}

CertificateInfo contains parsed certificate metadata.

type CertificateReconciler

type CertificateReconciler struct {
	// contains filtered or unexported fields
}

CertificateReconciler manages certificate reconcile tasks and retries, and prevents duplicate concurrent processing for the same (providerKey, certName).

Semantics:

  • Key is (providerKey, cert.Name).
  • Enqueue replaces any existing in-flight item for the same key (cancel+drop).
  • The underlying RetryQueue worker is sequential; handler is not called in parallel.

func (*CertificateReconciler) Enqueue

func (r *CertificateReconciler) Enqueue(bundleName, providerKey string, cert *certificate, cfg CertificateConfig) error

Enqueue schedules (or replaces) a reconcile item.

providerKey is expected to already be stable and bundle-namespaced. bundleName is retained for capability boundary / lookup in the handler.

func (*CertificateReconciler) Get

func (r *CertificateReconciler) Get(providerKey, certName string) (*certificate, CertificateConfig)

Get returns the currently tracked certificate/config for a key. If not present, returns (nil, CertificateConfig{}).

func (*CertificateReconciler) IsProcessing

func (r *CertificateReconciler) IsProcessing(providerKey, certName string) bool

IsProcessing reports whether (providerKey, certName) is currently tracked.

func (*CertificateReconciler) Len

func (r *CertificateReconciler) Len() int

Len returns the number of currently tracked in-flight items.

func (*CertificateReconciler) Remove

func (r *CertificateReconciler) Remove(providerKey, certName string)

Remove cancels and removes the tracked item if it exists.

func (*CertificateReconciler) Run

Run starts the underlying worker and binds the reconciler lifetime to ctx. Call in a goroutine.

type ConfigProvider

type ConfigProvider interface {
	// Name returns a unique identifier for this configuration provider
	Name() string
	// GetCertificateConfigs returns all certificate configurations from this provider
	GetCertificateConfigs() ([]CertificateConfig, error)
}

ConfigProvider supplies certificate configurations from various sources. It provides certificate configurations and optionally supports change notifications.

type HandlerFunc

type HandlerFunc[T any] func(ctx context.Context, item T, attempt int) *time.Duration

HandlerFunc defines a processing function for each item in the retry queue.

attempt is 0 on the first invocation.

Return value semantics:

  • nil: processing is complete; do not retry
  • non-nil: requeue the item after the returned delay (<=0 means immediate)

type Logger

type Logger interface {
	Info(args ...any)
	Warn(args ...any)
	Error(args ...any)
	Debug(args ...any)
	Infof(format string, args ...any)
	Warnf(format string, args ...any)
	Errorf(format string, args ...any)
	Debugf(format string, args ...any)
}

Logger provides a logging interface for certificate management operations. It supports different log levels for debugging, monitoring, and error reporting.

type ManagerOption

type ManagerOption func(*CertManager) error

ManagerOption defines a functional option for configuring CertManager during initialization.

func WithBundleProvider

func WithBundleProvider(bp BundleProvider) ManagerOption

WithBundleProvider registers a bundle during CertManager construction.

type ProvisionRequest

type ProvisionRequest struct {
	Desired     CertificateConfig
	LastApplied CertificateConfig

	// Attempt is the 1-based attempt number for the current provisioning cycle.
	// The manager increments this when retrying after Ready == false or transient errors.
	Attempt int
}

ProvisionRequest describes a single provisioning attempt for a certificate.

Desired is the target configuration we want to end up with.

LastApplied is the previously applied configuration known to the manager at the time of this call.

If LastApplied.IsEmpty(), the Provisioner MUST treat the previous state as unknown.

type ProvisionResult

type ProvisionResult struct {
	// Ready indicates whether the certificate is fully provisioned.
	// If false, the caller should retry after RequeueAfter.
	Ready bool

	// Cert contains the provisioned X.509 certificate in PEM form.
	//
	// MUST be non-nil when Ready == true.
	// MUST be nil when Ready == false.
	Cert []byte

	// Key contains the private key material in PEM form, if exportable.
	//
	// Key MAY be nil even when Ready == true, to support non-exportable keys
	// (e.g. TPM-backed or HSM-backed keys).
	//
	// Storage providers MUST tolerate Key == nil.
	Key []byte

	// RequeueAfter specifies how long to wait before retrying provisioning
	// when Ready == false.
	//
	// If <= 0, the manager will apply DefaultRequeueDelay.
	RequeueAfter time.Duration

	// Meta carries optional, opaque data produced by the provisioner.
	//
	// This is intended for provisioner-to-storage handoff or other internal coordination.
	// Keys SHOULD be namespaced to avoid collisions.
	//
	// Values are opaque bytes and must be interpreted only by components that
	// explicitly understand them.
	//
	// Meta SHOULD be ignored when Ready == false.
	Meta map[string][]byte
}

ProvisionResult describes the outcome of a single provisioning attempt.

type ProvisionerConfig

type ProvisionerConfig struct {
	// Provisioner type identifier (e.g., "csr", "self-signed")
	Type ProvisionerType `json:"type,omitempty"`
	// Type-specific configuration as JSON
	Config json.RawMessage `json:"config,omitempty"`
}

ProvisionerConfig defines provisioner configuration including type and type-specific settings.

func (ProvisionerConfig) Equal

func (c ProvisionerConfig) Equal(other ProvisionerConfig) bool

Equal compares two ProvisionerConfig instances for equality. This checks both the type and the type-specific configuration.

func (ProvisionerConfig) IsEmpty

func (c ProvisionerConfig) IsEmpty() bool

IsEmpty reports whether this ProvisionerConfig is the zero-value configuration.

type ProvisionerFactory

type ProvisionerFactory interface {
	// Type returns the provisioner type identifier (e.g., "csr", "self-signed")
	Type() string
	// New creates a new provisioner instance from the certificate configuration
	New(log Logger, cc CertificateConfig) (ProvisionerProvider, error)
	// Validate checks if the certificate configuration is valid for this provisioner type
	Validate(log Logger, cc CertificateConfig) error
}

ProvisionerFactory creates provisioner instances for a specific provisioner type. It provides validation and instantiation of provisioners based on certificate configuration.

type ProvisionerProvider

type ProvisionerProvider interface {
	// Provision performs a single provisioning step.
	//
	// It MUST be safe to call multiple times.
	//
	// Contract:
	//   - If result.Ready == true:
	//       - result.Cert MUST be non-nil
	//       - result.Key MAY be nil (non-exportable key)
	//       - result.RequeueAfter is ignored
	//   - If result.Ready == false:
	//       - result.RequeueAfter controls retry timing (<=0 means "use manager default")
	//       - result.Cert, result.Key, and result.Meta are ignored.
	//
	// Returning a non-nil error indicates a hard failure and aborts the current provisioning attempt.
	// If err == nil, result MUST be non-nil.
	Provision(ctx context.Context, req ProvisionRequest) (*ProvisionResult, error)
}

ProvisionerProvider handles certificate provisioning operations.

Provisioners may be synchronous or asynchronous. They decide readiness and retry timing (e.g. exponential backoff, polling an external CA, waiting for approval).

type ProvisionerType

type ProvisionerType string

ProvisionerType represents the type identifier for a certificate provisioner. Use the provided constants instead of raw string literals.

type RetryQueue

type RetryQueue[T any] struct {
	// contains filtered or unexported fields
}

RetryQueue processes items sequentially using a handler function and supports delayed retries. Single worker goroutine; no goroutine-per-retry.

func (*RetryQueue[T]) Add

func (q *RetryQueue[T]) Add(item T)

Add inserts a new item into the queue with attempt 0, due immediately.

func (*RetryQueue[T]) RunWorker

func (q *RetryQueue[T]) RunWorker(ctx context.Context)

RunWorker runs the retry queue worker loop until ctx is canceled. Items are processed sequentially. Retries are scheduled via heap + a single timer.

type StorageConfig

type StorageConfig struct {
	// Storage type identifier (e.g., "filesystem")
	Type StorageType `json:"type,omitempty"`
	// Type-specific configuration as JSON
	Config json.RawMessage `json:"config,omitempty"`
}

StorageConfig defines storage provider configuration including type and type-specific settings.

func (StorageConfig) Equal

func (c StorageConfig) Equal(other StorageConfig) bool

Equal compares two StorageConfig instances for equality. This checks both the type and the type-specific configuration.

func (StorageConfig) IsEmpty

func (c StorageConfig) IsEmpty() bool

IsEmpty reports whether this StorageConfig is the zero-value configuration.

type StorageFactory

type StorageFactory interface {
	// Type returns the storage type identifier (e.g., "filesystem", "empty")
	Type() string
	// New creates a new storage instance from the certificate configuration
	New(log Logger, cc CertificateConfig) (StorageProvider, error)
	// Validate checks if the certificate configuration is valid for this storage type
	Validate(log Logger, cc CertificateConfig) error
}

StorageFactory creates storage instances for a specific storage type. It provides validation and instantiation of storage providers based on certificate configuration.

type StorageProvider

type StorageProvider interface {
	// Store persists provisioned material according to the desired configuration.
	//
	// The storage implementation MUST:
	//   - Persist req.Result.Cert.
	//   - Persist req.Result.Key if applicable for this storage backend.
	//
	// The storage implementation MAY:
	//   - Use req.LastApplied to perform best-effort cleanup or migration.
	//
	// If req.LastApplied.IsEmpty(), the previous state MUST be treated as unknown
	// and no cleanup or migration should be attempted.
	Store(ctx context.Context, req StoreRequest) error

	// LoadCertificate loads an existing certificate if present.
	//
	// Returning (nil, nil) indicates that no certificate is currently stored.
	LoadCertificate(ctx context.Context) (*x509.Certificate, error)
}

StorageProvider handles certificate storage operations.

Storage implementations are responsible for persisting provisioned material and MAY perform best-effort cleanup or migration based on configuration changes.

The certificate manager does NOT perform storage-level cleanup itself.

type StorageType

type StorageType string

StorageType represents the type identifier for a certificate storage backend. Use the provided constants instead of raw string literals.

type StoreRequest

type StoreRequest struct {
	Result      *ProvisionResult
	Desired     StorageConfig
	LastApplied StorageConfig
}

StoreRequest describes what should be persisted and where.

Desired and LastApplied are the storage configurations for this certificate. If LastApplied.IsEmpty(), the storage MUST treat the previous state as unknown.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL