cluster

package
v0.16.2 Latest Latest
Warning

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

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

Documentation

Overview

Package cluster implements the in-cluster secret backend.

It is the counterpart to the external managers RFD-90 anticipates: the same reference model, but Miren holds the value. A team gets a secret store without standing up Vault first, and because Miren owns retention a pinned version is guaranteed to stay resolvable rather than being pruned out from under a deploy.

Secrets are modeled the way config already is — a stable identity plus immutable versions — so the secret value stops being the one floating input in an otherwise fully-pinned deploy record. Each version is independently envelope-encrypted, so nothing sits in etcd in plaintext and the value exists only transiently, in memory, during a resolve.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ValidatePath

func ValidatePath(path string) error

ValidatePath reports whether a path is addressable in the cluster backend. External backends address secrets in shapes Miren does not control, so this constrains only paths the cluster itself stores.

Types

type Backend

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

Backend stores secret values inside the cluster's entity store.

func NewBackend

func NewBackend(log *slog.Logger, ec *entityserver.Client, ring *keyring.Keyring) *Backend

NewBackend builds the in-cluster backend over an entity store and the cluster's keyring.

func (*Backend) CountOnKey

func (b *Backend) CountOnKey(ctx context.Context, kekID string) (int, error)

CountOnKey reports how many stored versions are still wrapped by a given key.

This is what decides when a retiring key can be dropped: while it is above zero, retiring the key would strand those versions with nothing able to unwrap them. kek_id is indexed, so this is a single lookup rather than a scan of every secret.

func (*Backend) Keyring

func (b *Backend) Keyring() *keyring.Keyring

Keyring returns the ring currently in use.

func (*Backend) KeyringReport

func (b *Backend) KeyringReport(ctx context.Context) (secret.KeyringReport, error)

KeyringReport describes the cluster's keys and any rotation in flight.

The per-key version count is what makes rotation legible: a non-current key with versions still on it is a backfill that has not finished, and is exactly why that key cannot be dropped yet.

func (*Backend) List

func (b *Backend) List(ctx context.Context) ([]secret.Summary, error)

List returns every secret the cluster holds, with its versions, and never a value. An operator uses it to see the blast radius of a rotation or a revocation before acting.

func (*Backend) ListVersions

func (b *Backend) ListVersions(ctx context.Context, path string) (secret.Summary, error)

ListVersions returns one secret's versions, without their values.

func (*Backend) Name

func (b *Backend) Name() string

Name returns the instance name this backend registers under.

func (*Backend) Put

func (b *Backend) Put(ctx context.Context, path string, value []byte) (string, bool, error)

Put stores a new version of the secret at path, reporting whether it reused the current version instead of minting a new one.

The reuse check is a keyed-hash comparison, not a decrypt-and-compare, so a re-run of the same `secret set` does not churn a new version and invalidate every pin — and does not need the value to be readable to notice. Reporting it from here rather than leaving the caller to compare handles is what keeps the answer honest under a concurrent rotation.

func (*Backend) Resolve

func (b *Backend) Resolve(ctx context.Context, ref string) (secret.SecretValue, error)

Resolve returns the value for a backend-relative reference along with the fully-qualified reference it resolved to.

A version-less reference tracks the secret's current version; a pinned one holds exactly what it names. Either way the returned Ref carries a concrete version, so a ConfigVersion that records it sees identical bytes on every later resolve.

func (*Backend) RewrapBatch

func (b *Backend) RewrapBatch(ctx context.Context, kekID string, limit int) (int, error)

RewrapBatch moves up to limit versions off kekID and onto the ring's current key, returning how many it moved.

The work is defined by a query rather than a cursor — "versions still on the old key" — so it needs no progress bookkeeping. An interrupted backfill resumes simply by asking again, and a version rewrapped twice is a no-op. That matters because the alternative, tracking position, is state that can disagree with reality after a crash.

Only wrapped_dek and kek_id change. The ciphertext is never rewritten, so the cost per version is a few dozen bytes regardless of how large the secret is, and a value cannot be corrupted by a partially applied rewrap.

func (*Backend) SetState

func (b *Backend) SetState(ctx context.Context, ref string, state secret.VersionState) error

SetState transitions a specific version between enabled, disabled and destroyed. Destroying additionally drops the payload, so the value is gone rather than merely unreachable.

The reference must name a version: a state change is always about one version, and letting it float would make "disable the current one" a different secret depending on when it ran.

func (*Backend) UseKeyring

func (b *Backend) UseKeyring(ring *keyring.Keyring)

UseKeyring swaps in a new ring, after which writes seal with its current key.

The caller must have persisted the ring before calling this. Sealing with a key that is not yet on disk means a crash leaves rows naming a key the cluster no longer has, and there is nothing to recover them from.

Jump to

Keyboard shortcuts

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