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

secrets

package
v0.5.0 Latest Latest
Warning

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

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

Documentation

Overview

Package secrets encrypts sensitive values (e.g. connection passwords) at rest with AES-256-GCM under a configured key. See ADR 0019.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoKey = errors.New("no encryption key configured")

ErrNoKey reports that no encryption key is configured; callers must treat secret writes as unavailable rather than storing plaintext.

Functions

func LooksLikeHalfEntropyHexKey

func LooksLikeHalfEntropyHexKey(s string) bool

LooksLikeHalfEntropyHexKey reports whether a key is 32 characters of pure hexadecimal — the signature of `openssl rand -hex 16`, which the project's own docs recommended until they were corrected.

ParseKey accepts a 32-character string as 32 RAW bytes, so such a key is used as an AES-256 key carrying 128 bits of entropy. The cipher is still AES-256; the secret behind it is half the size intended, and nothing about the configuration says so.

This is a warning and not a rejection because the two shapes cannot be told apart with certainty: a legitimate 32-character passphrase made only of the characters 0-9a-f is unlikely but perfectly valid, and refusing it would break an operator who did nothing wrong. Reporting it lets the caller say something while still starting.

func ParseKey

func ParseKey(s string) ([]byte, error)

ParseKey decodes a configured key string into 32 raw bytes, accepting a raw 32-char string, 64-char hex, or base64 (standard or raw).

func ParseKeys

func ParseKeys(s string) ([][]byte, error)

ParseKeys parses a comma-separated key list. The FIRST key encrypts and decrypts; every later one only decrypts.

This is the shape Apache Airflow's `fernet_key` uses, and Dexaflow is an Airflow-compatible control plane, so an operator arriving from Airflow already knows the rule: put the new key first, the old ones after, then run the re-encryption and drop the tail.

A single key parses to exactly what ParseKey returns for it, so every deployment that predates the list keeps working unchanged.

A malformed entry is an error rather than a silent drop. Dropping it would leave an operator believing a predecessor is in the read set when it is not, and the next thing they do is delete the only remaining copy of it.

Types

type Cipher

type Cipher interface {
	Encrypt(plaintext string) (string, error)
	Decrypt(ciphertext string) (string, error)
}

Cipher encrypts and decrypts secret values.

func NewAESGCM

func NewAESGCM(key []byte) (Cipher, error)

NewAESGCM builds a Cipher from a 32-byte key. The key may be given raw (32 bytes), hex (64 chars), or base64 (standard or raw); ParseKey handles the decoding.

type StaleReader

type StaleReader interface {
	Cipher
	// DecryptStale decrypts and reports whether the value was read with a
	// fallback key rather than the primary one.
	DecryptStale(ciphertext string) (plaintext string, stale bool, err error)
}

StaleReader is a Cipher that can also say whether a value it just decrypted was written under an older key, so a caller can re-encrypt it.

func WithFallback

func WithFallback(primary Cipher, fallbacks ...Cipher) StaleReader

WithFallback returns a Cipher that writes with primary and reads with primary then fallbacks, skipping nil entries.

It always wraps, including when no fallback survives: the result is a StaleReader either way, which callers rely on. With an empty fallback list every read reports fresh, so a single-key deployment behaves exactly as the bare primary does.

Jump to

Keyboard shortcuts

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