Documentation
¶
Overview ¶
Package crypt seals secret columns at rest (decision record 0017): remote repository and proxy passwords, LDAP and mail credentials, webhook secrets, key pair private keys, OIDC secrets and the token signing key.
A sealed value is
magic(4) | version(4, big endian) | key id(4) | nonce(12) | AES-256-GCM ciphertext and tag
Keys are derived from the operator's master key with HKDF-SHA256, one per version, so rotation adds a version instead of replacing the key: values sealed under an older version still open until the store re-seals them (Reseal), and the old master key can then be retired. The key id is a fingerprint of the master key for that version; it turns "the server was started with a different master key" into ErrWrongKey rather than an authentication failure that looks like tampering.
The purpose (which column) and row id (which record) are authenticated but not stored, so a sealed value copied into another row or column fails to open. This is the same design as hostweave's keyring, with a version number in place of a key name because artifactweave has one master key at a time.
Index ¶
- Constants
- Variables
- func IsSealed(b []byte) bool
- func KeepIfMasked(incoming, stored string) string
- func Mask(secret string) string
- func ParseMasterKey(s string) ([]byte, error)
- func Version(sealed []byte) (uint32, error)
- type Keyring
- func (k *Keyring) Active() uint32
- func (k *Keyring) Open(purpose, rowID string, sealed []byte) ([]byte, error)
- func (k *Keyring) Reseal(purpose, rowID string, sealed []byte) ([]byte, bool, error)
- func (k *Keyring) Rotate(newMaster []byte) (*Keyring, error)
- func (k *Keyring) Seal(purpose, rowID string, plaintext []byte) ([]byte, error)
- func (k *Keyring) Versions() []uint32
- type MasterKey
Constants ¶
const Masked = "********"
Masked is what reads return in place of a stored secret. Research 03 and 15 record that Artifactory returns secrets masked rather than in clear; the exact string Artifactory uses is unverified, so this one is artifactweave's.
const (
// MinMasterKey is the shortest accepted master key.
MinMasterKey = 32
)
Variables ¶
var ( // ErrWeakKey reports master key material shorter than 32 bytes. ErrWeakKey = errors.New("crypt: master key must be at least 32 bytes") // ErrNoKeys reports a keyring built from no keys. ErrNoKeys = errors.New("crypt: no master key") // ErrBadVersion reports a zero or duplicate key version. ErrBadVersion = errors.New("crypt: invalid key version") // ErrBadFormat reports input that is not a sealed value. ErrBadFormat = errors.New("crypt: not a sealed value") // ErrUnknownKey reports a value sealed under a version the ring lacks. ErrUnknownKey = errors.New("crypt: sealed under an unknown key version") // ErrWrongKey reports a value sealed under a different master key for the // same version: the configured master key is not the one that sealed it. ErrWrongKey = errors.New("crypt: sealed under a different master key") // ErrTampered reports failed authentication, including a value moved to // another purpose or row. ErrTampered = errors.New("crypt: authentication failed") // ErrBadPurpose reports an empty purpose. ErrBadPurpose = errors.New("crypt: purpose is required") )
Sentinel errors; callers test them with errors.Is.
Functions ¶
func KeepIfMasked ¶
KeepIfMasked resolves an incoming secret on update. Clients such as the Terraform providers and `jf` read a configuration, change a field and send the whole document back; the secret then arrives as Masked and must not overwrite the stored value.
func Mask ¶
Mask returns Masked for a set secret and "" for an unset one, so a client can still tell whether a password is configured.
func ParseMasterKey ¶
ParseMasterKey turns the configured master key (ARTIFACTWEAVE_MASTER_KEY) into key material. Base64 (standard or URL alphabet, padded or not) that decodes to at least 32 bytes is decoded, which is what `openssl rand -base64 32` produces; anything else is used as raw bytes and must itself be at least 32 bytes.
Types ¶
type Keyring ¶
type Keyring struct {
// contains filtered or unexported fields
}
Keyring seals under its newest version and opens any version it holds. It is safe for concurrent use.
func NewKeyring ¶
NewKeyring returns a keyring holding every given version. The highest version seals; all of them open.
func (*Keyring) Reseal ¶
Reseal re-encrypts a value under the active version if it was sealed under an older one, and reports whether it changed. Stores run it over every sealed column after Rotate; once nothing changes, the old master key can be removed from the configuration.
func (*Keyring) Rotate ¶
Rotate returns a keyring that seals under newMaster as the next version and still opens every version this one holds. The receiver is unchanged.
type MasterKey ¶
MasterKey is one version of the operator's master key.
func ParseVersionedKey ¶
ParseVersionedKey reads one configured master key, optionally prefixed with its version as "vN:" (N >= 1); a key without a prefix is version 1. Versions must be stable across restarts because sealed values name the version that sealed them, so rotation adds the next version explicitly: the old key moves to master_key_previous unchanged and the new one is configured as "v2:<key>", then "v3:<key>" at the next rotation. Base64 never contains ':', so the prefix cannot be mistaken for key material.