Documentation
¶
Overview ¶
Package stdtemporalcodec implements a Temporal converter.PayloadCodec that encrypts payloads using a Google Tink AEAD primitive backed by an AES-256-GCM keyset, together with an HTTP handler that exposes the codec over Temporal's remote codec contract.
Why Tink instead of a hand-rolled AES-GCM construction:
- Tink owns the on-the-wire ciphertext format (a 5-byte type-prefix that embeds the key id, followed by iv|ct|tag). We don't have to define and freeze our own byte layout.
- Tink keysets are first-class containers for key rotation: every keyset has one primary key (used to encrypt) and any number of additional keys (all tried on decrypt). Rotation is therefore the boring case, not a special path.
- AES-256-GCM is still the underlying primitive; tenant isolation is enforced by passing the Temporal namespace into the AEAD's additionalData argument. A ciphertext produced for namespace A cannot be decrypted under namespace B: GCM authentication will fail.
Payloads that are not encoded with MetadataEncodingEncrypted pass through Decode unchanged.
Key rotation ¶
To rotate keys:
- Add a new key to the Tink keyset (e.g. with tinkey or the cmd/stdtemporalcodec-genkeyset helper in this repo).
- Promote it to primary.
- Ship the new base64-encoded cleartext keyset to every worker, client and codec-server process and redeploy.
New ciphertexts are produced under the new primary; ciphertexts produced under the previous primary continue to decrypt because the old key is still present in the keyset. Once Temporal history retention has expired for all payloads encrypted under the old key, it can be removed from the keyset.
Index ¶
Constants ¶
const ( // MetadataEncodingEncrypted is the value of the standard "encoding" // metadata key for payloads produced by this codec. MetadataEncodingEncrypted = "binary/encrypted" // MetadataContextNamespace is the metadata key holding the Temporal // namespace this payload was encrypted for. It is captured for // observability; the AEAD additionalData binding enforces the // constraint at decrypt time. MetadataContextNamespace = "encryption-context-namespace" )
Metadata keys and well-known values used on commonpb.Payload to identify payloads that were encrypted by this codec.
const ( PathEncode = "/encode" PathDecode = "/decode" )
Default route paths.
const HeaderNamespace = "X-Namespace"
HeaderNamespace is the HTTP request header that carries the Temporal namespace for the codec call.
Variables ¶
This section is empty.
Functions ¶
func Handler ¶
func Handler(opts HandlerOptions) (http.Handler, error)
Handler returns an http.Handler that serves POST /encode and POST /decode. The returned handler routes by request path suffix so it can be mounted at any prefix.
func StripCloudAccountSuffix ¶
StripCloudAccountSuffix is a NormalizeNamespace helper that trims everything after (and including) the last dot in the given namespace. Temporal Cloud's Web UI sends X-Namespace as `<name>.<accountID>`; the codec is configured with bare namespace names, so callers integrating with Cloud should set HandlerOptions.NormalizeNamespace = StripCloudAccountSuffix.
If the input contains no dot it is returned unchanged.
Types ¶
type Codec ¶
type Codec struct {
// contains filtered or unexported fields
}
Codec implements converter.PayloadCodec using a Tink AEAD primitive (AES-256-GCM in the typical configuration) scoped to a single Temporal namespace.
func (*Codec) Decode ¶
Decode decrypts each payload that bears MetadataEncodingEncrypted; any other payload is passed through unchanged.
func (*Codec) Encode ¶
Encode encrypts each payload via the Tink AEAD primitive and returns new payloads tagged as MetadataEncodingEncrypted.
func (*Codec) WithNamespace ¶
WithNamespace returns a copy of the codec scoped to a different namespace. This is useful on the server side where the namespace is determined per request. The underlying Tink AEAD primitive (and keyset) is shared.
type HandlerOptions ¶
type HandlerOptions struct {
// Codec performs the actual encryption/decryption work. It will be
// scoped to the per-request namespace via Codec.WithNamespace before
// each call. Required.
Codec *Codec
// AllowedNamespaces is the set of Temporal namespaces the server will
// service. A request bearing any other namespace is rejected with
// 403 Forbidden. If empty, all namespaces are rejected. Compared
// against the value returned by NormalizeNamespace (if set).
AllowedNamespaces []string
// NormalizeNamespace, if set, is applied to the X-Namespace header
// value before allowlist comparison and before passing to the codec
// (which forwards it as the KMS EncryptionContext namespace value).
// Defaults to identity. Use StripCloudAccountSuffix when serving the
// Temporal Cloud Web UI.
NormalizeNamespace func(string) string
// Logger receives structured warnings (auth denials) and errors
// (codec failures). Defaults to zap.NewNop().
Logger *zap.Logger
}
HandlerOptions configures the codec server handler.
type Options ¶
type Options struct {
// Keyset is the Tink keyset used to encrypt (with the primary key)
// and decrypt (trying every key in the keyset). Required.
Keyset *keyset.Handle
// Namespace is the Temporal namespace that scopes the codec instance.
// It is bound into the AEAD additionalData on every operation.
// Required.
Namespace string
}
Options configures a Codec.