What Nobody Has Forbidden Is Allowed
After the move to STRICT in the previous report, every connection in the mesh is encrypted and mutually authenticated. Sounds like mission accomplished. Except: every workload is still allowed to talk to every other one.
- Date
- Topic
- AuthorizationPolicy
- Sources
- 3
- Reading time
- 2 min
- Version
- Translation
mTLS answers the identity question. That does not authorize anything. As long as no AuthorizationPolicy exists, Istio lets every authenticated call through. The billing service is allowed to call the neighboring team’s admin endpoint, cleanly encrypted, with a valid certificate. The audit log looks exemplary, yet segmentation is completely missing.
Figure as text
The AuthorizationPolicy evaluation as a three-step flowchart: an authenticated request passes first through CUSTOM (external authorization, if configured), then DENY (explicit denials, one match ends everything), then ALLOW (allow list, if one exists). Marked in red, the silent default: if no ALLOW policy exists, the request stays allowed and bypasses the entire check. Below, the pattern (an empty ALLOW policy per namespace flips the default to deny) and the trap (stacking only DENY policies sets no default).
The evaluation logic in three steps: first the CUSTOM policies run (external authorization), then all DENY policies, then the ALLOW policies. If a DENY matches, that is the end of it. If no ALLOW policy exists for the workload, the request is allowed. If at least one exists and none matches, it is denied.
The pattern is in that last sentence: an empty ALLOW policy per namespace, with no rules at all, matches nothing and thereby flips the default to deny. From then on, every allowed path is a deliberate, readable decision. The typical trap goes the other way round: anyone who only stacks DENY policies forbids individual cases and still has no default. Everything without a DENY match stays open.
You know the ownership question from reports #4 and #6, and it applies here unchanged: policies with local effect belong to the tenant, who knows who is allowed to call their service. The mesh-wide default belongs to the platform.
For decision makers: in a network review, nobody would sign off on a firewall that lets everything through by default. In the mesh, exactly this state often sits in production for years, with a compliance checkmark on top.
What someone has forbidden is forbidden. Everything else goes through.
An honest question for the room: how many of your namespaces would already have a default-deny policy today if you checked right now?