append and read on any new streams.
Determined at stream creation
A stream captures its
cipher when it is created, through its basin’s configuration.Key supplied on data plane requests
Encrypted streams require the
s2-encryption-key header on REST requests, or pass it using the corresponding CLI environment variable or flags.Key custody stays with you
S2 does not persist or log the encryption key.
How it works
New streams inherit thestream_cipher configured on the basin at the moment they are created. Reconfiguring the basin later only affects streams created after that change.
What is encrypted
For regular records, S2 encrypts headers and body before storage, and decrypts them only when serving a read with the correct key. Command records stay plaintext because S2 must interpret them to apply service-side operations such as fencing and trimming.Encrypted records are cryptographically bound to the stream they were written to. S2 includes the stream’s unique identifier as associated data, so ciphertext from one stream cannot be accepted as a record in another stream.
Supported ciphers
Keys are base64-encoded when provided in the
s2-encryption-key header or to the CLI. SDKs allow providing either a string or bytes.
A stream configured with
aes-256-gcm can have up to 2^32 records (~4.3 billion), and subsequent appends will be rejected. Otherwise, a stream can have up to 2^64 records (effectively unlimited) – so aegis-256 is generally preferable.Where keys are required
Generate a key
Store the resulting value as a secret to be used for one or more streams. Maintain a mapping of which key was used for which stream, so that it may be specified consistently for appends and reads.
Key management
For coarse-grained access, manage a shared key in your existing Key Management System (KMS) or secrets infrastructure. For finer-grained access, such as a key per stream, use envelope encryption:- Keep a Key Encryption Key (KEK) in your KMS.
- Generate a Data Encryption Key (DEK) per stream, and store the wrapped DEK alongside your stream metadata.
- At request time, your application unwraps the DEK and passes it to S2 as the stream encryption key.
Configure encryption for new streams
- CLI
- REST
- TypeScript
- Python
- Go
- Rust
Stream create endpoints do not take a per-stream encryption field. A stream inherits the basin default when it is created, and that
cipher is immutable for the lifetime of the stream.Append and read with the key
- CLI
- REST
- TypeScript
- Python
- Go
- Rust
The same keying pattern applies to single-request operations, append/read sessions, SSE reads, and S2S sessions. The encryption key is just an HTTP header on the wire.
Inspect cipher config
- Get basin config to see the basin’s current
stream_cipherfor new streams. - List streams to inspect current streams’
cipher.

