Skip to content

ADR-005: HMAC-SHA256 for Policy Bundle Signing

ADR-005: HMAC-SHA256 for Policy Bundle Signing

Section titled “ADR-005: HMAC-SHA256 for Policy Bundle Signing”

Status: Accepted Date: 2026-03 Deciders: Platform + Outpost teams (outpost-0021)


The Arbitex Platform delivers policy bundles to Hybrid Outposts via a synchronised pull mechanism (outposts poll the platform every 60 seconds). Policy bundles contain sensitive configuration: DLP rules, provider routing, budget caps, and IP allowlists. An outpost that accepts a tampered or replayed policy bundle could be made to forward traffic to an attacker-controlled provider, disable DLP, or bypass budget controls.

Two threat vectors require mitigation:

  1. On-path tampering — a network attacker between the outpost and the platform modifies the policy bundle in transit.
  2. Replay attacks — an attacker replays an older (weaker) policy bundle to downgrade the outpost’s configuration.

The communication channel already uses mTLS (mutual TLS), which provides transport-layer confidentiality and origin authentication. However, defence in depth demands that the bundle itself be cryptographically authenticated at the application layer, independent of the transport.


Policy bundles are signed with HMAC-SHA256. The platform computes an HMAC over the serialised bundle using a shared secret (POLICY_HMAC_KEY). The outpost recomputes the HMAC on receipt and rejects any bundle where the computed MAC does not match the platform-supplied MAC.

Bundles also include an expiry timestamp checked by the outpost. Bundles older than a configured staleness threshold are rejected, preventing replay of valid but outdated bundles.

The outpost enforces the HMAC check at startup. If POLICY_HMAC_KEY is not set and INSECURE_SKIP_HMAC is not explicitly enabled, the outpost refuses to start.


Positive:

  • Provides application-layer bundle integrity independent of the mTLS transport — defence in depth.
  • HMAC-SHA256 is computationally inexpensive — negligible overhead on the outpost’s policy sync path.
  • The shared-secret model is operationally simple: distribute POLICY_HMAC_KEY once during outpost provisioning (alongside the mTLS certificate).
  • Replay protection via bundle expiry prevents downgrade attacks.
  • INSECURE_SKIP_HMAC=true provides an explicit, auditable escape hatch for development environments.

Negative / trade-offs:

  • The shared secret (POLICY_HMAC_KEY) must be securely distributed to every outpost and kept in sync. If the key must be rotated, all outposts must receive the new key before the platform starts signing with it.
  • HMAC does not provide non-repudiation — both the platform and the outpost can produce valid MACs. An asymmetric signature (e.g. ECDSA) would provide non-repudiation but adds key management complexity. For the current threat model (HMAC is sufficient; the outpost trusts the platform), this is acceptable.
  • Bundles that fail HMAC verification cause the outpost to continue operating on its last valid cached bundle. This is the correct safe behaviour but means misconfigured keys cause policy drift without an error surfacing to end users.

Configuration:

  • Platform: POLICY_HMAC_KEY — shared secret used to sign bundles.
  • Outpost: POLICY_HMAC_KEY — shared secret used to verify bundles; INSECURE_SKIP_HMAC=true — dev bypass.