Help us shape the future of Go! Take the 2026 Go Developer Survey

secretsource

package
v0.5.8 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package secretsource resolves a leoflow-declared Connection/Variable name from an external secret store (e.g. AWS Secrets Manager), pod-side in the agent.

The control plane never resolves an external secret: doing so would send an author-named reference over a core-identity network call, the confused-deputy class the pod boundary forecloses in advance. Resolution runs here, in the agent, under the pod's own workload identity. The resolver is only ever asked for names the DAG declared, so declaration remains the scope authority; the leoflow vault stays the chain fallback.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Backend

type Backend struct {
	// Connections and Variables mark which kinds this backend serves. A prefix
	// alone does not enable a kind (a flat namespace has an empty prefix), and a
	// zero Backend serves nothing — an unconfigured operator never accepts an
	// undeclared external name at registration.
	Connections bool
	Variables   bool

	// ConnectionsPrefix and VariablesPrefix are the provider namespaces a leoflow
	// name is resolved under, mirroring Airflow's AWS backend kwargs. Empty means a
	// flat namespace (the name maps through unchanged).
	ConnectionsPrefix string
	VariablesPrefix   string
}

Backend is an operator-configured external secret store (set via Helm, never by a DAG author). It names which kinds it serves and the prefix under which a leoflow name is found in the provider. Keeping this operator-sourced is a security invariant: the ADR 0055 D6 registration check consults Covers to accept an externally-backed declared name without a provider call, so if a DAG could supply its own Backend it could mark any name "covered" and defeat D6.

func (Backend) Covers

func (b Backend) Covers(kind Kind) bool

Covers reports whether this backend serves the given kind — the ADR 0055 D6 coverage predicate. It derives only from the operator-set enabled flags.

func (Backend) SecretID

func (b Backend) SecretID(name string, kind Kind) string

SecretID maps a leoflow-declared name to the provider secret id via the operator's prefix. The leoflow name never carries a provider path; the prefix convention lives here, in operator config.

type BackendConfig

type BackendConfig struct {
	// Class is the provider backend class the in-pod resolver subprocess
	// instantiates (e.g. the Airflow AWS SecretsManagerBackend).
	Class string
	// Kwargs is the raw backend kwargs JSON, passed to the subprocess on stdin
	// (never argv/env — a shared PID namespace makes those task-readable).
	Kwargs json.RawMessage
	// Routing is the declaration-scope predicate (Covers) + name→provider-id
	// mapping (SecretID), derived from the kwargs prefixes.
	Routing Backend
}

BackendConfig is the operator-supplied external-secrets backend configuration, read pod-side from the LEOFLOW_SECRETS_* env the control plane injects (operator only — the dispatch filter keeps an author's task env from setting LEOFLOW_ keys, #828). It is never author-influenced.

func ParseBackendConfig

func ParseBackendConfig(class, kwargsJSON string) (cfg BackendConfig, enabled bool, err error)

ParseBackendConfig builds the operator backend config from the class name and raw kwargs JSON. enabled is false when no class is set (no external backend → the resolver is never built and the chain is vault-only). A kind is covered iff its `*_prefix` kwarg is present, mirroring Airflow's enable-by-prefix. Malformed kwargs JSON is an error (fail closed at config time, not at resolve time).

type BatchResolver

type BatchResolver interface {
	ResolveBatch(ctx context.Context, refs []Ref) (map[Ref]string, error)
}

BatchResolver resolves many declared names in a single call. The 2b in-pod resolver pays a heavy per-invocation startup (a Python/Airflow subprocess), so it must batch rather than spawn once per name. A resolver may implement both interfaces; the chain prefers ResolveBatch when available. The returned map holds only the hits (a clean miss is an omission → the vault fallback stands); a non-nil error is a hard failure the caller fails closed on.

type Kind

type Kind int

Kind distinguishes a connection (resolves to an Airflow connection URI) from a variable (resolves to a scalar value). The resolver learns only the leoflow-declared name and its kind — never a provider path, ARN, or mount.

const (
	// KindConnection resolves to a rendered Airflow connection URI.
	KindConnection Kind = iota
	// KindVariable resolves to a scalar variable value.
	KindVariable
)

type NoOp

type NoOp struct{}

NoOp is the default resolver, used when no external backend is configured. It resolves nothing, so the chain falls through to the vault — behavior identical to the pre-ADR-0060 env-export path. A DAG that declares no external backend gets byte-identical secrets delivery.

func (NoOp) Resolve

func (NoOp) Resolve(_ context.Context, _ string, _ Kind) (value string, found bool, err error)

Resolve always reports a clean miss.

type Ref

type Ref struct {
	Name string
	Kind Kind
}

Ref identifies one declared secret to resolve: its leoflow name and kind.

type SecretResolver

type SecretResolver interface {
	Resolve(ctx context.Context, name string, kind Kind) (value string, found bool, err error)
}

SecretResolver resolves one leoflow-declared name to its value using an identity the pod already carries. It never receives credentials, a provider path, or an ARN — those live in the adapter's operator-supplied config, bound to the pod's workload identity.

Resolve returns (value, found, err). found=false is a clean miss: the caller falls through to the next link in the chain (the leoflow vault). A non-nil err is a hard failure (access denied, throttle, malformed value); the caller fails closed for a required name rather than masking it.

Jump to

Keyboard shortcuts

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