セキュリティクイズ
対応バージョン: Istio 1.28.0 EKS バージョン: 1.34 (Kubernetes 1.28+) 最終更新: February 23, 2026
このクイズでは、Istio のセキュリティ機能に関する理解度を確認します。
選択問題(1~5)
問題 1: PeerAuthentication モード
PeerAuthentication における PERMISSIVE mTLS モードを正しく説明しているのはどれですか?
A. mTLS と平文トラフィックの両方を許可する B. mTLS のみを許可し、平文を拒否する C. すべてのトラフィックを拒否する D. mTLS を無効にする
回答を表示
回答: A
PERMISSIVE モードは、段階的な移行をサポートするために mTLS と平文トラフィックの両方を許可します。
解説:
PeerAuthentication mTLS モード:
| モード | 説明 | 使用シナリオ |
|---|---|---|
| PERMISSIVE | mTLS + 平文の両方を許可 | 段階的な移行、混在環境 |
| STRICT | mTLS のみを許可 | 本番環境のセキュリティ強化 |
| DISABLE | mTLS を無効化(平文のみ) | デバッグ、レガシーシステム |
PERMISSIVE モードの例:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: PERMISSIVE # Allows both mTLS + plaintext動作:
Client A (Istio Sidecar) -> [mTLS] -> Server (PERMISSIVE) Allowed
Client B (No Sidecar) -> [Plaintext] -> Server (PERMISSIVE) AllowedSTRICT モードとの比較:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: strict-mtls
namespace: production
spec:
mtls:
mode: STRICT # Only allows mTLSClient A (Istio Sidecar) -> [mTLS] -> Server (STRICT) Allowed
Client B (No Sidecar) -> [Plaintext] -> Server (STRICT) Rejected移行戦略:
Step 1: PERMISSIVE (Allow mixed traffic)
|
Step 2: Inject Sidecars to all services
|
Step 3: STRICT (Enforce mTLS)参照:
問題 2: AuthorizationPolicy アクション
次の AuthorizationPolicy 設定は何を意味しますか?
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
spec:
{}A. すべてのリクエストを許可する B. すべてのリクエストを拒否する C. ポリシーを適用しない D. mTLS のみを許可する
回答を表示
回答: B
空の spec を持つ AuthorizationPolicy は、すべてのリクエストを拒否します(デフォルト拒否)。
解説:
AuthorizationPolicy のデフォルト動作:
- ポリシーが存在しない: すべてのリクエストを許可
- 空の spec(例のようなもの): すべてのリクエストを拒否
- ルールあり: ルールに基づいて許可/拒否
デフォルト拒否パターン:
# Step 1: Deny all requests
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: default
spec: {} # Empty spec = deny all requests
---
# Step 2: Selectively allow only what's needed
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-frontend
namespace: default
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/frontend"]
to:
- operation:
methods: ["GET", "POST"]AuthorizationPolicy のアクション種別:
| action | 説明 | 優先度 |
|---|---|---|
| DENY | 明示的な拒否 | 1(最高) |
| ALLOW | 明示的な許可 | 2 |
| AUDIT | ログのみ | 3 |
| CUSTOM | 外部認証サービス | 4 |
評価順序:
1. Evaluate DENY policies -> If matched, immediately deny
| (pass)
2. Evaluate ALLOW policies -> If matched, allow
| (no match)
3. Default behavior
- If any ALLOW policy exists -> Deny
- If no ALLOW policy exists -> Allow実践例:
# Scenario: Restrict HTTP methods
---
# DENY: Prohibit DELETE
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-delete
spec:
selector:
matchLabels:
app: backend
action: DENY
rules:
- to:
- operation:
methods: ["DELETE"]
---
# ALLOW: Only allow GET, POST
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-read-write
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/frontend"]
to:
- operation:
methods: ["GET", "POST"]テスト:
# GET request -> Matches ALLOW policy -> Allowed
curl http://backend/api
# POST request -> Matches ALLOW policy -> Allowed
curl -X POST http://backend/api
# DELETE request -> Matches DENY policy -> Rejected
curl -X DELETE http://backend/api
# PUT request -> No ALLOW policy match -> Rejected
curl -X PUT http://backend/api参照:
問題 3: JWT 認証
RequestAuthentication で JWT トークンの検証に使用するフィールドはどれですか?
A. issuer と audiences B. principals と namespaces C. methods と paths D. hosts と ports
回答を表示
回答: A
RequestAuthentication は issuer フィールドと audiences フィールドを使用して JWT トークンを検証します。
解説:
JWT トークン構造:
Header.Payload.Signature
Payload example:
{
"iss": "https://auth.example.com", # issuer
"sub": "user@example.com", # subject
"aud": ["api.example.com"], # audiences
"exp": 1735689600, # expiration
"iat": 1735686000 # issued at
}RequestAuthentication 設定:
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: jwt-auth
namespace: default
spec:
selector:
matchLabels:
app: backend
jwtRules:
- issuer: "https://auth.example.com" # Validate iss field
jwksUri: "https://auth.example.com/.well-known/jwks.json"
audiences:
- "api.example.com" # Validate aud field
forwardOriginalToken: trueJWT 検証プロセス:
OIDC プロバイダーとの統合:
# Google OAuth2 example
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: google-jwt
spec:
jwtRules:
- issuer: "https://accounts.google.com"
jwksUri: "https://www.googleapis.com/oauth2/v3/certs"
audiences:
- "123456789-abcdefg.apps.googleusercontent.com"
---
# Keycloak example
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: keycloak-jwt
spec:
jwtRules:
- issuer: "https://keycloak.example.com/realms/myrealm"
jwksUri: "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/certs"
audiences:
- "myapp"AuthorizationPolicy との組み合わせ:
# 1. RequestAuthentication: Validate JWT
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: jwt-auth
spec:
selector:
matchLabels:
app: backend
jwtRules:
- issuer: "https://auth.example.com"
jwksUri: "https://auth.example.com/.well-known/jwks.json"
---
# 2. AuthorizationPolicy: Only allow authenticated requests
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-jwt
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["*"] # Only requests with JWT
to:
- operation:
methods: ["GET", "POST"]
---
# 3. AuthorizationPolicy: Only allow specific issuer
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-specific-issuer
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["https://auth.example.com/*"]テスト:
# Request without JWT -> Passes RequestAuthentication, denied by AuthorizationPolicy
curl http://backend/api
# 401 Unauthorized
# Request with valid JWT
TOKEN="eyJhbGc..."
curl -H "Authorization: Bearer $TOKEN" http://backend/api
# 200 OK参照:
問題 4: mTLS 証明書管理
Istio における mTLS 証明書のデフォルト有効期間はどれですか?
A. 1 時間 B. 24 時間 C. 7 日 D. 90 日
回答を表示
回答: B
Istio の mTLS 証明書のデフォルト有効期間は 24 時間で、自動更新されます。
解説:
Istio 証明書管理:
# Istiod configuration (defaults)
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
certificates:
- secretName: dns.example-service-account
dnsNames:
- example.comデフォルト設定:
- 証明書の有効期間: 24 時間(1 日)
- 更新タイミング: 有効期限の 8 時間前
- 更新方法: 自動(Istiod が管理)
- 証明書形式: X.509
証明書ライフサイクル:
証明書の確認:
# Check pod's mTLS certificate
istioctl proxy-config secret <pod-name> -o json
# Example output:
{
"name": "default",
"tlsCertificate": {
"certificateChain": {
"inlineBytes": "LS0tLS1CRU..."
},
"privateKey": {
"inlineBytes": "LS0tLS1CRU..."
}
},
"validationContext": {
"trustedCa": {
"inlineBytes": "LS0tLS1CRU..."
}
}
}
# Decode certificate contents
kubectl exec <pod-name> -c istio-proxy -- \
openssl x509 -text -noout -in /etc/certs/cert-chain.pem
# Example output:
Certificate:
Validity
Not Before: Jan 20 00:00:00 2025 GMT
Not After : Jan 21 00:00:00 2025 GMT # 24 hours later
Subject: O=cluster.local
X509v3 Subject Alternative Name:
URI:spiffe://cluster.local/ns/default/sa/myapp有効期間のカスタマイズ:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
# Change certificate validity period
defaultConfig:
proxyMetadata:
SECRET_TTL: "48h" # Extend to 48 hours証明書更新が失敗するシナリオ:
# Check Istiod logs
kubectl logs -n istio-system -l app=istiod
# Common issues:
# 1. Communication issues between Istiod and Envoy
# 2. RBAC permission issues
# 3. Blocked by network policies
# Manually trigger certificate renewal
kubectl delete pod <pod-name> # Pod restart reissues certificateSPIFFE ID:
Istio's mTLS certificates follow the SPIFFE (Secure Production Identity Framework For Everyone) standard.
Format: spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>
Example: spiffe://cluster.local/ns/default/sa/frontendCA 階層:
Root CA (Istiod)
+- Intermediate CA (auto-generated)
| +- frontend Pod certificate (24 hours)
| +- backend Pod certificate (24 hours)
| +- database Pod certificate (24 hours)
+- ...外部 CA 統合:
# Using external CA with Cert-Manager
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
components:
pilot:
k8s:
env:
- name: EXTERNAL_CA
value: ISTIOD_RA_KUBERNETES_API参照:
問題 5: Service Account ベースの認証
Istio でサービス間認証に使用されるアイデンティティはどれですか?
A. Pod 名 B. Service 名 C. Service Account D. Namespace 名
回答を表示
回答: C
Istio は Service Account に基づいてサービス間アイデンティティを管理します。
解説:
Service Account ベースのアイデンティティ:
# 1. Create Service Account
apiVersion: v1
kind: ServiceAccount
metadata:
name: frontend
namespace: default
---
# 2. Use Service Account in Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
template:
spec:
serviceAccountName: frontend # Used as identity
containers:
- name: frontend
image: frontend:v1SPIFFE ID 形式:
spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>
Examples:
spiffe://cluster.local/ns/default/sa/frontend
spiffe://cluster.local/ns/production/sa/backendAuthorizationPolicy での Service Account の使用:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: backend-policy
namespace: default
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
# Only allow frontend Service Account
- from:
- source:
principals:
- "cluster.local/ns/default/sa/frontend"
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/*"]
# admin Service Account allowed for all operations
- from:
- source:
principals:
- "cluster.local/ns/default/sa/admin"Service Account と Pod/Service 名の比較:
| 項目 | Service Account | Pod 名 | Service 名 |
|---|---|---|---|
| 安定性 | 安定 | 動的に変化 | 安定 |
| セキュリティ | 証明書ベース | 信頼できない | 信頼できない |
| RBAC 統合 | Kubernetes RBAC | 不可能 | 不可能 |
| mTLS | 証明書に含まれる | 含まれない | 含まれない |
実践例: 3 層アプリケーション:
# Frontend -> Backend only allowed
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: frontend
namespace: app
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: backend
namespace: app
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: database
namespace: app
---
# Backend policy: Only allow Frontend access
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: backend-policy
namespace: app
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/app/sa/frontend"]
---
# Database policy: Only allow Backend access
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: database-policy
namespace: app
spec:
selector:
matchLabels:
app: database
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/app/sa/backend"]Service Account の確認:
# Check pod's Service Account
kubectl get pod <pod-name> -o jsonpath='{.spec.serviceAccountName}'
# Check SPIFFE ID in mTLS certificate
istioctl proxy-config secret <pod-name> -o json | \
jq -r '.dynamicActiveSecrets[0].secret.tlsCertificate.certificateChain.inlineBytes' | \
base64 -d | openssl x509 -text -noout | grep URI
# Output:
# URI:spiffe://cluster.local/ns/default/sa/frontendNamespace をまたぐ通信:
# Allow production namespace's frontend -> staging namespace's backend access
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: backend-policy
namespace: staging
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/production/sa/frontend"
namespaces:
- "production"参照:
記述問題(6~10)
問題 6: デフォルト拒否セキュリティポリシーの実装
Kubernetes クラスターで Istio を使用し、デフォルト拒否セキュリティポリシーを実装する手順を段階的に説明してください。必須リソース(PeerAuthentication、AuthorizationPolicy)と例外処理の方法を含めてください。
回答を表示
回答:
デフォルト拒否セキュリティポリシーの実装:
ステップ 1: mTLS STRICT モードを有効化
すべてのサービス間通信で mTLS を使用するよう強制します:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT # Enforce mTLSスコープ:
istio-systemNamespace にデプロイ -> メッシュ全体に適用- 特定の Namespace にデプロイ -> その Namespace のみに適用
- selector を使用 -> 特定の workload のみに適用
ステップ 2: すべてのトラフィックを拒否(デフォルト拒否)
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: default
spec: {} # Empty spec = deny all requestsこのポリシーの適用後:
- すべてのインバウンドトラフィックが拒否される
- サービス間通信がブロックされる
- 外部アクセスがブロックされる
ステップ 3: 必要な通信を選択的に許可
例 1: Frontend -> Backend 通信を許可
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-frontend-to-backend
namespace: default
spec:
selector:
matchLabels:
app: backend # Apply to Backend
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/default/sa/frontend" # Only allow Frontend
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/*"]例 2: Backend -> Database 通信を許可
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-backend-to-database
namespace: default
spec:
selector:
matchLabels:
app: database
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/default/sa/backend"
to:
- operation:
ports: ["5432"] # PostgreSQL portステップ 4: Ingress Gateway ポリシー
外部トラフィックを許可するには Ingress Gateway 用のポリシーが必要です:
# Allow traffic to Ingress Gateway
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-ingress
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
action: ALLOW
rules:
- to:
- operation:
ports: ["80", "443"]
---
# Allow Ingress Gateway -> Frontend
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-gateway-to-frontend
namespace: default
spec:
selector:
matchLabels:
app: frontend
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"ステップ 5: ヘルスチェックと Readiness Probe の例外
Kubernetes のヘルスチェックがブロックされないように例外を処理します:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-health-checks
namespace: default
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
# Allow Kubernetes health checks
- to:
- operation:
paths: ["/health", "/ready"]
methods: ["GET"]または、PeerAuthentication で特定のポートを除外します:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default
spec:
mtls:
mode: STRICT
portLevelMtls:
8080:
mode: DISABLE # Disable mTLS for health check portステップ 6: 監視とロギングの例外
Prometheus によるメトリクス収集を許可します:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-prometheus
namespace: default
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["istio-system"]
principals: ["cluster.local/ns/istio-system/sa/prometheus"]
to:
- operation:
paths: ["/stats/prometheus"]
methods: ["GET"]完全な例: 3 層アプリケーション
# 1. mTLS STRICT
---
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: production
spec:
mtls:
mode: STRICT
# 2. Deny-by-default
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: production
spec: {}
# 3. Ingress -> Frontend
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-ingress-to-frontend
namespace: production
spec:
selector:
matchLabels:
app: frontend
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"]
# 4. Frontend -> Backend
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-frontend-to-backend
namespace: production
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/production/sa/frontend"]
to:
- operation:
methods: ["GET", "POST", "PUT", "DELETE"]
paths: ["/api/*"]
# 5. Backend -> Database
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-backend-to-database
namespace: production
spec:
selector:
matchLabels:
app: database
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/production/sa/backend"]
# 6. Health Checks
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-health-checks
namespace: production
spec:
action: ALLOW
rules:
- to:
- operation:
paths: ["/health", "/ready", "/live"]
# 7. Prometheus metrics
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-prometheus
namespace: production
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["istio-system"]
to:
- operation:
paths: ["/stats/prometheus"]テストと検証:
# 1. Frontend -> Backend (allowed)
kubectl exec -it <frontend-pod> -- curl http://backend/api
# 200 OK
# 2. Direct Database access (denied)
kubectl exec -it <frontend-pod> -- curl http://database:5432
# 403 RBAC: access denied
# 3. External direct Backend access (denied)
curl http://<ingress-gateway>/backend
# 403 RBAC: access denied
# 4. Normal path (allowed)
curl http://<ingress-gateway>/frontend
# 200 OKベストプラクティス:
- 段階的な適用:
- まず mTLS を PERMISSIVE モードで有効化する
- すべての Service に Sidecar が inject されていることを確認する
- STRICT モードに切り替える
- デフォルト拒否ポリシーを適用する
- 最小権限の原則:
- 必要最小限の通信のみを許可する
- HTTP メソッドを制限する(GET のみ、POST のみなど)
- パスを制限する(/api/* のみなど)
- 例外処理:
- ヘルスチェックの例外を必ず処理する
- 監視システムのアクセスを許可する
- Ingress Gateway ポリシーを設定する
- テスト:
- 各ポリシー適用後にテストする
- 副作用(ログ、メトリクス)を確認する
- ロールバック計画を準備する
参照:
問題 7: JWT + mTLS 二重認証
Istio で **エンドユーザー認証(JWT)とサービス間認証(mTLS)**を組み合わせて使用するシナリオを実装してください。OAuth2/OIDC プロバイダー(例: Keycloak)との統合方法を含めてください。
回答を表示
回答:
JWT + mTLS 二重認証アーキテクチャ:
User
| (JWT Token)
Ingress Gateway (Validate JWT with RequestAuthentication)
| (mTLS)
Frontend (Validate mTLS with PeerAuthentication)
| (mTLS)
Backendステップ 1: Keycloak のセットアップ
# Create Keycloak Realm
Realm: myrealm
# Create Client
Client ID: myapp
Access Type: confidential
Valid Redirect URIs: http://myapp.example.com/*
# Get JWKS URI
https://keycloak.example.com/realms/myrealm/protocol/openid-connect/certsステップ 2: mTLS を有効化(サービス間認証)
# Apply STRICT mTLS to entire mesh
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICTステップ 3: JWT 認証を設定(エンドユーザー認証)
# Validate JWT at Ingress Gateway
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: jwt-ingress
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
jwtRules:
- issuer: "https://keycloak.example.com/realms/myrealm"
jwksUri: "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/certs"
audiences:
- "myapp"
forwardOriginalToken: true # Forward JWT to backend
outputPayloadToHeader: "x-jwt-payload" # Extract payload to headerステップ 4: AuthorizationPolicy を設定
Ingress Gateway ポリシー
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: ingress-jwt-policy
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
action: ALLOW
rules:
# Only allow requests with JWT
- from:
- source:
requestPrincipals: ["*"]
to:
- operation:
paths: ["/api/*", "/app/*"]
# Allow health checks without JWT
- to:
- operation:
paths: ["/health", "/ready"]Backend ポリシー
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: backend-jwt-mtls-policy
namespace: default
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
# 1. mTLS: Only allow Frontend Service Account
# 2. JWT: Must have valid JWT
- from:
- source:
principals: ["cluster.local/ns/default/sa/frontend"]
requestPrincipals: ["https://keycloak.example.com/realms/myrealm/*"]
to:
- operation:
methods: ["GET", "POST"]ステップ 5: ロールベースアクセス制御
JWT claim に基づくきめ細かな認可:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: backend-rbac
namespace: default
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
# Only Admin role allowed for DELETE
- from:
- source:
principals: ["cluster.local/ns/default/sa/frontend"]
requestPrincipals: ["*"]
when:
- key: request.auth.claims[roles]
values: ["admin"]
to:
- operation:
methods: ["DELETE"]
paths: ["/api/admin/*"]
# User role only allowed GET, POST
- from:
- source:
principals: ["cluster.local/ns/default/sa/frontend"]
requestPrincipals: ["*"]
when:
- key: request.auth.claims[roles]
values: ["user"]
to:
- operation:
methods: ["GET", "POST"]
paths: ["/api/users/*"]ステップ 6: JWT ペイロードの利用
Backend で JWT ペイロードを使用します:
# EnvoyFilter to pass JWT claims as headers
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: jwt-claim-to-header
namespace: istio-system
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.jwt_authn"
patch:
operation: INSERT_AFTER
value:
name: envoy.lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inline_code: |
function envoy_on_request(request_handle)
local payload = request_handle:headers():get("x-jwt-payload")
if payload then
-- Base64 decode and JSON parse
local json = require("json")
local decoded = json.decode(payload)
-- Pass user info as headers
request_handle:headers():add("x-user-id", decoded.sub)
request_handle:headers():add("x-user-email", decoded.email)
request_handle:headers():add("x-user-roles", table.concat(decoded.roles, ","))
end
endステップ 7: 完全な例
Ingress Gateway
---
# JWT validation
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: jwt-ingress
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
jwtRules:
- issuer: "https://keycloak.example.com/realms/myrealm"
jwksUri: "https://keycloak.example.com/realms/myrealm/protocol/openid-connect/certs"
audiences: ["myapp"]
forwardOriginalToken: true
---
# Require JWT
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["*"]Frontend
---
# mTLS STRICT
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: frontend-mtls
namespace: default
spec:
selector:
matchLabels:
app: frontend
mtls:
mode: STRICT
---
# Only allow Ingress Gateway access
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: frontend-policy
namespace: default
spec:
selector:
matchLabels:
app: frontend
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"]
requestPrincipals: ["*"]Backend
---
# mTLS STRICT
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: backend-mtls
namespace: default
spec:
selector:
matchLabels:
app: backend
mtls:
mode: STRICT
---
# Only allow Frontend access + Require JWT
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: backend-policy
namespace: default
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/frontend"]
requestPrincipals: ["https://keycloak.example.com/realms/myrealm/*"]テスト:
# 1. Get token from Keycloak
TOKEN=$(curl -X POST \
"https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token" \
-d "client_id=myapp" \
-d "client_secret=<secret>" \
-d "grant_type=password" \
-d "username=user@example.com" \
-d "password=password123" \
| jq -r '.access_token')
# 2. Call API with JWT
curl -H "Authorization: Bearer $TOKEN" \
http://myapp.example.com/api/users
# 3. Call without JWT (fails)
curl http://myapp.example.com/api/users
# 401 Unauthorized
# 4. Invalid JWT (fails)
curl -H "Authorization: Bearer invalid-token" \
http://myapp.example.com/api/users
# 401 Unauthorizedセキュリティ上の利点:
- 二重認証:
- JWT: エンドユーザーのアイデンティティを検証
- mTLS: サービスのアイデンティティを検証
- 多層防御:
- Gateway で JWT を検証
- サービス間の mTLS による暗号化通信
- AuthorizationPolicy によるきめ細かな認可
- ロールベースアクセス制御(RBAC):
- JWT claim に基づく認可管理
- 動的な権限更新(Keycloak で管理)
参照:
問題 8: 外部 Service アクセス制御
Istio で Egress トラフィックを制御し、特定の外部 Service へのアクセスのみを許可する方法を説明してください。ServiceEntry、VirtualService、AuthorizationPolicy を使用した完全な例を含めてください。
回答を表示
回答:
Egress トラフィック制御戦略:
ステップ 1: Egress トラフィックのデフォルトモードを確認
Istio は 2 つの Egress モードをサポートします:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
outboundTrafficPolicy:
mode: REGISTRY_ONLY # or ALLOW_ANYモード比較:
| モード | 説明 | セキュリティ |
|---|---|---|
| ALLOW_ANY | すべての外部トラフィックを許可(デフォルト) | 低 |
| REGISTRY_ONLY | ServiceEntry に登録された Service のみを許可 | 高 |
REGISTRY_ONLY モードへの切り替え:
istioctl install --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLYステップ 2: ServiceEntry で外部 Service を登録
例 1: HTTPS API(GitHub)
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: github-api
namespace: default
spec:
hosts:
- api.github.com
ports:
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS例 2: HTTP API(httpbin)
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: httpbin-ext
namespace: default
spec:
hosts:
- httpbin.org
ports:
- number: 80
name: http
protocol: HTTP
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS例 3: 特定の IP アドレス
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: external-database
namespace: default
spec:
hosts:
- database.external.com
addresses:
- 203.0.113.10 # Specific IP
ports:
- number: 5432
name: postgres
protocol: TCP
location: MESH_EXTERNAL
resolution: STATIC
endpoints:
- address: 203.0.113.10ステップ 3: VirtualService でトラフィックを制御
タイムアウトとリトライの設定
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: github-api-vs
namespace: default
spec:
hosts:
- api.github.com
http:
- timeout: 10s
retries:
attempts: 3
perTryTimeout: 3s
retryOn: 5xx,reset,connect-failure
route:
- destination:
host: api.github.comヘッダーを追加(API Key)
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: external-api-vs
namespace: default
spec:
hosts:
- api.example.com
http:
- headers:
request:
add:
X-API-Key: "my-secret-key"
route:
- destination:
host: api.example.comステップ 4: AuthorizationPolicy によるアクセス制御
特定の Service Account のみを許可
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-github-api
namespace: default
spec:
action: ALLOW
rules:
# Only allow Backend Service Account to access GitHub API
- from:
- source:
principals: ["cluster.local/ns/default/sa/backend"]
to:
- operation:
hosts: ["api.github.com"]特定のパスのみを許可
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-specific-api
namespace: default
spec:
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/backend"]
to:
- operation:
hosts: ["api.example.com"]
paths: ["/v1/data", "/v1/status"]
methods: ["GET"]ステップ 5: Egress Gateway の使用(任意)
Egress を一元的に制御します:
# Deploy Egress Gateway
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
components:
egressGateways:
- name: istio-egressgateway
enabled: true
k8s:
replicas: 2
---
# Define Gateway
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: egress-gateway
namespace: default
spec:
selector:
istio: egressgateway
servers:
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- api.github.com
tls:
mode: PASSTHROUGH # Pass TLS traffic through
---
# DestinationRule
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: egress-gateway-dr
namespace: default
spec:
host: istio-egressgateway.istio-system.svc.cluster.local
subsets:
- name: github
---
# VirtualService: Pod -> Egress Gateway
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: github-through-egress
namespace: default
spec:
hosts:
- api.github.com
gateways:
- mesh # From Sidecar
- egress-gateway
http:
- match:
- gateways:
- mesh # Starting from Pod
port: 443
route:
- destination:
host: istio-egressgateway.istio-system.svc.cluster.local
subset: github
port:
number: 443
- match:
- gateways:
- egress-gateway # From Egress Gateway
port: 443
route:
- destination:
host: api.github.com
port:
number: 443トラフィックフロー:
Pod -> Sidecar -> Egress Gateway -> External Serviceステップ 6: 完全な例
シナリオ: Backend Service の GitHub API へのアクセスのみを許可
# 1. Set REGISTRY_ONLY mode
---
apiVersion: v1
kind: ConfigMap
metadata:
name: istio
namespace: istio-system
data:
mesh: |
outboundTrafficPolicy:
mode: REGISTRY_ONLY
# 2. GitHub API ServiceEntry
---
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: github-api
namespace: default
spec:
hosts:
- api.github.com
ports:
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS
# 3. VirtualService: Timeout and retry
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: github-api-vs
namespace: default
spec:
hosts:
- api.github.com
http:
- timeout: 30s
retries:
attempts: 3
perTryTimeout: 10s
retryOn: 5xx,reset,connect-failure
route:
- destination:
host: api.github.com
port:
number: 443
# 4. AuthorizationPolicy: Only allow Backend
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-backend-github
namespace: default
spec:
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/default/sa/backend"]
to:
- operation:
hosts: ["api.github.com"]
methods: ["GET", "POST"]
# 5. Deny-by-default (block all other egress)
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all-egress
namespace: default
spec:
action: DENY
rules:
- to:
- operation:
hosts: ["*"]テスト:
# 1. Call GitHub API from Backend (allowed)
kubectl exec -it <backend-pod> -- \
curl -I https://api.github.com/users/octocat
# 200 OK
# 2. Call GitHub API from Frontend (denied)
kubectl exec -it <frontend-pod> -- \
curl -I https://api.github.com/users/octocat
# Connection refused
# 3. Call other external service from Backend (denied)
kubectl exec -it <backend-pod> -- \
curl -I https://google.com
# Connection refused (No ServiceEntry)監視:
# Check egress traffic
kubectl exec -it <backend-pod> -c istio-proxy -- \
curl localhost:15000/stats/prometheus | grep upstream_cx_total
# Check ServiceEntry
istioctl proxy-config clusters <backend-pod> | grep githubセキュリティ上の利点:
- 許可リスト方式: ServiceEntry に登録された Service へのアクセスのみを許可
- Service Account ベースの制御: 特定の Service だけが外部 API を呼び出せる
- 監査とロギング: すべての Egress トラフィックをログに記録できる
- 一元管理: Egress Gateway を通じてすべての外部トラフィックを監視
参照:
問題 9: セキュリティ監査とロギング
Istio でセキュリティ関連イベントを監査してログに記録する方法を説明してください。AuthorizationPolicy の AUDIT アクションとAccess Log設定を含めてください。
回答を表示
回答:
Istio セキュリティ監査とロギング戦略:
1. AuthorizationPolicy AUDIT アクション
AUDIT アクションはトラフィックをブロックせずにログに記録します。
基本 AUDIT ポリシー
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: audit-all-requests
namespace: default
spec:
selector:
matchLabels:
app: backend
action: AUDIT
rules:
- {} # Audit all requests特定の条件のみを監査
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: audit-sensitive-operations
namespace: default
spec:
selector:
matchLabels:
app: backend
action: AUDIT
rules:
# Audit DELETE operations
- to:
- operation:
methods: ["DELETE"]
# Audit Admin API access
- to:
- operation:
paths: ["/api/admin/*"]
# Audit external IP access
- from:
- source:
notNamespaces: ["default", "production"]2. Access Logging を有効化
メッシュ全体の Access Logging を有効化
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
accessLogFile: /dev/stdout
accessLogEncoding: JSON
accessLogFormat: |
{
"start_time": "%START_TIME%",
"method": "%REQ(:METHOD)%",
"path": "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%",
"protocol": "%PROTOCOL%",
"response_code": "%RESPONSE_CODE%",
"response_flags": "%RESPONSE_FLAGS%",
"bytes_received": "%BYTES_RECEIVED%",
"bytes_sent": "%BYTES_SENT%",
"duration": "%DURATION%",
"upstream_service_time": "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%",
"x_forwarded_for": "%REQ(X-FORWARDED-FOR)%",
"user_agent": "%REQ(USER-AGENT)%",
"request_id": "%REQ(X-REQUEST-ID)%",
"authority": "%REQ(:AUTHORITY)%",
"upstream_host": "%UPSTREAM_HOST%",
"upstream_cluster": "%UPSTREAM_CLUSTER%",
"upstream_local_address": "%UPSTREAM_LOCAL_ADDRESS%",
"downstream_local_address": "%DOWNSTREAM_LOCAL_ADDRESS%",
"downstream_remote_address": "%DOWNSTREAM_REMOTE_ADDRESS%",
"requested_server_name": "%REQUESTED_SERVER_NAME%",
"route_name": "%ROUTE_NAME%"
}特定の Namespace のみに適用
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: access-logging
namespace: production
spec:
accessLogging:
- providers:
- name: envoy3. セキュリティ監査向けのカスタムログフィルター
mTLS 情報を含める
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
accessLogFile: /dev/stdout
accessLogFormat: |
[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%"
%RESPONSE_CODE% %RESPONSE_FLAGS%
%BYTES_RECEIVED% %BYTES_SENT% %DURATION%
"%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%"
"%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%"
"%UPSTREAM_HOST%" "%DOWNSTREAM_REMOTE_ADDRESS%"
mtls=%DOWNSTREAM_PEER_ISSUER% peer=%DOWNSTREAM_PEER_URI_SAN%認可情報を含める
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: security-audit-logging
namespace: default
spec:
accessLogging:
- providers:
- name: envoy
filter:
expression: response.code >= 400 # Log only errors4. 外部ロギングシステムとの統合
FluentBit を使用して CloudWatch に送信
apiVersion: v1
kind: ConfigMap
metadata:
name: fluent-bit-config
namespace: istio-system
data:
fluent-bit.conf: |
[SERVICE]
Flush 5
Log_Level info
[INPUT]
Name tail
Path /var/log/containers/*istio-proxy*.log
Parser docker
Tag istio.proxy
Refresh_Interval 5
[FILTER]
Name parser
Match istio.proxy
Parser istio-access-log
[OUTPUT]
Name cloudwatch_logs
Match istio.proxy
region us-east-1
log_group_name /aws/eks/istio/access-logs
log_stream_prefix proxy-
auto_create_group trueElasticsearch 統合
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: elasticsearch-logging
namespace: default
spec:
accessLogging:
- providers:
- name: envoy
filter:
expression: |
response.code >= 400 ||
request.headers['x-audit'] == 'true'5. 完全なセキュリティ監査設定
# 1. AUDIT Policy: Audit sensitive operations
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: audit-sensitive
namespace: production
spec:
selector:
matchLabels:
app: backend
action: AUDIT
rules:
# DELETE operations
- to:
- operation:
methods: ["DELETE"]
# Admin API
- to:
- operation:
paths: ["/api/admin/*"]
# Access from outside production
- from:
- source:
notNamespaces: ["production"]
# 2. DENY Policy: Actually block
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-unauthorized
namespace: production
spec:
selector:
matchLabels:
app: backend
action: DENY
rules:
# Block admin access from outside production
- from:
- source:
notNamespaces: ["production"]
to:
- operation:
paths: ["/api/admin/*"]
# 3. Access Logging: JSON format
---
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
name: security-logging
namespace: production
spec:
accessLogging:
- providers:
- name: envoy
filter:
expression: |
response.code >= 400 ||
request.method == "DELETE" ||
request.url_path.startsWith("/api/admin")6. ログ分析クエリ
Prometheus クエリ
# Authorization deny count
sum(rate(
envoy_http_rbac_denied_total[5m]
)) by (namespace, pod)
# AUDIT action trigger count
sum(rate(
envoy_http_rbac_logged_total[5m]
)) by (namespace, pod)
# 403 Forbidden responses
sum(rate(
istio_requests_total{
response_code="403"
}[5m]
)) by (destination_service_name)CloudWatch Insights クエリ
# Audit DELETE operations
fields @timestamp, method, path, response_code, downstream_remote_address
| filter method = "DELETE"
| sort @timestamp desc
| limit 100
# Admin API access
fields @timestamp, path, response_code, downstream_remote_address, user_agent
| filter path like /api/admin/
| sort @timestamp desc
# Failed Authorization
fields @timestamp, path, response_code, response_flags
| filter response_code = 403
| stats count() by bin(5m)7. Grafana ダッシュボード
# Panel 1: Authorization deny rate
rate(envoy_http_rbac_denied_total[5m])
# Panel 2: AUDIT log trend
rate(envoy_http_rbac_logged_total[5m])
# Panel 3: 403 response distribution
sum by (destination_service_name) (
rate(istio_requests_total{response_code="403"}[5m])
)
# Panel 4: Sensitive operations (DELETE)
sum by (destination_service_name) (
rate(istio_requests_total{request_method="DELETE"}[5m])
)8. アラート設定
# PrometheusRule
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: istio-security-alerts
namespace: monitoring
spec:
groups:
- name: istio-security
interval: 30s
rules:
# High Authorization deny rate
- alert: HighAuthorizationDenyRate
expr: |
sum(rate(envoy_http_rbac_denied_total[5m])) by (namespace)
> 10
for: 5m
labels:
severity: warning
annotations:
summary: "High authorization deny rate in {{ $labels.namespace }}"
description: "{{ $value }} denials per second"
# Unauthorized Admin API access attempt
- alert: UnauthorizedAdminAccess
expr: |
sum(rate(istio_requests_total{
request_url_path=~"/api/admin/.*",
response_code="403"
}[5m])) > 0
for: 1m
labels:
severity: critical
annotations:
summary: "Unauthorized admin API access attempt"ベストプラクティス:
- 先に AUDIT、後で DENY:
- 新しいポリシーは AUDIT から開始する
- ログを分析してから DENY に切り替える
- 選択的なロギング:
- すべてのトラフィックをログに記録するとコストが増加する
- 機微な操作のみをログに記録する
- ログ保持:
- セキュリティ監査: 最低 90 日間
- コンプライアンス: 1 年以上
- リアルタイムアラート:
- 未認可アクセス試行に即時アラートを出す
- 異常なパターンを検出する
参照:
問題 10: ゼロトラストネットワークの実装
Istio を使用してゼロトラストネットワークの原則を実装する方法を説明してください。mTLS STRICT、デフォルト拒否、最小権限の原則を適用する完全な例を含めてください。
回答を表示
回答:
ゼロトラストネットワークの原則:
- 決して信頼せず、常に検証する: すべての通信を検証する
- 最小権限: 必要最小限の権限のみを付与する
- 侵害を前提とする: 侵害を想定して設計する
Istio ゼロトラストアーキテクチャ:
# 1. mTLS STRICT (Only encrypted communication allowed)
# 2. Deny-by-default (Deny all traffic by default)
# 3. Explicit Allow (Explicitly allow required communication only)
# 4. Identity-based (Based on Service Account)
# 5. Fine-grained (Path/method level control)ステップ 1: mTLS STRICT モード
すべてのサービス間通信を暗号化します:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT検証:
# Check mTLS status
istioctl authn tls-check <pod-name>.<namespace>
# Output:
# HOST:PORT STATUS SERVER CLIENT AUTHN POLICY
# backend.default.svc.cluster.local OK mTLS mTLS default/defaultステップ 2: デフォルト拒否ポリシー
グローバル拒否ポリシー
# Apply to all Namespaces
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: default
spec: {}
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: production
spec: {}ステップ 3: 最小権限
シナリオ: 3 層 Web アプリケーション
User -> Ingress Gateway -> Frontend -> Backend -> DatabaseService Account を作成
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: frontend
namespace: app
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: backend
namespace: app
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: database
namespace: appIngress Gateway -> Frontend
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-ingress-to-frontend
namespace: app
spec:
selector:
matchLabels:
app: frontend
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"Frontend -> Backend
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-frontend-to-backend
namespace: app
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/app/sa/frontend"
to:
- operation:
methods: ["GET", "POST", "PUT"] # Exclude DELETE
paths: ["/api/v1/*"] # Only v1 API
ports: ["8080"] # Specific port onlyBackend -> Database
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-backend-to-database
namespace: app
spec:
selector:
matchLabels:
app: database
action: ALLOW
rules:
- from:
- source:
principals:
- "cluster.local/ns/app/sa/backend"
to:
- operation:
ports: ["5432"] # PostgreSQL onlyステップ 4: Namespace の分離
他の Namespace からのアクセスをブロックします:
# Block Production -> Staging
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-cross-namespace
namespace: production
spec:
action: DENY
rules:
- from:
- source:
notNamespaces: ["production", "istio-system"]ステップ 5: 時間ベースのアクセス制御
EnvoyFilter で時間ベースの制御を実装します:
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: time-based-access
namespace: app
spec:
workloadSelector:
labels:
app: backend
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
patch:
operation: INSERT_BEFORE
value:
name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inline_code: |
function envoy_on_request(request_handle)
local hour = tonumber(os.date("%H"))
-- Allow only business hours (9AM-6PM)
if hour < 9 or hour >= 18 then
request_handle:respond(
{[":status"] = "403"},
"Access denied outside business hours"
)
end
endステップ 6: Egress トラフィック制御
外部 Service へのアクセスを制限します:
# REGISTRY_ONLY mode
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
outboundTrafficPolicy:
mode: REGISTRY_ONLY
---
# Register only approved external services
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: allowed-external-api
namespace: app
spec:
hosts:
- api.approved-vendor.com
ports:
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS
---
# Only allow Backend to access external API
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-backend-egress
namespace: app
spec:
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/app/sa/backend"]
to:
- operation:
hosts: ["api.approved-vendor.com"]ステップ 7: 完全なゼロトラスト設定
# ========================================
# 1. mTLS STRICT (Entire mesh)
# ========================================
---
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: istio-system
spec:
mtls:
mode: STRICT
# ========================================
# 2. Deny-by-default (Each Namespace)
# ========================================
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all
namespace: app
spec: {}
# ========================================
# 3. Ingress Gateway Policy
# ========================================
---
# Only allow external traffic to Gateway Pod
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-external
namespace: istio-system
spec:
selector:
matchLabels:
istio: ingressgateway
action: ALLOW
rules:
- to:
- operation:
ports: ["80", "443"]
# ========================================
# 4. Frontend Policy (Least privilege)
# ========================================
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: frontend-policy
namespace: app
spec:
selector:
matchLabels:
app: frontend
action: ALLOW
rules:
# Only allow Ingress Gateway
- from:
- source:
principals:
- "cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"
# ========================================
# 5. Backend Policy (Fine-grained control)
# ========================================
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: backend-policy
namespace: app
spec:
selector:
matchLabels:
app: backend
action: ALLOW
rules:
# Only allow Frontend
- from:
- source:
principals: ["cluster.local/ns/app/sa/frontend"]
to:
- operation:
methods: ["GET", "POST", "PUT"]
paths: ["/api/v1/users/*", "/api/v1/data/*"]
ports: ["8080"]
# ========================================
# 6. Database Policy (Most restrictive)
# ========================================
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: database-policy
namespace: app
spec:
selector:
matchLabels:
app: database
action: ALLOW
rules:
# Only allow Backend
- from:
- source:
principals: ["cluster.local/ns/app/sa/backend"]
to:
- operation:
ports: ["5432"]
# ========================================
# 7. Health Check Exception
# ========================================
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-health-checks
namespace: app
spec:
action: ALLOW
rules:
- to:
- operation:
paths: ["/health", "/ready", "/live"]
methods: ["GET"]
# ========================================
# 8. Prometheus Metrics Exception
# ========================================
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-prometheus
namespace: app
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["istio-system"]
principals: ["cluster.local/ns/istio-system/sa/prometheus"]
to:
- operation:
paths: ["/stats/prometheus"]
# ========================================
# 9. Egress Control
# ========================================
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: deny-all-egress
namespace: app
spec:
action: DENY
rules:
- to:
- operation:
hosts: ["*"]
---
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: allow-backend-egress
namespace: app
spec:
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/app/sa/backend"]
to:
- operation:
hosts: ["api.approved-vendor.com"]ステップ 8: 検証と監視
# 1. mTLS validation
istioctl authn tls-check <pod-name>.<namespace>
# 2. Authorization test
# Frontend -> Backend (allowed)
kubectl exec -it <frontend-pod> -n app -- \
curl http://backend:8080/api/v1/users
# Frontend -> Database (denied)
kubectl exec -it <frontend-pod> -n app -- \
curl http://database:5432
# 3. Prometheus query
# Authorization deny count
sum(rate(envoy_http_rbac_denied_total[5m])) by (namespace, pod)
# 4. Grafana dashboard
# - mTLS connection count
# - Authorization deny rate
# - Service-to-service communication matrixゼロトラストチェックリスト:
- mTLS STRICT モード(すべての通信を暗号化)
- デフォルト拒否(デフォルトですべてを拒否)
- 明示的な許可(必要なものだけを許可)
- Service Account ベースのアイデンティティ
- 最小権限(メソッド/パス/ポートを制限)
- Namespace の分離
- Egress トラフィック制御
- ヘルスチェック例外の処理
- 監視と監査
- 定期的なポリシーレビュー
参照:
スコア計算
- 選択問題 1~5: 各 10 点(合計 50 点)
- 記述問題 6~10: 各 10 点(合計 50 点)
- 合計: 100 点
評価基準:
- 90~100 点: 優秀(Istio セキュリティエキスパート)
- 80~89 点: 良好(本番セキュリティ設定の準備完了)
- 70~79 点: 平均(追加学習を推奨)
- 60~69 点: 平均以下(基本概念の復習が必要)
- 0~59 点: 再学習が必要