This guide explains how to configure Trellis to handle sensitive data securely using the built-in Middleware Hooks.
If your Trellis sessions store sensitive information (API Keys, User PII) and use persistent storage (File, Redis), you should enable Encryption at Rest.
Trellis uses an Envelope Pattern with AES-GCM. The entire session state is encrypted and wrapped in an opaque “envelope” state before being stored.
To enable encryption, wrap your StateStore with the EncryptionMiddleware. (See examples/manual-security for a full runnable example).
import (
"github.com/aretw0/trellis/pkg/persistence/middleware"
"github.com/aretw0/trellis/pkg/adapters/file"
)
func main() {
// 1. Initialize your base store (e.g., file.Store or Redis)
baseStore := file.NewStore("./sessions")
// 2. Define your Encryption Config (Keys should come from KMS/Env)
config := middleware.EncryptionConfig{
ActiveKey: []byte("your-32-byte-secret-key-12345678"), // AES-256
}
// 3. Wrap the store
secureStore := middleware.NewEncryptionMiddleware(config)(baseStore)
// 4. Use secureStore in your Runner/Manager
manager := session.NewManager(secureStore)
}
Trellis supports Zero-Downtime Key Rotation. When you rotate encryption keys, you can provide the old keys as fallbacks.
The middleware will:
ActiveKey.FallbackKeys in order.ActiveKey.config := middleware.EncryptionConfig{
ActiveKey: []byte("new-32-byte-secret-key-87654321"),
FallbackKeys: [][]byte{
[]byte("old-32-byte-secret-key-12345678"),
},
}
This effectively migrates your data lazily as sessions are accessed.
If you need to ensure that sensitive fields (like password, ssn) are never written to disk in plaintext—even if not using encryption, or as a secondary defense layer—use the PIIMiddleware.
The PII middleware accepts a list of regular expressions. Any key in the Context matching these patterns will have its value replaced by ***.
piiMiddleware := middleware.NewPIIMiddleware([]string{
"password",
"api_key",
"ssn_*",
})
// Chain it: Encryption(PII(Store))
// This means: Mask PII first -> Then Encrypt -> Then Save to Store
cautiousStore := middleware.NewEncryptionMiddleware(encConfig)(
piiMiddleware(baseStore),
)
The PII Middleware masks data before persistence.
***).Effect on Resume: If your application crashes and restarts, it will load the session from disk. Since the sensitive data was masked, the resumed state will contain *** instead of the real values.
Use Case: Use PII Masking primarily for Logging compliance or Ephemeral sessions where you prefer to crash rather than leak data. If you need Durable Execution with sensitive data, rely on Encryption instead of Masking.