Documentation
¶
Overview ¶
Package fieldcrypt provides AES-256-GCM encryption of sensitive fields within connection-config maps, plus the RestFieldEncryptor adapter used by sub-package stores (gateway OAuth tokens, PKCE state). It is a standalone package (not tied to *platform.Platform) so the at-rest encryption concern lives in one place and does not count against the platform package budget.
Index ¶
- Constants
- Variables
- func DecodeKey(keyStr string) []byte
- func DecodeKeys(list string) [][]byte
- func SensitiveConfigKeyList() []string
- func SensitiveNestedMapKeyList() []string
- type FieldEncryptor
- type RestFieldEncryptor
- func (g *RestFieldEncryptor) Decrypt(ciphertext string) (string, error)
- func (g *RestFieldEncryptor) Enabled() bool
- func (g *RestFieldEncryptor) Encrypt(plaintext string) (string, error)
- func (g *RestFieldEncryptor) Open(sealed string) (string, error)
- func (g *RestFieldEncryptor) Seal(plaintext string) (string, error)
Constants ¶
const ( // CfgKeySecretAccessKey is the S3 secret access key config-map key. CfgKeySecretAccessKey = "secret_access_key" // CfgKeyToken is the bearer/token config-map key. CfgKeyToken = "token" )
Conventional config-map keys for sensitive fields. Defined as constants because the same literals appear in multiple call sites (encryption allowlist + per-toolkit config extraction) and a typo or rename would silently bypass at-rest encryption.
const CfgKeyPassword = "password"
CfgKeyPassword is the conventional config-map key for password fields.
const CfgKeyStaticHeaders = "static_headers"
CfgKeyStaticHeaders is the connection-config key whose value is a nested map[string]any of HTTP headers added to every outbound apigateway request. Exported so the toolkit and admin redaction share one canonical name. The inner values are encrypted at rest.
const KeyLength = 32
KeyLength is the required key length in bytes for AES-256.
Variables ¶
var ErrDisabled = errors.New("encryption is not configured: the platform needs ENCRYPTION_KEY")
ErrDisabled is a value that must be encrypted on a deployment with no encryption key.
Functions ¶
func DecodeKey ¶ added in v1.152.0
DecodeKey reads a key as ENCRYPTION_KEY holds it: hex (64 characters), then base64 (44 characters), then the raw bytes.
func DecodeKeys ¶ added in v1.152.0
DecodeKeys reads ENCRYPTION_KEY_PREVIOUS: the keys ENCRYPTION_KEY replaced, comma-separated, each in any form DecodeKey reads. They only decrypt, so a value written before a rotation still reads.
func SensitiveConfigKeyList ¶
func SensitiveConfigKeyList() []string
SensitiveConfigKeyList returns a copy of the sensitive-key set as a slice for tests in other packages (e.g. pkg/admin) that assert their redaction list covers the encryption layer's set. Returning a copy keeps the underlying map private.
func SensitiveNestedMapKeyList ¶
func SensitiveNestedMapKeyList() []string
SensitiveNestedMapKeyList returns the nested-map sensitive key set as a slice for cross-package tests (mirrors SensitiveConfigKeyList).
Types ¶
type FieldEncryptor ¶
type FieldEncryptor struct {
// contains filtered or unexported fields
}
FieldEncryptor encrypts and decrypts sensitive fields within connection config maps. Uses AES-256-GCM with a random nonce per encryption. The encrypted value is stored as "enc:" + base64(nonce + ciphertext).
A key is rotated by making the new key current and passing the old one as a previous key: every value is encrypted with the current key, and a value the current key does not open is opened with each previous key in turn. GCM authenticates, so a key that did not encrypt a value fails to open it rather than yielding garbage, and the stored form needs no key id.
func NewFieldEncryptor ¶
func NewFieldEncryptor(key []byte, previous ...[]byte) (*FieldEncryptor, error)
NewFieldEncryptor creates an encryptor from a 32-byte (AES-256) key, and the keys it replaced, which only decrypt. The key should come from the ENCRYPTION_KEY environment variable and the previous keys from ENCRYPTION_KEY_PREVIOUS. Returns nil if the key is empty (encryption disabled — values stored in plain text).
func (*FieldEncryptor) DecryptSensitiveFields ¶
DecryptSensitiveFields returns a copy of the config map with sensitive field values decrypted. Non-sensitive fields and plain-text values are left unchanged. If the encryptor is nil, the original map is returned unchanged.
func (*FieldEncryptor) EncryptSensitiveFields ¶
EncryptSensitiveFields returns a copy of the config map with sensitive field values encrypted. Non-sensitive fields and already-encrypted values are left unchanged. If the encryptor is nil, the original map is returned unchanged.
type RestFieldEncryptor ¶
type RestFieldEncryptor struct {
// contains filtered or unexported fields
}
RestFieldEncryptor adapts a FieldEncryptor to the generic Encrypt/Decrypt interface used by sub-package stores (gateway OAuth tokens, PKCE state, etc.) so every at-rest secret uses the same key, algorithm, and enc:base64(nonce|cipher) prefix as connection credentials.
Exported so consumers like main.go can pass it to constructors (e.g., pkcestore.NewPostgresStore) without importing internal platform types.
func NewRestFieldEncryptor ¶
func NewRestFieldEncryptor(enc *FieldEncryptor) *RestFieldEncryptor
NewRestFieldEncryptor wraps a FieldEncryptor (which may be nil when encryption is disabled) as a RestFieldEncryptor.
func (*RestFieldEncryptor) Decrypt ¶
func (g *RestFieldEncryptor) Decrypt(ciphertext string) (string, error)
Decrypt reverses Encrypt. Plaintext (no enc: prefix) is returned unchanged so legacy/unencrypted rows degrade gracefully. Nil-receiver safe, matching Encrypt.
func (*RestFieldEncryptor) Enabled ¶ added in v1.152.0
func (g *RestFieldEncryptor) Enabled() bool
Enabled reports whether the encryptor holds a key. Encrypt and Decrypt pass values through without one; Seal and Open refuse.
func (*RestFieldEncryptor) Encrypt ¶
func (g *RestFieldEncryptor) Encrypt(plaintext string) (string, error)
Encrypt wraps a string with the same enc:base64(nonce|cipher) prefix the field encryptor uses for sensitive config map values. Nil-receiver safe: a nil encryptor (encryption disabled or never wired) passes plaintext through, matching FieldEncryptor's own nil semantics.
func (*RestFieldEncryptor) Open ¶ added in v1.152.0
func (g *RestFieldEncryptor) Open(sealed string) (string, error)
Open decrypts a value Seal wrote, with the current key or a previous one. ErrDisabled with no key; a value that is not "enc:..." is refused rather than returned, since it was never sealed.
func (*RestFieldEncryptor) Seal ¶ added in v1.152.0
func (g *RestFieldEncryptor) Seal(plaintext string) (string, error)
Seal encrypts a value someone else wrote, whatever it holds: unlike Encrypt it never takes a value that already reads "enc:..." as encrypted, so text typed into a form cannot pass through as plaintext by looking like ciphertext. ErrDisabled with no key.