Documentation
¶
Overview ¶
Package vault is Atlas's engine-internal encrypted secret store: worker credentials sealed at rest with AES-256-GCM under a master key that never leaves the operator's control (ADR-0069), on by default with a generated key file when no operator key is supplied (ADR-0070).
It exists as its own package so the boundary is enforced rather than merely intended: nothing here returns a plaintext secret except Vault.Get, nothing writes the master key anywhere but the key file, and a caller cannot reach past the API into a record. The rest of the server holds a *Vault and resolves secret *references*, so a credential never sits in a compiled process, an event, or a log line.
Index ¶
- Constants
- Variables
- func ConnectionCredentialName(connectionID string) string
- func DataKeyName(subject string) string
- func IsDataKeyName(name string) bool
- func IsEnciphered(text string) bool
- func IsLinkClientSecretName(name string) bool
- func IsReservedName(name string) bool
- func LinkClientSecretName(provider string) string
- func ResolveKey(keyFile string) (key []byte, source string, err error)
- func SubjectOfDataKeyName(name string) (string, bool)
- type Envelope
- type Meta
- type Vault
- func (v *Vault) DataSubjects() ([]Meta, error)
- func (v *Vault) Delete(name string) error
- func (v *Vault) Erase(subject string) error
- func (v *Vault) Get(name string) (string, bool, error)
- func (v *Vault) HasDataKey(subject string) (bool, error)
- func (v *Vault) List() ([]Meta, error)
- func (v *Vault) Open(name string, e Envelope) (string, error)
- func (v *Vault) Seal(subject, name string, kind uint8, plaintext string) (Envelope, error)
- func (v *Vault) Set(name, value string) (Meta, error)
Constants ¶
const ( KeyEnv = "ATLAS_VAULT_KEY" KeyFileEnv = "ATLAS_VAULT_KEY_FILE" )
Environment variables that configure the vault master key. The key is 32 bytes (AES-256), given as hex (64 chars) or base64. An operator key from either of these is preferred and, per ADR-0069, is NEVER written to disk by Atlas. When neither is set the vault is on by default and generates its own key file (ADR-0070).
Variables ¶
var ErrErased = errors.New("vault: the data subject's key has been erased; this value is permanently unreadable")
ErrErased is returned by Open when the subject's data key is gone: the value is permanently unreadable, which is the intended outcome of an erasure and not a fault. Callers distinguish it from a genuine failure because the two need opposite handling — one is reported to an operator as "erased", the other as broken.
Functions ¶
func ConnectionCredentialName ¶ added in v0.20.0
ConnectionCredentialName is the vault name of one connection's credential.
func DataKeyName ¶ added in v0.7.0
DataKeyName is the vault name a subject's data key is stored under. Exported so the secrets API can refuse the region and an operator view can label it.
func IsDataKeyName ¶ added in v0.7.0
IsDataKeyName reports whether a vault name belongs to the data-key region.
func IsEnciphered ¶ added in v0.7.0
IsEnciphered reports whether a stored value is an envelope. It needs no key, so any layer can ask — which is how the operator UI labels a value rather than showing it.
func IsLinkClientSecretName ¶ added in v0.21.0
IsLinkClientSecretName reports whether a vault name holds a linking client secret.
func IsReservedName ¶ added in v0.20.0
IsReservedName reports whether a name belongs to a region the vault keeps for Atlas itself — a data subject's key, a connection's credential, or the client secret accounts are linked through. The operator surfaces — the secrets API, a Worker's credential reference, an API token sealed into the vault — refuse such a name, because reaching one through them would hand a person's credential, or the key to their data, to whatever that surface feeds.
func LinkClientSecretName ¶ added in v0.21.0
LinkClientSecretName is the vault name of a provider's linking client secret.
func ResolveKey ¶
ResolveKey sources the master key with operator precedence (ADR-0070): an operator key from the environment (ATLAS_VAULT_KEY / ATLAS_VAULT_KEY_FILE) wins and is never written to disk; absent one, the key is loaded from keyFile, or generated into it (readable by this account only) so the vault is on by default without provisioning. source is "env", "file", or "generated" — the caller logs the generated case, which trades a weaker at-rest guarantee (key beside the ciphertext) for turnkey operation.
func SubjectOfDataKeyName ¶ added in v0.7.0
SubjectOfDataKeyName returns the subject a data-key name belongs to.
Types ¶
type Envelope ¶ added in v0.7.0
type Envelope struct {
// Subject names whose data key opens this value. It is in the clear on purpose:
// ADR-0314's primary defence is that people are named by reference, so the id is
// exactly the part that was never meant to be hidden — and carrying it here is
// what makes the ciphertext self-contained in a backup nobody can interpret any
// more.
Subject string
// Kind is the caller's own value kind, carried so an opened value returns as the
// type it had rather than as a string. This package does not interpret it.
Kind uint8
// contains filtered or unexported fields
}
Envelope is an enciphered value as it is carried everywhere else in Atlas: in a command, in an event, in the state record, in a checkpoint, in an export.
Subject and Kind are readable because a reader that cannot open the value still has to render it — an operator inspecting an instance is shown whose data this is and what type it had, not a wall of base64. The nonce and the ciphertext are not exported: only this package can open one, which is the same boundary the package already draws around a secret's plaintext.
func ParseEnvelope ¶ added in v0.7.0
ParseEnvelope reads a stored value back into an envelope, ok=false when the text is not one.
The parse is strict — the marker member, all four fields present, decodable base64, a non-empty subject — because an ordinary variable whose value happened to resemble an envelope would otherwise be treated as enciphered. Strictness makes an accidental collision vanishingly unlikely; a deliberate one is possible and harmless, since the forged envelope simply fails to open and only affects the instance its author submitted it to.
func (Envelope) Text ¶ added in v0.7.0
Text renders the envelope as the canonical JSON that is stored and transported.
The marshal error is discarded rather than handled: every field is a string or a uint8, so encoding/json cannot fail here, and a branch nothing can reach is a branch nothing can test.
type Meta ¶
type Meta struct {
Name string `json:"name"`
KeyID string `json:"keyId"`
CreatedAt int64 `json:"createdAt"`
UpdatedAt int64 `json:"updatedAt"`
}
Meta is the value-free view of a secret returned by the API and List: it proves a secret exists and under which key, but never reveals the value.
type Vault ¶
type Vault struct {
// contains filtered or unexported fields
}
Vault is the engine-internal encrypted secret store (ADR-0069, closing the A3 option deferred by ADR-0041). It owns a sidecar directory — one JSON file per secret, hex-named, atomic write + dir fsync, the connectorStore pattern — and an AES-256-GCM cipher built from the master key. Like the other sidecar stores it is owned by the run-loop goroutine, so it needs no locking; and it writes only ciphertext, so no secret value ever reaches the WAL, an event, or a variable (I6).
func New ¶
New opens (creating if needed) the vault directory and builds the AES-256-GCM cipher from a 32-byte master key.
func (*Vault) DataSubjects ¶ added in v0.7.0
DataSubjects lists the subjects that hold a data key, oldest first. It is the operator's view of what an erasure could still act on; it reveals ids, which are references by ADR-0314's design and not the content the keys protect.
func (*Vault) Erase ¶ added in v0.7.0
Erase destroys a subject's data key, which is the whole of an erasure: every copy of every value ever sealed under it, in every store and every backup, becomes permanently unreadable in one act. It is idempotent, so a repeated request is not an error.
func (*Vault) Get ¶
Get returns the decrypted value for a name, ok=false when no such secret exists. A record sealed under a different master key, or one that has been tampered with, is an error rather than a silent miss.
func (*Vault) HasDataKey ¶ added in v0.7.0
HasDataKey reports whether a subject still has a data key, i.e. whether their values are still readable.
func (*Vault) List ¶
List returns value-free metadata for every stored secret, oldest first. Non-record files are ignored, and so are the per-subject data keys of ADR-0314: those are not credentials an operator manages, and showing them here would invite deleting one — which is an erasure of business data, not the removal of a secret. Vault.DataSubjects is their own view.
func (*Vault) Open ¶ added in v0.7.0
Open deciphers an envelope belonging to the named variable. A subject whose key has been erased is ErrErased, which is an answer and not a failure.
func (*Vault) Seal ¶ added in v0.7.0
Seal enciphers one value of one variable under the subject's data key, creating that key on first use.
name binds the ciphertext to the variable it belongs to (with the subject, as the AEAD's additional data), so an envelope cannot be moved to another variable — or to another subject's — and still open. It survives the operations that legitimately copy a value under its own name: a fork, a migration, a checkpoint.