Documentation
¶
Overview ¶
Package secrets provides the core types and URI parser for secret provider integration in audit.
Secret references use the syntax ref+SCHEME://PATH#KEY, following the vals convention. When a YAML config value contains a ref URI, the outputconfig package resolves it by looking up the registered provider for the scheme and calling [Provider.Resolve].
This package is stdlib-only and defines only the interface, ref parser, and sentinel errors. Concrete provider implementations (OpenBao, Vault) live in separate sub-modules.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrMalformedRef indicates a string starts with "ref+" but is // structurally invalid (missing scheme, path, key, or contains // path traversal). ErrMalformedRef = errors.New("audit/secrets: malformed secret reference") // ErrProviderNotRegistered indicates no provider is registered // for the scheme in a ref URI. ErrProviderNotRegistered = errors.New("audit/secrets: no provider registered for scheme") // ErrSecretNotFound indicates the secret path exists but the // requested key was not found. ErrSecretNotFound = errors.New("audit/secrets: secret not found at path") // ErrSecretResolveFailed indicates a transient or permanent // failure during secret resolution (network error, auth failure). ErrSecretResolveFailed = errors.New("audit/secrets: secret resolution failed") // ErrUnresolvedRef indicates that after all resolution passes, a // string in the config still contains a ref+ URI. ErrUnresolvedRef = errors.New("audit/secrets: unresolved secret reference in config") )
Sentinel errors for secret provider operations. Consumers use errors.Is to distinguish error categories.
Functions ¶
func ContainsRef ¶
ContainsRef reports whether s contains a ref+ URI pattern anywhere in the string. Used by the safety-net scanner to detect unresolved references, including those embedded in larger strings.
This function intentionally over-matches (false positives are acceptable). It checks for "ref+" followed by at least one lowercase letter and "://" — but does not validate the full ref structure. Callers should follow up with ParseRef for full validation when needed.
func ValidatePath ¶
ValidatePath checks that a secret path has no traversal, empty segments, or percent-encoded characters. Intended for BatchProvider implementations to validate paths received from external callers.
Types ¶
type BatchProvider ¶
type BatchProvider interface {
Provider
// ResolvePath fetches all key-value pairs at the given path.
// Returns the full map; the caller extracts individual keys.
// The caller guarantees that path has passed [Ref.Valid]
// validation (no traversal, no empty segments).
//
// Returns [ErrSecretNotFound] when the path does not exist.
// Returns [ErrSecretResolveFailed] for transient/auth failures.
ResolvePath(ctx context.Context, path string) (map[string]string, error)
}
BatchProvider is an optional extension of Provider for backends that can fetch all keys at a path in a single API call (e.g. Vault KV v2, OpenBao KV v2). The outputconfig resolver uses this to enable path-level caching — same path with different #key fragments results in one API call.
Providers that do not implement BatchProvider fall back to per-key [Provider.Resolve] calls with ref-level caching.
type Provider ¶
type Provider interface {
// Scheme returns the URI scheme this provider handles (e.g.
// "openbao", "vault"). Must be lowercase and match the scheme
// used in ref+ URIs.
Scheme() string
// Resolve fetches the secret value for the given reference.
// The ctx controls timeout and cancellation for network I/O.
// Returns the plaintext secret value as a string.
//
// Implementations should call [Ref.Valid] before using the ref
// path to guard against manually-constructed invalid refs.
//
// Errors should wrap the appropriate sentinel:
// - [ErrSecretNotFound] when the path or key does not exist
// - [ErrSecretResolveFailed] for transient or auth failures
//
// Memory retention: the returned string is a Go string and
// cannot be zeroed. Providers SHOULD store their authentication
// material as `[]byte` and zero it in [Close] to reduce the
// retention window for bootstrap credentials, but the resolved
// VALUE returned from Resolve persists in memory until GC
// reclaims it. Callers (notably [outputconfig.Load]) embed
// resolved values in long-lived config structs; see SECURITY.md
// §Secrets and Memory Retention for the full model.
Resolve(ctx context.Context, ref Ref) (string, error)
// Close releases resources held by the provider (HTTP clients,
// connection pools). Errors are informational — the caller
// cannot recover from a close failure but should log it.
// Close is idempotent.
//
// Memory retention: implementations SHOULD zero any `[]byte`
// storage of authentication material (e.g. the provider token)
// to minimise the retention window. This is best-effort —
// Go strings derived from the bytes (e.g. HTTP header copies)
// cannot be zeroed and persist until GC. See SECURITY.md
// §Secrets and Memory Retention.
Close() error
}
Provider resolves secret references to their plaintext values. Implementations must be safe for sequential use within a single goroutine (the outputconfig load pipeline is single-threaded).
Providers carry credentials and must redact them in fmt.Stringer output. Construction (New) must not perform network I/O — connection is deferred to the first [Resolve] call.
type Ref ¶
type Ref struct {
// Scheme is the provider identifier (e.g. "openbao", "vault").
Scheme string
// Path is the secret path within the provider. Never contains
// ".." segments, "." segments, empty segments, or percent-encoded
// characters. MUST NOT be included in logs or error messages.
Path string
// Key is the field name within the secret (from the URI fragment).
Key string
}
Ref is a parsed secret reference. The zero value indicates that ParseRef determined the input was not a secret reference.
Fields are exported for use by [Provider.Resolve] implementations. The Path field contains the vault path and MUST NOT appear in logs or error messages — use Ref.String for safe formatting.
func ParseRef ¶
ParseRef parses "ref+SCHEME://PATH#KEY" into a Ref.
Returns (zero, nil) if s does not start with "ref+" — the input is not a secret reference and callers should treat it as a literal value.
Returns (zero, ErrMalformedRef) if s starts with "ref+" but is structurally invalid. Invalid cases include: empty scheme, empty path, leading slash in path, path containing ".." or "." segments, path containing empty segments (consecutive slashes), trailing slash, percent-encoded characters, empty or missing key fragment, key containing "#".
Returns (ref, nil) on success.
Error-message redaction ¶
No error returned by ParseRef echoes any substring of the input (scheme, path, or key). A malformed ref may carry sensitive material; a user-controlled substring in an error message is a leakage vector when the error is logged or propagated through a config-loader surface. Error messages are category-level ("invalid scheme", "empty path", "key fragment must not contain "#"") plus the class descriptor returned by [redactRef] for the whole-input case (#486).
func (Ref) Format ¶
Format implements fmt.Formatter to ensure path redaction across all format verbs (%v, %+v, %#v, %s). Without this, %+v would print the struct fields directly, leaking the vault path.
func (Ref) GoString ¶
GoString implements fmt.GoStringer to prevent path leakage via %#v.
func (Ref) IsZero ¶
IsZero reports whether r is the zero value, indicating that ParseRef determined the input was not a secret reference.