secrets

package
v1.76.10 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package secrets resolves the secrets a service document declares, by name.

A document never holds a secret: it names one (`valkey.passwordSecret: valkey/password`), and `secrets.source` says how a name is delivered (truvity/policy docs/contracts/config.md, section 5):

env   the variable SLUIS_SECRET_<NAME>, the name upper-cased with every
      character that is not a letter or a digit made an underscore:
      `valkey/password` is SLUIS_SECRET_VALKEY_PASSWORD. For a local run.
file  the file <root>/<name>, read on every use, so a rotated Secret
      mounted by the platform takes effect without a restart.
ssm   the SecureString <root>/internal/config/<name> of AWS SSM Parameter
      Store (root `/sluis/<instance>`): a name is read by itself,
      decrypted, when it is first asked for (nothing is read at
      start), and read again when its copy is older than the refresh
      (one minute), so a rotation reaches a function within that.

The names are the layout's (docs/decisions/0041): `clients/<id>/secret`, `providers/google/<id>/client-id` and `client-secret`, `issuer/state-secret`, `recovery/password`, `directory/<id>/key`, `valkey/password`. Nothing here logs or returns a value in an error.

Index

Constants

View Source
const (
	KindEnv  = "env"
	KindFile = "file"
	KindSSM  = "ssm"
)

The kinds of source, as `secrets.source` spells them.

View Source
const ConfigPrefix = "/internal/config/"

ConfigPrefix is where, under an installation's root, the secrets a document names live: `<root>/internal/config/<name>` (ADR 0041).

View Source
const DefaultMaxStale = 24 * time.Hour

DefaultMaxStale is how old a copy may grow while every read again fails before the source fails closed: an instance whose read access was revoked stops serving the secrets it read, a day later at the latest.

View Source
const DefaultRefresh = time.Minute

DefaultRefresh is how old the SSM source's copy of one secret may be before it is read again: a rotated secret reaches every instance within it.

View Source
const EnvPrefix = "SLUIS_SECRET_"

EnvPrefix begins every variable the env source reads.

Variables

View Source
var ErrNotFound = errors.New("secrets: not delivered")

ErrNotFound is a name the source does not deliver.

Functions

func Check

func Check(name string) error

Check refuses a name that is not one: segments of letters, digits, '.', '_' and '-', separated by '/', none empty and none a dot or two.

func CheckEnvNames

func CheckEnvNames(names []string) error

CheckEnvNames refuses names two of which the env source would read from one variable (`a/b` and `a-b` are both SLUIS_SECRET_A_B): one would silently be the other's secret.

func CheckRoot

func CheckRoot(root string) error

CheckRoot refuses an SSM root that would nest under another installation's tree, or under the old /sluis/private and /sluis/export: no segment of it may be `private`, `export`, `internal` or `external`.

func ClientSecret

func ClientSecret(clientID string) string

ClientSecret is a confidential client's secret.

func EnvName

func EnvName(name string) string

EnvName is the variable the env source reads a name from.

func Named

func Named(f *config.Serve) []string

Named is every secret name a serve document gives.

func ParseStateSecret added in v1.75.0

func ParseStateSecret(raw []byte) ([]byte, error)

ParseStateSecret reads a state secret: one trailing newline trimmed, then hex or base64 for at least 32 bytes that look random. A file of one repeated character, or of a few distinct bytes, is a placeholder and not a secret, and is refused.

func ProviderClientID

func ProviderClientID(provider string) string

ProviderClientID and ProviderClientSecret are a Google OAuth client's halves.

func ProviderClientSecret

func ProviderClientSecret(provider string) string

ProviderClientSecret is a Google OAuth client's secret.

Types

type Env

type Env struct{ Getenv func(string) string }

Env reads SLUIS_SECRET_<NAME> through getenv, on every use.

func (Env) Describe

func (e Env) Describe(name string) string

Describe implements Source.

func (Env) Get

func (e Env) Get(_ context.Context, name string) (string, error)

Get implements Source.

type File

type File struct{ Root string }

File reads <Root>/<name> on every use, so a rotated mount is seen at once.

func (File) Describe

func (f File) Describe(name string) string

Describe implements Source.

func (File) Get

func (f File) Get(_ context.Context, name string) (string, error)

Get implements Source.

type Legacy

type Legacy struct {
	Locations map[string]Location
	ClientDir string
	Next      Source
}

Legacy is what a v1 document named, secret by secret, in front of another source: a v1 document keeps reading the variables and the files it named until it is moved to v2. Dir, when set, holds one file per client (v1's `clientSecretsDir`).

func (Legacy) Describe

func (l Legacy) Describe(name string) string

Describe implements Source.

func (Legacy) Get

func (l Legacy) Get(ctx context.Context, name string) (string, error)

Get implements Source.

type Location

type Location struct {
	Env  string
	File string
}

Location is where a converted v1 document said one secret was: a variable or a file.

type ParametersAPI

type ParametersAPI interface {
	GetParameter(ctx context.Context, in *awsssm.GetParameterInput, opts ...func(*awsssm.Options)) (*awsssm.GetParameterOutput, error)
}

ParametersAPI is the part of the SSM client the source calls.

type SSM

type SSM struct {
	API     ParametersAPI
	Root    string
	Refresh time.Duration
	// MaxStale is how old a copy may grow while reads fail. Zero is
	// DefaultMaxStale.
	MaxStale time.Duration
	// Now is the clock; nil is time.Now.
	Now func() time.Time
	// contains filtered or unexported fields
}

SSM reads one SecureString at a time, <Root>/internal/config/<name>, decrypted, when a name is first asked for, and again when its copy is older than Refresh. Nothing is read when the source is built, and a name nobody asks for is never read.

A read again happens outside any lock, by one caller at a time per name; everybody else asking for that name is answered from the copy meanwhile, or waits for the read when there is none. A read that fails keeps the copy, and the next is not tried before retryAfter. An absent name is remembered as absent for retryAfter. A copy older than MaxStale with every read again failing is not served: the source fails closed.

func NewSSM

func NewSSM(ctx context.Context, root, region, endpoint string, refresh time.Duration) (*SSM, error)

NewSSM connects with the platform's credentials (a Lambda role, Pod Identity, the environment). It makes no call to SSM.

func (*SSM) Describe

func (s *SSM) Describe(name string) string

Describe implements Source.

func (*SSM) Get

func (s *SSM) Get(ctx context.Context, name string) (string, error)

Get implements Source.

type Source

type Source interface {
	// Get returns the secret, or an error wrapping ErrNotFound when the
	// source has none by that name. The value is never in an error.
	Get(ctx context.Context, name string) (string, error)
	// Describe says where a name is read from, for a log line: never a
	// value.
	Describe(name string) string
}

Source delivers secrets by name.

func Open

func Open(ctx context.Context, f *config.Serve, more ...string) (Source, error)

Open builds the source a serve document's `secrets` names: env when it names none. A document converted from v1 reads, in front of it, every secret where v1 said it was. more are names the document does not hold that are read too (each confidential client's): with the env source no two names may share a variable.

Jump to

Keyboard shortcuts

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