KV Store, Intentions, and Access Control Lists (ACLs)
Domain 4 combines three topics that all answer "who may read or do what". The KV store holds configuration; intentions decide which services may talk to which; ACLs decide which humans, agents and services may call the API at all. Exam questions frequently chain them - a token needs KV read on one prefix and service read on one service, and that service also needs an intention.
KV store mechanics
Keys are hierarchical strings; consul kv put/get/delete map onto /v1/kv/. Values are capped at 512 KB. The primitives that matter:
- Check-and-set:
-cas=<modify-index>, orcas=0for create-if-absent - the basis of optimistic concurrency. - Sessions and locks: create a session, then acquire a key with
acquire=<session-id>;consul lockwraps this for leader election and fencing. Sessions die on TTL expiry or node failure. - Transactions:
/v1/txnperforms atomic multi-key check/set/delete operations for coordinated configuration updates.
Intentions
An intention allows or denies traffic between a source and a destination service. Precedence is most-specific first: exact source plus exact destination beats a wildcard on either side. L7 intentions, expressed through the service-intentions config entry, can match HTTP paths, methods and headers. Intentions live in Raft and are consumed by Connect proxies; they are not an ACL mechanism for the HTTP API.
ACL model
Enable with acl { enabled = true, default_policy = "deny" }. Bootstrap exactly once with consul acl bootstrap, which prints the initial management token - store it in Vault, not on disk. The building blocks are: policy (HCL or JSON rules), role (bundle of policies plus service identities), token (the secret attached to policies/roles), auth method (OIDC/SAML/Kubernetes login that mints tokens), and service identity / node identity scoped tokens for workloads. acl_down_policy controls behaviour when servers are unreachable: allow, deny, or extend-cache (the default).
Worked example
A CI job must write config/web/* in KV and read the web service, nothing else. Rules: key_prefix "config/web/" { policy = "write" } plus service "web" { policy = "read" }, packaged as a policy and attached to a non-management token. Reasoning: key_prefix grants the subtree without exposing config/db/; a management token would pass the test but violate least privilege; a service identity alone cannot grant KV access.
Traps
Leaving default_policy = "allow"; assuming token revocation is instant under extend-cache; expecting intentions to apply to non-Connect traffic; granting key_prefix "" with write; and forgetting that ACL changes propagate through Raft, so a brand-new token can briefly fail on a lagging server.