🎯 LESSON OBJECTIVE__HTMLTAG_70___
- ✅ AuthorizationPolicy: ALLOW, DENY, CUSTOM rules
- ✅ RequestAuthentication: JWT token validation
- ✅ Network segmentation between namespaces__HTMLTAG_77___
- ✅ Zero-trust security model
- ✅ Audit logging for security events__HTMLTAG_81___
PART 1: AUTHORIZATIONPOLICY
Istio Authorization Flow:
Request → Envoy Proxy → AuthorizationPolicy check → Allow/Deny
Policy Actions:
- ALLOW: Explicitly permit (whitelist)
- DENY: Explicitly block (blacklist)
- CUSTOM: Delegate to external authz
Evaluation Order:
1. CUSTOM policies
2. DENY policies (if match → reject)
3. ALLOW policies (if match → allow)
4. No ALLOW policy → allow all (permissive)
5. Has ALLOW policy but no match → DENY
1.1. Default Deny All (Zero Trust)
# Deny all traffic in namespace:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: default
spec:
{}
# Empty spec = match all → no ALLOW rules → DENY all
1.2. Allow Specific Services__HTMLTAG_89___
# Allow order-service to call payment-service:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-order-to-payment
namespace: default
spec:
selector:
matchLabels:
app: payment-service
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/default/sa/order-service"
to:
- operation:
methods: ["POST"]
paths: ["/api/v1/payments/*"]
---
# Allow frontend to call API services:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-frontend-to-api
namespace: default
spec:
selector:
matchLabels:
app: order-service
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/default/sa/frontend"
to:
- operation:
methods: ["GET", "POST", "PUT"]
paths: ["/api/v1/*"]
---
# Allow ingress gateway to all services:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-ingress
namespace: default
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["istio-system"]
# Allow order-service to call payment-service:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-order-to-payment
namespace: default
spec:
selector:
matchLabels:
app: payment-service
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/default/sa/order-service"
to:
- operation:
methods: ["POST"]
paths: ["/api/v1/payments/*"]
---
# Allow frontend to call API services:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-frontend-to-api
namespace: default
spec:
selector:
matchLabels:
app: order-service
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/default/sa/frontend"
to:
- operation:
methods: ["GET", "POST", "PUT"]
paths: ["/api/v1/*"]
---
# Allow ingress gateway to all services:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-ingress
namespace: default
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["istio-system"]
1.3. Deny Specific Patterns
# Block access to admin endpoints from non-admin:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-admin-access
namespace: default
spec:
selector:
matchLabels:
app: admin-service
action: DENY
rules:
- from:
- source:
notNamespaces: ["admin"]
to:
- operation:
paths: ["/admin/*"]
---
# Block specific IP ranges:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-external-ips
namespace: default
spec:
action: DENY
rules:
- from:
- source:
ipBlocks: ["10.0.0.0/8"]
notIpBlocks: ["10.0.1.0/24"] # Except trusted subnet
PART 2: JWT AUTHENTICATION
2.1. RequestAuthentication
# Validate JWT tokens:
apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
name: jwt-auth
namespace: default
spec:
selector:
matchLabels:
app: order-service
jwtRules:
- issuer: "https://auth.myapp.com"
jwksUri: "https://auth.myapp.com/.well-known/jwks.json"
audiences:
- "api.myapp.com"
forwardOriginalToken: true
outputPayloadToHeader: x-jwt-payload
---
# Require valid JWT:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: default
spec:
selector:
matchLabels:
app: order-service
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["https://auth.myapp.com/*"]
when:
- key: request.auth.claims[role]
values: ["user", "admin"]
2.2. Role-Based Access (JWT Claims)
# Admin-only endpoints:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: admin-only
namespace: default
spec:
selector:
matchLabels:
app: admin-service
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["https://auth.myapp.com/*"]
to:
- operation:
paths: ["/admin/*"]
when:
- key: request.auth.claims[role]
values: ["admin"]
---
# Read-only for viewers:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: viewer-read-only
namespace: default
spec:
selector:
matchLabels:
app: order-service
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["https://auth.myapp.com/*"]
to:
- operation:
methods: ["GET"]
when:
- key: request.auth.claims[role]
values: ["viewer"]
PART 3: NAMESPACE SEGMENTATION__HTMLTAG_101___
# Isolate namespaces:
# default ←→ messaging (allowed)
# default ←→ database (allowed)
# default ←X→ monitoring (blocked)
# Allow default → messaging:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-from-default
namespace: messaging
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["default"]
# Allow default → database:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-from-default
namespace: database
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["default"]
- from:
- source:
namespaces: ["monitoring"]
to:
- operation:
methods: ["GET"]
paths: ["/metrics"]
# Isolate namespaces:
# default ←→ messaging (allowed)
# default ←→ database (allowed)
# default ←X→ monitoring (blocked)
# Allow default → messaging:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-from-default
namespace: messaging
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["default"]
# Allow default → database:
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-from-default
namespace: database
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["default"]
- from:
- source:
namespaces: ["monitoring"]
to:
- operation:
methods: ["GET"]
paths: ["/metrics"]
PART 4: SECURITY AUDIT LOGGING
# Enable access logging:
apiVersion: telemetry.istio.io/v1
kind: Telemetry
metadata:
name: access-logging
namespace: istio-system
spec:
accessLogging:
- providers:
- name: envoy
filter:
expression: "response.code >= 400 || connection.mtls == false"
# View access logs:
kubectl -n default logs order-service-xxx -c istio-proxy | \
jq 'select(.response_code >= 400)'
# Check mTLS status:
istioctl authn tls-check order-service-xxx.default
# Analyze authorization denials:
kubectl -n default logs order-service-xxx -c istio-proxy | \
grep "rbac_access_denied"
💡 KEY TAKEAWAYS
- Zero Trust: Start with deny-all, explicitly allow needed paths
- AuthorizationPolicy: Service-to-service access control (who can call whom)
- RequestAuthentication: JWT validation at ingress (end-user auth)
- mTLS + AuthZ: Combined = strong identity-based security
- Namespace segmentation: Isolate blast radius of compromised services
- Audit: Log denied requests, mTLS failures for security monitoring
🎯 EXERCISES
Exercise 1: Zero Trust Lab__HTMLTAG_138___
- Apply deny-all to default namespace
- Create ALLOW policies for specific service paths
- Test: unauthorized service call → RBAC denied
Exercise 2: JWT Auth Lab__HTMLTAG_148___
- Configure RequestAuthentication with Keycloak
- Create role-based AuthorizationPolicy
- Test admin vs viewer access
📚 NEXT POST
In Lesson 28: GitOps with ArgoCD — Architecture and Installation, we will move on to the GitOps workflow for continuous deployment.