hashicorp/consul
Intentions
Intentions are the mesh's authorization layer: "is service A allowed to talk to service B over the mesh?" They are evaluated at L4 (allow/deny based on identity) and L7 (rules over HTTP method/path/header).
Pieces
| Piece | Where |
|---|---|
| Service-intentions config entry | agent/structs/config_entry_intentions.go |
| Legacy intention table (compatibility) | agent/consul/state/intention.go, agent/consul/state/intention_ce.go |
| RPC endpoint | agent/consul/intention_endpoint.go |
| HTTP endpoint | agent/intentions_endpoint.go |
| Migration leader loop | agent/consul/leader_intentions.go |
| RBAC translation for Envoy | agent/xds/rbac.go (43 KB) |
| API client | api/connect_intention.go |
| CLI | command/intention/ |
Concept
A service-intentions config entry has a destination service and a list of source ⇒ action pairs:
Kind = "service-intentions"
Name = "db"
Sources = [
{ Name = "web", Action = "allow" },
{ Name = "metrics-*", Action = "allow", Permissions = [{ Action = "allow", HTTP = { PathPrefix = "/metrics" } }] },
{ Name = "*", Action = "deny" },
]The db service accepts traffic from web, accepts only /metrics from any service whose name matches metrics-*, and denies everything else.
L7 permissions allow filtering by HTTP method, path, header presence/value, query parameters, and JWT claims (when used with a service-intentions JWT block referencing a jwt-provider config entry).
Default policy
The cluster-wide default action when no intention matches is configurable via the mesh config entry's AllowEnableV2TenancyMetadataDefaults (or a similar default_intention_policy field) and the global acl.default_policy for non-mesh aspects. Code: agent/structs/config_entry_mesh.go.
Compilation to RBAC
Envoy enforces intentions via its RBAC filter. agent/xds/rbac.go translates intentions into Envoy RBAC rules:
- Identity match — SPIFFE URI prefix (matches the source service identity from the leaf cert).
- L7 match — HTTP path, method, header, JWT claims.
- Mode —
ALLOWorDENY.
The compiled RBAC filter goes into the inbound listener of the destination's sidecar in agent/xds/listeners.go.
Legacy intentions
Before service-intentions config entries (Consul 1.9+), intentions were rows in a dedicated table with a unique-source/destination key. Code stayed for compatibility:
agent/consul/state/intention.go— legacy table.agent/consul/leader_intentions.go— migration loop that copies legacy entries into config entries.agent/consul/intention_endpoint.go— handles both legacy and config-entry-based reads/writes transparently.
The legacy CLI surface remains under command/intention/ (create, delete, match, check); new clusters should use consul config write with a service-intentions HCL.
Wildcards and matching
*source matches every service in the namespace/partition.- Prefix wildcards:
web-*matches any service whose name starts withweb-. - Action precedence: more-specific source wins over less-specific. Exact name beats prefix beats
*. - Within a source, L7 permissions are evaluated top-to-bottom; first match decides.
The matching logic lives in agent/structs/config_entry_intentions.go::SortedMatches and is exercised heavily in agent/structs/config_entry_intentions_test.go.
Streaming and propagation
Intentions are config entries — they propagate via agent/consul/config_entry_events.go and the streaming subscribe topic. When an intention changes, every relevant proxycfg.state rebuilds its snapshot, the xDS server emits new RBAC filters, and Envoy applies them within seconds without dropping connections.
Operator workflow
# Quick allow
consul intention create web db
# Read all intentions for db
consul intention match -destination -type service db
# Apply via config entry (recommended)
consul config write intentions.hcl
# Check whether traffic would be allowed (offline match)
consul intention check web dbconsul intention list reads the unified set; the CLI hides the legacy/config-entry split.
ACL gating
Editing intentions for a destination service requires intentions:write on that service. The check is enforced server-side in agent/consul/intention_endpoint.go and surfaced via acl.IntentionDefault* methods in acl/acl.go.
Integration points
- Service mesh — every sidecar's inbound listener has the RBAC filter built from intentions.
- API gateway — uses the same intention machinery to enforce per-route policies between the gateway listener and the upstream service.
- JWT providers — referenced by
service-intentionsfor claims-based authorization. - Audit logging — intention writes are logged (Enterprise has a fuller audit trail; CE emits standard log lines).
Entry points for modification
- Add a new L7 match dimension: extend
agent/structs/config_entry_intentions.goand the RBAC translator inagent/xds/rbac.go. - Tune migration cadence:
agent/consul/leader_intentions.go. - Add tests:
agent/structs/config_entry_intentions_test.goalready covers most edge cases — extend the table-driven cases there.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.