kms

package
v0.0.7 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 28 Imported by: 0

Documentation

Overview

Package kms connects the secret store's keyring to an external key-management service (Task 20433).

The keyring (pkg/secretbroker) can hold a key-encryption key wrapped by a KMS instead of deriving it from CLOOP_SECRET_KEY: the record keeps only the KMS's ciphertext and key id, and opening the store is a call to the KMS — a call the KMS logs and its owner can refuse. This package is the other end of that call. It implements secretbroker.KMS twice:

  • kmsv2: the Kubernetes KMS v2 plugin protocol, gRPC over a unix socket. The API server's own envelope encryption speaks it, so one integration reaches Azure Key Vault, AWS KMS, Google Cloud KMS and Vault through the plugins those vendors already ship — deployed as a sidecar beside the hub in the Helm chart. The client is the generated k8s.io/kms/apis/v2 one, so the hub speaks the protocol exactly as kube-apiserver does.
  • transit: HashiCorp Vault's, or OpenBao's, Transit engine over HTTPS, for a hub with a Vault and no plugin to run.

What the KMS sees

Thirty-two bytes of key-encryption key on the way in to Encrypt, and the ciphertext on the way in to Decrypt. Never a secret, a data key, or a payload: those stay sealed under the KEK in the hub's database. The KMS can therefore not read the store, and the store cannot be read without it.

Every call is measured

Each call records cloop_kms_requests_total{backend,operation,result} and cloop_kms_request_duration_seconds{backend,operation}, whatever it returns, so a slow or failing KMS shows on the hub's metrics before it shows as a store that will not open.

Index

Constants

View Source
const (
	OpStatus  = "status"
	OpEncrypt = "encrypt"
	OpDecrypt = "decrypt"
	// OpLogin is a Vault login (the Kubernetes auth method).
	OpLogin = "login"
)

Operations, as the metrics label them.

View Source
const (
	ResultOK          = "ok"
	ResultUnavailable = "unavailable" // could not reach the KMS, or it said it is not serving
	ResultTimeout     = "timeout"     // no answer within the configured timeout
	ResultDenied      = "denied"      // the KMS refused this identity
	ResultInvalid     = "invalid"     // the KMS refused the request: a wrong key, a ciphertext it does not hold
	ResultError       = "error"       // anything else, a malformed answer included
)

Results, as the metrics label them. A closed set: every error a provider returns is classified into one of these.

Variables

This section is empty.

Functions

func Resolver

Resolver returns a secretbroker.RootResolver for a command's secrets section: the roots are built on first use, once, so a command that never opens the store never builds a KMS client, let alone calls one.

func Unreachable

func Unreachable(err error) bool

Unreachable reports whether err says a KMS could not be reached or did not answer — the KMS may be fine and merely absent — rather than that it answered and refused.

Types

type Error

type Error struct {
	KMS    string
	Op     string
	Result string
	Err    error
}

Error is a failed KMS call: which KMS, which operation, how it was classified, and what it said. It wraps secretbroker.ErrKMSUnavailable when the KMS could not be reached or did not answer in time, so the keyring tells an outage from a refusal without knowing this package.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() []error

type Provider

type Provider interface {
	secretbroker.KMS
	secretbroker.KMSKeyReporter
	// Kind is config.KMSProviderKMSv2 or config.KMSProviderTransit.
	Kind() string
	// Status asks the KMS whether it is serving and which key it encrypts
	// under. Cheap enough to poll: it is what kube-apiserver polls.
	Status(ctx context.Context) (Status, error)
	// Describe says where the KMS is, for a message: the socket, or the
	// server and key. Never a token.
	Describe() string
	// Close releases the provider's connection.
	Close() error
}

Provider is one configured KMS key.

func Open

func Open(cfg config.KMSConfig) (Provider, error)

Open builds the provider a KMS block describes. It does not connect: the first call does, so a command that never opens the store never talks to the KMS. Call config.ValidateSecrets first; Open re-checks only what it needs.

type Roots

type Roots struct {
	Current  secretbroker.Root
	Previous secretbroker.Root
	// Providers are the KMSs among them, current first.
	Providers []Provider
}

Roots are the keyring's roots, and the providers behind any that are KMSs.

func Resolve

func Resolve(sc config.SecretsConfig, keys rootkey.Roots) (Roots, error)

Resolve builds the keyring's roots from the secrets section and the root key pkg/rootkey resolved. It connects to nothing; AwaitReady does.

func (Roots) Close

func (r Roots) Close()

Close releases every provider.

func (Roots) UsesKMS

func (r Roots) UsesKMS() bool

UsesKMS reports whether either root is a KMS.

type Status

type Status struct {
	// Healthy: the KMS answered and says it is serving.
	Healthy bool `json:"healthy"`
	// Healthz is a KMS v2 plugin's health string ("ok" when healthy).
	Healthz string `json:"healthz,omitempty"`
	// KeyID is the key it encrypts under now; a change is a rotation of the
	// KMS key, after which the hub rewraps (secretbroker.Keyring.RewrapKMS).
	KeyID string `json:"key_id,omitempty"`
	// Version is a KMS v2 plugin's protocol version.
	Version string `json:"version,omitempty"`
}

Status is what a KMS says about itself.

func AwaitReady

func AwaitReady(ctx context.Context, providers []Provider, timeout time.Duration,
	logf func(format string, args ...any)) ([]Status, error)

AwaitReady waits until every provider answers Status healthy, for at most timeout, polling with a short backoff, and returns the statuses. It returns the last failure when the time runs out, naming the KMS and why — which is what `cloop ui` refuses to start with. A timeout of zero asks once.

logf, when not nil, is told what is being waited for, at most every few seconds, so a hub whose plugin sidecar is still starting says so.

Directories

Path Synopsis
Package kmstest provides in-repo stand-ins for the key-management services pkg/kms speaks to (Task 20433): a Kubernetes KMS v2 plugin served over a real unix socket with the protocol's own generated server stubs, and a Vault Transit server over HTTP on loopback.
Package kmstest provides in-repo stand-ins for the key-management services pkg/kms speaks to (Task 20433): a Kubernetes KMS v2 plugin served over a real unix socket with the protocol's own generated server stubs, and a Vault Transit server over HTTP on loopback.

Jump to

Keyboard shortcuts

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