Propagation Security Best Practices¶
Guidelines for securing context propagation across service boundaries.
TLS first¶
Transport-level security (TLS/mTLS) is the baseline for all service-to-service communication. Context signing and encryption are defense-in-depth measures, not replacements for transport security.
When to sign¶
Use UseContextSigning() when:
- Context flows through 2+ service boundaries where any hop could modify headers
- You need tamper detection independent of transport security
- Context passes through third-party gateways or proxies you don't fully control
- You want to detect accidental header corruption or middleware bugs
For most production microservice deployments, signing is the recommended default.
When to encrypt¶
Use encryption (see Encryption with DataProtection) when:
- Context crosses public internet or untrusted network segments
- Headers contain operational data that should not be visible to intermediaries
- Regulatory or compliance requirements mandate payload-level encryption
For internal service mesh traffic over mTLS, encryption adds overhead without significant benefit.
Don't put secrets in context¶
Even with encryption, avoid propagating:
- Passwords, API keys, or authentication tokens
- Personally identifiable information (PII) subject to data protection regulations
- Data that requires audit trails for access
For sensitive data, use the Token strategy with a secure backing store (Redis, database) so only a reference token travels in headers.
Key rotation¶
Signing keys¶
The signing package supports zero-downtime key rotation via inline keys or a custom ISigningKeyProvider:
.UseContextSigning<TenantContext>(o =>
{
o.AddKey(1, oldKeyBytes);
o.AddKey(2, newKeyBytes);
o.CurrentKeyVersion = 2;
})
- Deploy new key version — add both old (v1) and new (v2) via
AddKey() - Switch current version — set
CurrentKeyVersion = 2. New signatures use v2; verification still accepts v1 from the signature header - Drain and revoke — once all in-flight requests using v1 have completed, remove v1
For dynamic key management (vault-backed keys), implement ISigningKeyProvider and register it in DI with o.KeyId = "...". See Signing Details.
Encryption keys (Data Protection)¶
ASP.NET Core Data Protection handles key rotation automatically. Keys have a default 90-day lifetime and are rotated transparently. See Microsoft docs for configuration.
Cache keys eagerly (custom key providers)¶
When using a custom ISigningKeyProvider (instead of inline keys), note that the interface is synchronous because the propagation pipeline (IContextPropagator<T>) is synchronous. Implementations should:
- Load keys from the vault at application startup
- Cache keys in memory
- Refresh periodically in the background (not on the request path)
Blocking on async key retrieval during request processing adds latency and risks timeouts.
For most deployments, inline keys via o.Key or o.AddKey() avoid this concern entirely.
Header size budget¶
- Signing adds one header (~60 bytes for base64url HMAC-SHA256 + version)
- Encryption increases total header size by ~2x due to the DataProtection envelope + base64 encoding
Account for these increases when configuring MaxPayloadBytes and HTTP server header limits.