Istio AuthorizationPolicyは、サービスメッシュ内のどの呼び出し元が、どのサービスのどのメソッドやパスへアクセスしてよいかを決める認可のリソースです。この記事では、CUSTOM・DENY・ALLOWの評価順と既定の動作、PeerAuthenticationでmTLSをSTRICTにしてからサービス間の許可リストを組む手順、DENYやJWTを使った条件の書き方を、Istio 1.31系の公式ドキュメントに沿ったYAMLで示します。本番へ適用する前の確かめ方と、アンビエント方式での違いも扱います。
まとめ:DENYが優先しALLOWが1つでもあれば一致しない通信は拒否
AuthorizationPolicyは、CUSTOM、DENY、ALLOWの順に評価されます。DENYに一致した通信は、ALLOWに一致していても拒否の対象です。注意したいのはALLOWの扱いで、ワークロードにALLOWのポリシーが1つも無ければすべて通り、1つでも付いた瞬間に「どのALLOWにも一致しない通信」は拒否へ切り替わります。
サービス間の認可で呼び出し元をprincipals(サービスアカウント)やnamespacesで指定する場合、その値はmTLSの証明書から取り出されます。先にPeerAuthenticationでmTLSをSTRICTにし、そのうえで何も許可しないポリシーを置き、必要な呼び出しだけを1本ずつ許可する順で組むと、穴の無い構成になります。
適用前にはistio.io/dry-runアノテーションで影響を数え、拒否の原因はistioctl x authz checkとEnvoyのrbacログで追うのが基本の流れです。
認可ポリシーの役割とmTLS認証との分担・YAMLの基本形を確認する
Istio全体の仕組みはIstioとは?サービスメッシュの仕組みとサイドカー/アンビエント方式・導入判断を解説で扱っています。ここでは、セキュリティ系の3つのリソースの分担と、AuthorizationPolicyの書き方の骨格を押さえます。
PeerAuthenticationとAuthorizationPolicyの役割分担
PeerAuthenticationで相手を確かめ、AuthorizationPolicyで許可を決める関係です。Istioのセキュリティ設定は、役割の異なる3つのリソースで構成されます。
| リソース | 決めること | 主な設定 |
|---|---|---|
| PeerAuthentication | サービス間の通信にmTLSを求めるか | STRICTかPERMISSIVE |
| RequestAuthentication | 利用者のJWTをどう検証するか | 発行者と公開鍵の取得先 |
| AuthorizationPolicy | 確かめた相手に何を許すか | 呼び出し元と操作の条件 |
前の2つは「相手が誰か」を確かめる認証で、AuthorizationPolicyはその結果を使って許可か拒否かを決めます。mTLSそのものの仕組みと証明書の運用はmTLSとは?相互TLS認証の仕組みとクライアント証明書・導入判断を実装目線で解説にまとめています。
security.istio.io/v1で認可を定義するYAMLの基本形
AuthorizationPolicyのリファレンスの例は、すべてsecurity.istio.io/v1で書かれています。基本形での役割は、selectorが適用対象、actionが許可や拒否の動作、rulesが一致条件です。日本語の解説にはv1beta1のYAMLが今も残っていますが、新しく書くならv1にそろえます。
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: orders-viewer
namespace: shop
spec:
selector:
matchLabels:
app: orders
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/shop/sa/frontend"]
to:
- operation:
methods: ["GET"]
paths: ["/api/orders/*"]
この例は、shop名前空間のfrontendサービスアカウントから、ordersのPodへのGETだけを許可します。selectorを省くと同じ名前空間の全ワークロードが対象になり、ポリシーをルート名前空間(通常はistio-system)に置くとメッシュ全体に効きます。actionを省いた場合に適用される既定のアクションはALLOWです。
1つのrulesの中ではfromとtoとwhenがANDで結ばれ、rulesの要素どうしはORになります。
CUSTOM・DENY・ALLOWの評価順とポリシーが無いときの既定動作
ポリシーを何本も重ねると、どれが効いて拒否されたのかが分かりにくくなります。評価の規則を先に頭に入れておくと、設計と調査の両方が楽になります。
ALLOWが1つでも付くと一致しない通信は拒否される既定拒否の仕様
リファレンスが定める判定の流れは次のとおりです。
- 一致するCUSTOMポリシーの外部認可が拒否を返したら拒否
- 一致するDENYポリシーがあれば拒否
- そのワークロードにALLOWポリシーが1つも無ければ許可
- 一致するALLOWポリシーがあれば許可
- どれにも当たらなければ拒否
3と5で許可の扱いが変わる点は、設定事故の原因です。たとえば管理画面用のパスだけを許可するつもりでALLOWを1本足すと、それまで通っていた他のパスへの通信もすべて拒否されます。公式のExplicit Denyタスクでも、/ipだけを許すALLOWを足した後、同じPodの/getが403になる様子が確かめられます。
allow-nothingとallow-allとdeny-allの空ルールの書き分け
中身の無い書き方は、見た目が似ていても意味が正反対です。
# 何も許可しない(ALLOWでrulesなし)=その名前空間の通信をすべて拒否
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-nothing
namespace: shop
spec:
{}
---
# すべて許可(空のルールは常に一致)
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-all
namespace: shop
spec:
rules:
- {}
spec: {}はルールの無いALLOWとなり、何にも一致しないため全拒否と同じ効果になります。rules: [{}]は常に一致するので全許可です。action: DENYに空のルールを付けたdeny-allは、ALLOWより先に評価されるため、どのALLOWを足しても通らなくなります。緊急の遮断以外では使わないほうが無難です。
mTLSをSTRICTにしてからサービス間認可を許可リストで組む手順
ここからは、名前空間の中で「必要な呼び出しだけを通す」構成を作る順番を示します。順番を誤ると、許可リストが平文の通信を素通しにします。
PeerAuthenticationで名前空間からSTRICTへ切り替える適用順
Istioのセキュリティの解説によると、PeerAuthenticationの既定は平文とmTLSの両方を受け付けるPERMISSIVEです。同じページは、principalsやnamespacesを使うポリシーは、STRICTと組み合わせることを強く勧めています。PERMISSIVEのまま平文で届いた通信では、予期しない拒否やポリシーの回避が起こり得るためです。
apiVersion: security.istio.io/v1
kind: PeerAuthentication
metadata:
name: default
namespace: shop
spec:
mtls:
mode: STRICT
公式のMutual TLS Migrationタスクは、全クライアントにサイドカーを入れてから、まず名前空間単位でSTRICTにし、問題が無ければistio-systemに同じリソースを置いてメッシュ全体へ広げる順を示しています。サイドカーの無いPodからSTRICTの名前空間を呼ぶと、curlはexit code 56で失敗します。設定範囲の優先順位は、ワークロード単位、名前空間単位、メッシュ全体の順です。
allow-nothingから始めてprincipalsで呼び出し元を1本ずつ許可する
公式のHTTP Trafficタスクは、名前空間にallow-nothingを置いて全体を止め、呼び出しの経路ごとにALLOWを足していく手順です。止めた直後の画面にはRBAC: access deniedと表示されます。
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: payments-from-orders
namespace: shop
spec:
selector:
matchLabels:
app: payments
action: ALLOW
rules:
- from:
- source:
principals: ["cluster.local/ns/shop/sa/orders"]
to:
- operation:
methods: ["POST"]
paths: ["/v1/charges"]
principalsの値はトラストドメイン/ns/名前空間/sa/サービスアカウントの形です。Deploymentごとに専用のサービスアカウントを割り当てていないと、defaultを共有するPodがすべて同じ呼び出し元に見えてしまい、許可を絞れません。許可リストを書き始める前に、サービスアカウントを分けておいてください。ポリシーは反映まで数秒かかることがあるため、確認は少し待ってから行います。
namespaces指定による名前空間の分離とIngress Gatewayの例外
サービス単位まで細かく書く前に、名前空間の外からの通信だけを止める方法もあります。公式のポリシー例集には、同じ名前空間からの通信に加えて、Ingress Gatewayからの通信だけを例外として許す形が載っています。
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: ns-isolation-except-ingress
namespace: shop
spec:
action: ALLOW
rules:
- from:
- source:
namespaces: ["shop"]
- source:
principals: ["cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account"]
Ingress Gatewayのサービスアカウント名は、インストール方法によって変わります。kubectl get pods -n istio-system -o yamlで実際のserviceAccountNameを確かめてから書いてください。入口側の構成はIstio Gatewayの設定方法:Ingress GatewayのYAML・TLS終端・Gateway API対応で扱っています。
DENYで外せない禁止事項を先に書くパスとヘッダーとJWTの条件
ALLOWの許可リストは、誰かが緩いALLOWを足すと広がってしまいます。どんな場合も通してはいけない通信は、DENYで書いておくと後から崩れません。
DENYとwhen条件で管理用パスへのリクエストを拒否する例
Explicit Denyタスクは、x-tokenヘッダーがadminでないGETを拒否する例を示しています。同じ考え方で、管理用のパスを特定の呼び出し元以外から閉じられます。
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: deny-admin-path
namespace: shop
spec:
selector:
matchLabels:
app: orders
action: DENY
rules:
- from:
- source:
notPrincipals: ["cluster.local/ns/ops/sa/admin-tool"]
to:
- operation:
paths: ["/admin/*"]
whenにはrequest.headers[x-token]のような属性をkeyに取り、valuesかnotValuesで値を並べます。パスは前方一致や後方一致の*が使えますが、whenのkeyとportsは完全一致のみです。
RequestAuthenticationと認可ポリシーでJWTを必須にする設定
公式のJWT Tokenタスクによると、RequestAuthenticationだけを置いた状態では、不正なトークンは401になりますが、トークンの無いリクエストは200で通ります。トークンを必須にするには、AuthorizationPolicyを組み合わせます。以下は、notRequestPrincipalsでトークンの無いリクエストを拒否する設定例です。
apiVersion: security.istio.io/v1
kind: RequestAuthentication
metadata:
name: jwt-orders
namespace: shop
spec:
selector:
matchLabels:
app: orders
jwtRules:
- issuer: "https://auth.example.com/"
jwksUri: "https://auth.example.com/.well-known/jwks.json"
---
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: require-jwt
namespace: shop
spec:
selector:
matchLabels:
app: orders
action: DENY
rules:
- from:
- source:
notRequestPrincipals: ["*"]
*は「空でない値」に一致するため、notRequestPrincipals: ["*"]は検証済みのトークンを持たないリクエストに当たります。ポリシー例集で紹介されているのも、このDENYを使う構成です。requestPrincipalsの値はトークンのissとsubを/でつないだ文字列なので、利用者単位で絞る場合はその形で書きます。発行者のURLと鍵の取得先は、利用している認証基盤の値に置き換えてください。
TCPポートにHTTP専用の条件を書くと意図より厳しくなる落とし穴
methods、paths、hosts、requestPrincipalsはHTTPでしか判定できません。公式のSecurity Problemsのページは、TCPとして扱われるポートにこれらを書くとポリシーが意図より厳しくなると注意しています。リファレンスにも、DENYではTCPで欠けている属性を「一致した」とみなすため、ポートで絞らないとTCPの通信がまとめて拒否されるとの注記があります。
対策は2つです。HTTPのServiceはポート名をhttp-で始め、IstioにHTTPとして認識させます。DENYにはportsを付け、対象のポートを限定してください。
dry-runとistioctlで本番適用前に効き方を確かめる確認の手順
認可の設定ミスは、障害として表に出るまで気付きにくいのが難点です。適用前の確認と、拒否されたときの原因の追い方を手順にしておきます。
istio.io/dry-runアノテーションで拒否されるはずの通信を数える
公式のDry Runタスクは、ポリシーを強制せずに「適用していたら拒否された件数」を記録する方法です。機能の段階はAlphaで、ALLOWとDENYだけが対象です。
# 既存のポリシーをdry-runに切り替える
kubectl annotate --overwrite authorizationpolicies deny-admin-path -n shop istio.io/dry-run='true'
# rbacのログをdebugにして、拒否されるはずだった通信を探す
istioctl proxy-config log deploy/orders -n shop --level "rbac:debug"
kubectl logs deploy/orders -n shop -c istio-proxy | grep "shadow denied"
Prometheusを入れている環境では、rbacのメトリクスをauthz_dry_run_actionとauthz_dry_run_resultのラベルで絞ると件数を見られます。ALLOWとDENYは別々に記録されるので、両方の結果を合わせて判断してください。数日分の通信で想定外の拒否が0件だと確かめてから、アノテーションを外して強制に移ります。
istioctl x authz checkとrbacログで拒否の原因ポリシーを特定する
Security Problemsのページは、次の順で確認する手順を挙げています。
# Podに実際に適用されているポリシーの一覧
istioctl x authz check orders-7d9f8c6b5-abcde.shop
# rbacログを有効にして、拒否したポリシー名を確かめる
istioctl proxy-config log deploy/orders -n shop --level "rbac:debug"
kubectl logs deploy/orders -n shop -c istio-proxy | grep "enforced"
ログのenforced deniedの後ろに、拒否したポリシーの名前が出ます。よくある原因は、fromの前に余計な-を付けてルールが2つに分かれ、AND条件のつもりがOR条件になっているケースです。セレクタのラベルと名前空間が対象のPodと合っているかも、同じタイミングで確かめます。
サイドカー方式とアンビエント方式での書き方の違いと採用判断の目安
同じAuthorizationPolicyでも、データプレーンの方式によって評価される場所が変わります。方式ごとの差と、どこまでIstioで認可を担うかの判断を示します。
ztunnelはL4属性だけを扱いL7条件付きのALLOWは拒否に倒れる
アンビエント方式のL4ポリシーのページによると、ztunnelが判定できるのは呼び出し元のID、名前空間、IP、ポートといったL4の属性だけです。L7の属性を含むポリシーがztunnelで強制されると、安全側に倒れてDENYとして扱われます。methods: ["GET"]を足したALLOWで、正しい呼び出し元からの接続まで失敗するのはこのためです。
アンビエント方式でメソッドやパスの条件を使うなら、waypointを置き、ポリシーをselectorではなくtargetRefsでwaypointに結び付けます。waypointを経由すると宛先のztunnelから見た呼び出し元はwaypointのIDに変わるため、呼び出し元で絞るL4のポリシーもwaypoint側へ移す必要があります。
NetworkPolicyで足りる通信制御とサービス間認可を追加する判断条件
Podどうしの通信を名前空間やラベルで止めるだけなら、KubernetesのNetworkPolicyで足ります。サービスが数本で、呼び出しの経路が固定されている構成では、Istioを入れずにNetworkPolicyで始めるのが手軽です。
AuthorizationPolicyを選ぶのは、IPではなくサービスアカウント単位で呼び出し元を特定したい場合、メソッドやパスの単位で許可を分けたい場合、利用者のJWTとサービス間の認可を同じ仕組みで扱いたい場合です。両方を重ねる多層防御も、公式のL4ポリシーのページで紹介されています。考え方の土台はゼロトラストとは?境界型防御との違い・NIST7原則と導入判断を解説で整理しています。
利用者の認証基盤とサービス間の認可をまとめて設計し直すなら、認証基盤・ID管理システム開発のように、JWTの発行側から権限の設計までを一体で任せる方法もあります。
Istio AuthorizationPolicyの設定と運用で挙がるよくある質問
AuthorizationPolicyを書き始めたときに出やすい疑問に、公式ドキュメントの記述をもとに答えます。
PeerAuthenticationがPERMISSIVEのままでも認可は効きますか?
メソッドやパスの条件だけなら、PERMISSIVEのままでも認可は有効です。ただしprincipalsやnamespacesはmTLSの証明書から取り出す値なので、平文で届いた通信では空になります。ALLOWなら一致せずに拒否され、notPrincipalsを使ったDENYでは想定と違う結果になり得ます。呼び出し元で絞るポリシーを使うなら、対象の名前空間はSTRICTにしてください。
AUDITとCUSTOMのアクションはどんな場面で使いますか?
AUDITは許可や拒否に影響せず、一致したリクエストを監査ログに残すためのアクションで、別途プラグインの設定が要ります。CUSTOMは判定を外部の認可サービスへ委ねるもので、MeshConfigに登録した拡張プロバイダーをprovider.nameで指定します。CUSTOMの評価順は、ALLOWやDENYよりも先です。
ポリシーを変更してから反映されるまでどのくらいかかりますか?
HTTP Trafficタスクは、キャッシュや伝播の遅れで数秒かかる場合があると記しています。適用直後に結果が変わらなくても、数秒待ってから再度試してください。それでも変わらない場合は、istioctl x authz checkでPodにポリシーが届いているかを見ます。
VirtualServiceのルーティングと認可はどちらが先に効きますか?
役割が別で、VirtualServiceは呼び出し元側のEnvoyで行き先を決め、AuthorizationPolicyは受け手側(サイドカー方式では宛先Podのサイドカー)で許可を判定します。カナリアで新バージョンへ振り分けた通信にも、受け手のポリシーがそのまま効きます。ルーティングの書き方はIstio VirtualServiceの書き方:DestinationRuleとカナリア・リトライのYAML例を参照してください。
Istioのバージョンを上げるとポリシーの書き換えが要りますか?
security.istio.io/v1で書いていれば、1.31系への更新で書き換えは要りません。Istioのサポート表では、2026年10月時点で1.31系が現行(最新パッチは1.31.2)です。v1beta1のまま残っているマニフェストは、更新の機会にv1へ直しておくと後の移行が楽になります。版ごとの差分はIstioの最新バージョンは1.31|1.28〜1.31の新機能・サポート期限とアップグレード手順にまとめています。
関連記事
- Istioとは?サービスメッシュの仕組みとサイドカー/アンビエント方式・導入判断を解説:Istio全体の仕組みと導入判断
- mTLSとは?相互TLS認証の仕組みとクライアント証明書・導入判断を実装目線で解説:認可の前提となる相互TLS認証
- Istio Gatewayの設定方法:Ingress GatewayのYAML・TLS終端・Gateway API対応:外部からの入口の設定
- Istio VirtualServiceの書き方:DestinationRuleとカナリア・リトライのYAML例:メッシュ内のルーティング設定
- サービスメッシュとは?サイドカー方式の仕組みとAPIゲートウェイとの違い・導入判断を解説:サービスメッシュの位置づけ
- Linkerdとは?軽量なRust製サービスメッシュの仕組みとIstioとの選び分けを解説:より軽量なメッシュとの比較