Consul ACLs don’t just grant permissions; they fundamentally shift how you think about trust by treating every service request as potentially hostile.

Let’s see this in action. Imagine two services, frontend and backend, and we want frontend to be able to read data from backend but not write to it.

First, we need a Consul token for the frontend service. We’ll create a policy that grants read access to backend and then generate a token for that policy.

# Create the policy file
cat <<EOF > frontend-read-backend.hcl
policy {
  name = "frontend-read-backend"
  rules = <<EOF
service_prefix "" {
  policy = "read"
}
service "backend" {
  policy = "read"
}
EOF
}
EOF

# Apply the policy to Consul
consul policy create -name frontend-read-backend -description "Allow frontend to read backend" -rules @frontend-read-backend.hcl

# Generate a token for the frontend service
consul acl token create -policy-name frontend-read-backend -name frontend-token -description "Token for frontend service"

This command will output a token like abc123def456.... We’ll set this token as an environment variable for the frontend service.

export CONSUL_HTTP_TOKEN="abc123def456..."

Now, when frontend makes a request to backend (e.g., consul kv get backend/data), Consul checks the token associated with the frontend service. The policy attached to frontend-token allows read operations on service "backend", so the request succeeds.

If frontend tried to write data to backend (e.g., consul kv put backend/data value=new), the ACL policy would deny it because only read permission was granted.

The mental model here is about least privilege. Instead of a broad "network access allowed" scenario, each service has a specific, granular set of permissions defined by its token and associated policies. Consul acts as the gatekeeper, inspecting every API call or service-to-service interaction against these defined rules.

The service_prefix "" rule is a bit of a gotcha if you’re not careful. It grants read access to all services by default. If you then try to restrict access to a specific service, like backend, the service_prefix "" rule might still allow broader read access than intended if not managed carefully. It’s often better to start with a more restrictive policy and explicitly grant access where needed, rather than starting broad and trying to revoke.

The next step is to ensure your services are correctly registered with Consul, so their identity can be properly authenticated and authorized.

Want structured learning?

Take the full Consul course →