Workflow history signing | Dapr Docs
Edit this page<br>Create documentation issue<br>Create project issue<br>Print entire section
Workflow history signing<br>Cryptographic tamper detection for workflow execution histories<br>Dapr workflow history signing provides cryptographic tamper detection for<br>workflow execution histories. Every history event produced during a workflow’s<br>lifetime is signed using the sidecar’s mTLS identity (X.509 SPIFFE Verifiable Identity Document (SVID)), creating an<br>auditable chain of signatures that is verified each time the workflow state is<br>loaded.<br>Before you enable signing: plan your root CA lifecycle<br>Workflow history signing trusts your Dapr root CA . The default Dapr-generated<br>self-signed root is valid for one year . If that root expires, or if you<br>rotate to a new root with a different private key, every signed workflow<br>issued under the old root stops verifying and fails to load with error type<br>SignatureVerificationFailed. There is no re-sign path.<br>Before turning the feature on, decide which of the following you will commit to:<br>Renew the leaf/issuer with the same root key (recommended). Back up the<br>Dapr-generated root private key now and reuse it for every renewal, or<br>Bring your own CA with a root key you control and store securely (HSM<br>or secret store), and reuse it for all issuer renewals, or<br>Drain before rotating to a new root. Only run workflows short enough<br>to complete (or be purged) inside one root-CA validity window, and complete<br>or purge all signed workflows before rotating the root.<br>If you cannot guarantee one of these for the full lifetime of your longest<br>workflow, do not enable signing yet . See<br>long-running workflows and root CA expiry<br>for the full guidance.
About SPIFFE Verifiable Identity Documents (SVIDs)<br>An SVID is the workload’s digital passport. Each Dapr sidecar gets one from<br>Sentry and uses it both for mTLS and for signing workflow history.<br>SPIFFE ID : embedded in the X.509 certificate (in the URI Subject<br>Alternative Name) as spiffe:///ns//. It<br>identifies the workload that produced the signature.<br>Cryptographic proof : the sidecar holds the matching private key and uses<br>it to sign each history batch.<br>Trust roots : every SVID chains to a Sentry CA. Verifiers accept a<br>signature only if its certificate chains to a CA in the trust bundle.<br>For background on Sentry, mTLS, and trust domains, see setup & configure<br>mTLS and security concepts.<br>Overview<br>Workflows in Dapr execute as a series of deterministic replay steps. Each step<br>appends history events to the actor state store. History signing ensures that those events have<br>not been modified, reordered, or removed after they were written.<br>When signing is active, Dapr:<br>Deterministically marshals each new history event.<br>Computes a SHA-256 digest over the batch of events.<br>Chains the new digest to the previous signature’s digest.<br>Signs the combined input using the sidecar’s SPIFFE X.509 private key (SVID).<br>Persists the signature and the signing certificate alongside the history.<br>On every subsequent load of that workflow’s state, Dapr walks the full<br>signature chain and verifies every link before allowing execution to continue.<br>flowchart LR<br>subgraph History["Workflow History"]<br>E0["Event 0"] --- E1["Event 1"] --- E2["Event 2"] --- E3["Event 3"] --- E4["Event 4"] --- E5["Event 5"]<br>end<br>subgraph Signatures["Signature Chain"]<br>S0["Sig 0Events [0,2)"]<br>S1["Sig 1Events [2,4)"]<br>S2["Sig 2Events [4,6)"]<br>S0 -->|prev digest| S1 -->|prev digest| S2<br>end<br>E0 & E1 -.-> S0<br>E2 & E3 -.-> S1<br>E4 & E5 -.-> S2<br>subgraph Certs["Certificate Table"]<br>C0["Cert 0SVID from Boot 1"]<br>C1["Cert 1SVID from Boot 2"]<br>end<br>S0 -.->|cert index 0| C0<br>S1 -.->|cert index 0| C0<br>S2 -.->|cert index 1| C1<br>Each signature covers a contiguous range of events and references the previous<br>signature’s digest, forming a hash chain. A certificate table stores the<br>DER-encoded X.509 certificate chains used for signing, indexed by position.<br>When the sidecar’s SVID rotates (for example, after a restart), a new certificate<br>entry is appended and subsequent signatures reference the new index.<br>Prerequisites<br>History signing requires mTLS to be enabled. mTLS provides the SPIFFE<br>X.509 identity that is used as the signing key. Without mTLS, there is no<br>identity material available and signing is silently disabled.<br>In a standard Dapr deployment with the Sentry service, mTLS is enabled by default.<br>Configuration<br>History signing is controlled by the WorkflowHistorySigning feature flag. It is<br>disabled by default and must be explicitly enabled.<br>Enabling signing<br>To enable signing, set the feature flag to true in your Dapr configuration:<br>apiVersion: dapr.io/v1alpha1<br>kind: Configuration<br>metadata:<br>name: my-config<br>spec:<br>features:<br>- name: WorkflowHistorySigning<br>enabled: true
Conditions for signing to be active<br>Both conditions must be true for signing to occur:<br>ConditionHow to checkmTLS is enabledSentry service is running and the sidecar has a valid...