Consul Connect Intentions: The Authorization Layer You Didn't Know You Needed
Consul Connect intentions enforce zero-trust service-to-service authorization with default-deny semantics. This blog covers the authorization model, a worked example locking down a payments service, L7 rule trade-offs, and operational gotchas like eventual consistency and namespace scoping.
01 Sept 2026, 18:01 UTC

The Problem: Identity Without Boundaries
You've deployed Consul Connect. mTLS is encrypting traffic between services. Every service has a verified identity. But here's the catch: every service can now talk to every other service. That's not zero trust—that's just encrypted chaos.
Consul Connect intentions solve this. They're the authorization layer that decides whether a source service may initiate a connection to a destination service. Default deny. Explicit allow. No application code changes required.
How Intentions Fit the Zero-Trust Model
Connect mTLS establishes service identity through SPIFFE IDs embedded in certificates. Intentions establish service authorization by mapping source identities to permitted destinations. The sidecar proxy (Envoy) enforces both at the network layer.
This separation matters. Your application code doesn't implement network authorization. The proxy does. But every mesh service must run a sidecar or register as a terminating gateway—there's no partial adoption.
Intention Mechanics: Source, Destination, Action
An intention is a rule with three core fields:
- Source: the calling service name (or "
*" for any) - Destination: the target service name
- Action:
allowordeny
Rules evaluate in order of specificity. A deny for web → api overrides a broader allow for * → api. When intentions are enabled, the default action is deny—no rule means no traffic.
Worked Example: Locking Down payments Service
Suppose you have three services: web, api, and payments. Only api should call payments. Here's the rollout:
1. Create the allow rule
consul intention create -allow api payments
Run this against your Consul server (requires intentions:write ACL token). The rule is stored in the Raft-backed store and replicated via gossip.
2. Verify the rule exists
consul intention get api payments
# Source: api
# Destination: payments
# Action: allow
3. Enable intentions (staging first)
consul intention check web payments
# Result: deny (default)
Test in staging before enabling cluster-wide. The check subcommand simulates evaluation without changing state.
4. Observe enforcement in sidecar logs
When web attempts a request to payments, Envoy logs show:
[2026-11-12T16:45:12.345Z] "RBAC access denied" "matcher": "intentions.deny" "source": "web" "destination": "payments"
The connection is refused at the proxy. api continues to work.
L7 Rules: Granular But Costly
Intentions support Layer 7 rules for HTTP methods and paths when the sidecar terminates TLS:
consul intention create -allow \
-l7-rule '{"http": {"methods": ["GET"], "paths": ["/health"]}}' \
web api
This allows web to call GET /health on api but blocks POST /charge. The trade-off: TLS termination at the sidecar adds CPU and latency overhead. For high-throughput internal traffic, L7 inspection may not be worth it. Stick to L4 (service-to-service) intentions unless you need path-level control.
Operational Trade-offs and Gotchas
- Eventual consistency: Intention changes propagate via gossip. In a multi-datacenter setup, expect seconds of divergence. Don't assume instant enforcement.
- Leader dependency: Writes go through the Raft leader. If the leader is unavailable, you can't create or modify intentions.
- ACLs ≠ Intentions: Consul ACLs protect the control plane (who can read/write service catalog, KV, intentions). Intentions protect the data plane (who can call whom). You need both.
- Enterprise namespaces: In Consul Enterprise, intentions are namespace-scoped. Cross-namespace traffic requires intentions in the destination namespace context.
Rollout Checklist
- Inventory all service-to-service calls in staging
- Create explicit
allowintentions for each legitimate pair - Run
consul intention checkfor every pair to verify - Enable intentions in staging; monitor sidecar logs for unexpected denials
- Promote to production with a maintenance window
Closing: Start With L4, Add L7 Only When Needed
Intentions turn encrypted chaos into governed communication. The mental model is simple: mTLS = identity, intentions = permission. Deploy sidecars everywhere, write explicit allow rules, and treat default deny as your safety net. L7 rules are a scalpel—use them for compliance boundaries, not every internal call.
Next step: run consul intention check against your current service graph. You'll likely find calls you didn't know existed.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.