A custom Cadence DataConverter that JSON-encodes workflow data and then encrypts it with AES-256-GCM. Every workflow input, output, and activity parameter is encrypted before being written to Cadence history. Without the key, payloads stored by the Cadence server are unreadable to operators browsing workflow history.
Note that application logs, metrics, and search attributes are separate disclosure surfaces — a DataConverter does not protect them. Treat them accordingly.
- Task list:
data-encryption - Workflow type:
EncryptedDataConverterWorkflow
- Cadence server running (e.g. Docker Compose from the Cadence repo).
- From the repo root, build:
./gradlew build.
./gradlew -q execute -PmainClass=com.uber.cadence.samples.common.RegisterDomainOr with the Cadence CLI:
cadence --domain samples-domain domain registerThe worker loads its AES-256 key from the CADENCE_ENCRYPTION_KEY environment variable (64 hex characters = 32 bytes). If the env var is unset, the worker falls back to a hardcoded demo key and prints a warning — never use the demo key in production. If the env var is set but invalid, the worker fails fast instead of silently using the demo key.
Generate a key:
export CADENCE_ENCRYPTION_KEY=$(openssl rand -hex 32)The worker prints an encryption statistics banner showing plaintext vs ciphertext size and a hex preview, then begins polling the data-encryption task list:
./gradlew -q execute -PmainClass=com.uber.cadence.samples.encryption.EncryptionWorker./gradlew -q execute -PmainClass=com.uber.cadence.samples.encryption.EncryptionStarterOr from the Cadence CLI:
cadence --domain samples-domain \
workflow start \
--workflow_type EncryptedDataConverterWorkflow \
--tl data-encryption \
--et 60toData: JSON-encode the arguments with the standardJsonDataConverter, then encrypt withAES/GCM/NoPaddingusing a fresh 12-byte random nonce. The output layout isnonce(12 bytes) || ciphertext || tag(16 bytes). A new nonce per call preserves semantic security for repeated payloads.fromData/fromDataArray: split nonce + ciphertext, run AES-GCM decrypt (which authenticates the tag and fails on any tampering), then delegate toJsonDataConverter.
| File | Purpose |
|---|---|
EncryptedJsonDataConverter.java |
The custom DataConverter |
EncryptionKeyLoader.java |
Reads the 32-byte key from CADENCE_ENCRYPTION_KEY or the demo fallback |
EncryptedDataConverterWorkflow.java |
Workflow + activity + sample SensitiveCustomerRecord POJO and generator |
EncryptionWorker.java |
Worker main; wires the converter into WorkflowClientOptions and prints the stats banner |
EncryptionStarter.java |
Thin async starter |