Using Consul Intentions to Enforce Least-Privilege Service Access in Connect
Consul Connect sidecars allow all inbound traffic by default. Intentions provide a declarative allow/deny layer enforced by the proxy, enabling least-privilege service-to-service access without code changes.
03 Oct 2025, 08:37 UTC

Microservices running behind Consul Connect sidecar proxies accept all inbound traffic by default. That means any service registered in the catalog can reach any other service on the mesh port, even if the caller should never be allowed to talk to it. The useful takeaway is to treat Intentions as the network authorization layer for Connect and move from an implicit allow to an explicit allow/deny policy.
The default-open problem in Connect
Consul Connect provides mTLS and service discovery via a sidecar proxy that sits next to each service. The proxy terminates inbound connections and originates outbound connections. By default, the proxy enforces identity but not authorization: if a service can resolve a destination name, the connection is permitted.
Intentions are Consul's declarative service-to-service authorization objects. An Intention maps a source service name to a destination service name with an action of allow or deny. The policy is stored in Consul and pushed to sidecar proxies, which enforce it without code changes.
How Intentions are enforced
When a proxy receives a connection, it checks the source and destination service identities from the mTLS certificate and evaluates the effective Intention. If no Intention exists, the default behavior is allow. An explicit deny overrides an allow.
Intentions only apply to traffic that traverses a Connect sidecar proxy. Plain TCP/UDP traffic, or services not registered with Connect, bypass Intentions entirely.
Changes are not instant. After creating, updating, or deleting an Intention, proxies sync with Consul on an interval. The default sync interval is around 10 seconds, so the old policy can remain in effect briefly.
Worked example: web to api
Assume two Connect-enabled services: web and api. Both have sidecars running and are registered in the catalog.
Run the following from a machine with the Consul CLI and an ACL token that has intention:write and intention:read on the relevant services.
consul intention create -source web -destination api -action denyExpected check: run consul intention list and confirm an entry for source web, destination api, action deny appears. In the Consul UI, Connect → Intentions should show the direction as blocked.
Risk: a deny created here blocks all traffic from web to api, including health checks or legitimate calls, until the policy is corrected. Test in a non-production namespace first.
To allow the path again:
consul intention create -source web -destination api -action allowVerification steps to use after the change:
- Run
consul intention listto confirm the effective action. - Inspect sidecar proxy logs for the web service, e.g., when running
consul connect proxy -sidecar-for web, for log entries indicating allowed or denied decisions on connections to api. - Perform a test request through the web sidecar to api and observe success or failure consistent with the Intention.
Do not claim the test succeeded; use the checks above to confirm the policy matches expectations before promoting.
Trade-offs and limitations
Centralizing policy in Intentions reduces duplication compared to in-code checks, but it adds operational overhead. A mis-ordered or overly permissive Intention can unintentionally expose a service. Because evaluation is name-based, wildcard and prefix matching can be powerful but easy to misconfigure.
Intentions do not provide L7 authorization such as path or header checks. They are a binary allow/deny at the service level.
Propagation delay means a newly applied deny may take up to the sync interval to take effect on all proxies, creating a temporary window.
Actionable closing
For critical services, adopt a default-deny stance by creating explicit deny Intentions for all unexpected source-destination pairs, then add targeted allows. Test intention changes in staging, validate effective policy with consul intention list and the UI, and wait for the proxy sync interval before declaring the change effective.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.