CoursesZero-trust & workload identityIdentity-based authorization

Identity-based authz

AuthorizationPolicy, default-deny, least privilege.

Advanced35 min · lesson 10 of 15

mTLS proves who is calling; authorization decides whether they may. Identity-based authorization is where zero trust turns "every service has an identity" into "every service may reach only what it needs" — the control that actually bounds lateral movement.

Allow by identity, default-deny

An Istio AuthorizationPolicy (or Linkerd’s authorization resources) makes access decisions based on the verified source identity — the SPIFFE principal in the caller’s certificate — plus namespace and L7 attributes, never the source IP. The zero-trust posture is default-deny: no service-to-service call is permitted until a policy explicitly allows it, so a workload can reach only the specific services and methods it was granted. Because the policy matches on stable identity rather than ephemeral IPs, it stays correct as pods reschedule — the rules follow the workload, not its address.

default-deny plus a least-privilege allow
# Default-deny for the namespace: nothing is allowed unless a policy permits it.
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata: { name: deny-all, namespace: prod }
spec: {} # empty spec with no rules = deny all
# Least-privilege allow: ONLY the frontend identity may POST /checkout to api.
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata: { name: allow-checkout, namespace: prod }
spec:
selector: { matchLabels: { app: api } }
rules:
- from: [{ source: { principals: ["cluster.local/ns/prod/sa/frontend"] } }]
to: [{ operation: { methods: ["POST"], paths: ["/checkout"] } }]

Two authorization planes

Mesh authorization governs the data plane — service-to-service calls — and is distinct from Kubernetes RBAC, which governs the control plane (who can act on the API server). You want both: RBAC decides who can deploy or read secrets; mesh authz decides which running service may call which. A compromised workload under default-deny identity authz is contained to exactly the destinations its policy allows, so the blast radius of a foothold is what you explicitly granted and nothing more. Manage these policies as version-controlled code and roll them out audit-then-enforce, learning the real call graph before flipping default-deny on.

Identity-based authorization
the decision
source principal (SPIFFE)
verified caller identity
L7: methods, paths
application-aware allow
default-deny
only declared flows permitted
two planes
mesh authz
service-to-service (data plane)
K8s RBAC
API-server access (control plane)
Authorize every call by verified identity under default-deny. Mesh authz and RBAC are complementary planes — use both.
mTLS without authorization only encrypts the breach
Enabling STRICT mTLS but leaving authorization at allow-all means every workload can still call every other — encrypted. Encryption alone does not bound lateral movement; pair it with default-deny, identity-based AuthorizationPolicy so a compromised service reaches only its few authorized destinations.