
はじめに
こんにちは。SRE部会員ID基盤SREブロックの田中です。
ZOZOではマイクロサービスの増加に伴い、昨今高度化するサイバー攻撃に対応しつつ、各システム間のセキュリティとその統一性を維持するための仕組みが求められていました。なかでも、認可基盤の統一は長年にわたる重要な課題のひとつでした。
そこで今回、Istioを活用することで認可機能をアプリケーションから切り離し、ZOZOTOWN共通の認可基盤を実装する方針を採用することにしました。
本記事では、IstioのAuthorizationPolicy機能を利用した認可制御の実装方法について紹介します。
目次
- はじめに
- 目次
- Istioとは
- 課題
- Istioを選定した理由
- AuthorizationPolicyによる認可制御
- AuthorizationPolicyの基本構造
- ヘッダーを用いた認可の動作検証
- 導入時の注意点
- 導入により得られた効果
- まとめ
Istioとは
Istioは、分散システムやマイクロサービス間の通信を一元管理するために設計されたオープンソースのサービスメッシュです。各サービスにサイドカーとしてEnvoy Proxyを配置し、サービス間のトラフィックを透過的に制御します。
Istioを利用することで、以下のような機能を実現できます。
- トラフィック管理(ルーティング、ロードバランシング)
- 可観測性(メトリクス、トレーシング、ロギング)
- セキュリティ(認証・認可、mTLS)
課題
ZOZOTOWN基盤ではマイクロサービス化の進行により、各アプリケーションが独自に認可処理を実装していましたが、徐々に以下のような課題が顕在化していきました。
| 課題 | 影響 |
|---|---|
| アプリケーションごとにポリシーや実装方式が異なる | 統一性が欠如し、セキュリティホールが生まれやすい。レビュー負荷の上昇 |
| セキュリティ要件の変更時にすべてのアプリケーションへ個別対応が必要 | 改修コストとリリース速度への影響 |
これらの課題を解決するため、アプリケーションごとに認可機能を実装する方針から、Istioサービスメッシュによる統一的な制御を実現する方針に転換することを決定しました。
Istioを選定した理由
Istioを選定した主な理由は以下の通りです。
- アプリケーションコードの変更が不要: Envoy Proxyによる透過的な通信制御により、既存アプリケーションへの影響を最小化
- 言語・フレームワーク非依存: Go、Java等の技術スタックに関係なく統一したポリシーを適用可能
- 宣言的な設定管理: Kubernetesネイティブなリソースとして管理でき、GitOpsとの親和性が高い
- 豊富な認証・認可機能: JWTの検証、mTLS、きめ細かなアクセス制御を標準機能として提供
AuthorizationPolicyによる認可制御
Istioの認可ポリシーはAuthorizationPolicyというリソースによって定義します。定義された認可ポリシーは各Envoy Proxyの認可エンジンによって評価され、リクエストに対してALLOW・DENYのどちらかを決定します。
AuthorizationPolicyはクラスタ全体や特定のNamespace・Podに対して設定が可能です。認可ポリシーはリクエストの属性(例:ヘッダー、JWTクレーム、メソッド、パス、宛先サービスなど)を条件として指定でき、ALLOW・DENYを決めるルールを柔軟に定義できます。
AuthorizationPolicyの基本構造
AuthorizationPolicyの基本構造をサンプルコードをもとに確認します。以下は検証用のnginx Podを対象とした認可制御を適用するAuthorizationPolicyの例です。

apiVersion: security.istio.io/v1 kind: AuthorizationPolicy metadata: name: nginx-test-authz namespace: authz-policy-test annotations: istio.io/dry-run: "true" spec: selector: matchLabels: app: nginx-test action: ALLOW rules: - to: - operation: methods: - "GET" paths: - "/*" when: - key: request.headers[x-test-token] values: - "allow-me"
AuthorizationPolicyは大きく分けてmetadataと3つのセクション(selector、action、rules)で構成されています。
metadata
作成するAuthorizationPolicyの名前、作成するNamespace、dry-runモードのオン・オフを設定します。
dry-runモードを有効にした場合、認可ポリシーによる評価は行われますが、実際のアクションは実行されません。
selector(適用対象)
AuthorizationPolicyは3つのスコープで適用できます。
(1) Workload単位(最も一般的)
spec: selector: matchLabels: app: myapp
(2) Namespace全体
metadata: namespace: default spec: {}
(3) メッシュ全体(istio-system)
metadata: namespace: istio-system spec: {}
action(動作)
| アクション | 説明 |
|---|---|
| ALLOW | 条件に一致した通信を許可 |
| DENY | 条件に一致した通信を拒否 |
| AUDIT | 条件に一致した通信を許可しつつ、ログに記録(検証用) |
AUDIT actionとdry-runモードは役割が似ており混同しやすいですが、利用目的が異なります。
前者はリクエストが認可エンジンにより評価されたかどうかの証跡・可視化を、後者はどのActionの対象として評価されたかの確認を目的としています。
どちらも実際の通信への影響はありません。
rules(認可ルール)
rulesはfrom、to、whenの3つの要素で構成されます。
from(リクエスト元の制御)
今回のサンプルコードにはありませんが、例えばService Accountを用いてリクエスト元を制御できます。
rules: - from: - source: principals: ["cluster.local/ns/default/sa/sample-app"]
to(リクエスト先の制御)
- to: - operation: methods: - "GET" paths: - "/*"
主な条件として以下が指定できます。
| 条件 | 説明 |
|---|---|
| methods | HTTPメソッド(GET、POSTなど) |
| paths | リクエストパス |
| ports | ポート番号 |
| hosts | ホスト名 |
when(追加条件)
when: - key: request.headers[x-test-token] values: - "allow-me"
使用できるキーの例は以下の通りです。
| キー | 説明 |
|---|---|
| request.headers[...] | リクエストヘッダーの値 |
| request.auth.claims[...] | JWTのクレーム値 |
| source.ip | リクエスト元IPアドレス |
その他の制御条件については公式ドキュメントを参照ください。
ヘッダーを用いた認可の動作検証
サンプルコードを用いて実際にAuthorizationPolicyを作成し、ログを確認しながら認可の様子を確認します。
前提として、nginx Podがすでに作成されており、サービスメッシュを通して通信ができる状態とします。
今回はヘッダーを用いた認可を検証します。dry-runモードを有効化することでリクエストに影響を与えず認可結果を確認できます。
先ほどのサンプルコードをapplyした後、以下のリクエストを実行します。
正しくヘッダーを付与した場合
$ curl -I -H "x-test-token: allow-me" http://nginx-test.authz-policy-test.svc.cluster.local HTTP/1.1 200 OK server: istio-envoy ...
Istioのログを確認すると、リクエストが許可(shadow allowed)されていることがわかります。
2025-12-31T03:37:41.966028Z debug envoy rbac external/envoy/source/extensions/filters/http/rbac/rbac_filter.cc:166 shadow allowed, matched policy ns[authz-policy-test]-policy[nginx-test-authz]-rule[0] thread=35
ヘッダーを付与せずにリクエストした場合
$ curl -I http://nginx-test.authz-policy-test.svc.cluster.local HTTP/1.1 200 OK server: istio-envoy ...
dry-runモードのためリクエストは成功していますが、Istioのログを確認すると、リクエストが拒否されるものと評価されていることがわかります(shadow denied)。
2025-12-31T03:38:01.890287Z debug envoy rbac external/envoy/source/extensions/filters/http/rbac/rbac_filter.cc:173 shadow denied, matched policy none thread=34
dry-runをfalseにした場合
次にdry-runをfalseに変更して、実際の挙動を確認します。
正しくヘッダーを付与した場合
$ curl -I -H "x-test-token: allow-me" http://nginx-test.authz-policy-test.svc.cluster.local HTTP/1.1 200 OK server: istio-envoy ...
ヘッダーを付与せずにリクエストした場合
$ curl -I http://nginx-test.authz-policy-test.svc.cluster.local HTTP/1.1 403 Forbidden ...
事前にdry-runモードで確認したように、想定通りリクエストが拒否されました。
このように、AuthorizationPolicyを用いることでIstioを介したリクエストの認可制御を行うことができます。
導入時の注意点
ここで、私たちがAuthorizationPolicyを本番環境に導入する際、注意した点を紹介します。
istio-proxyの負荷上昇
認可処理を追加することでistio-proxyの負荷が上昇します。負荷試験等を実施し、上昇値が許容範囲かどうかあらかじめ確認しておくことを推奨します。
AuthorizationPolicyの認可方法によって上昇率が異なりますが、CPU使用量が1.2〜1.5倍まで上昇したケースも見られました。
段階的なロールアウト
対象ワークロード向けの全リクエストに対して最初から認可処理を実行するのは、本来許可すべきリクエストまでブロックされてしまうリスクがあります。
ZOZOではFlaggerを用いた手動カナリアリリースを実施しました。手動カナリアリリースの詳細については以下の過去ブログから参照できます。
上記に加え、AuthorizationPolicyのselectorによる認可対象コントロールを用いた下記の手順でリリースを実施しました。
- カナリアPodに専用ラベルを付与し、selectorに設定することで独立した認可対象とする
- 段階的にカナリアPodへ向けるリクエストのパーセンテージを増加する
- 特定の段階までリクエストパーセンテージを増加させ意図しないブロックなどが行われていないことを確認する
- selectorをプライマリーPodに付与されているラベルへ変更し認可対象を切り替える
段階的に認可制御を適用することで、リスクを最小限に抑えたAuthorizationPolicyの本番導入が可能です。
dry-runモードの活用
本番導入前にdry-runモードを活用することで、実際のリクエストに影響を与えずに認可ポリシーの動作を確認できます。
Istioのログを分析し、想定通りの認可判定が行われているかを事前に確認することを推奨します。
導入により得られた効果
Istio AuthorizationPolicyを導入することにより、以下の効果が得られました。
| 効果 | 詳細 |
|---|---|
| 認可ロジックの一元化 | アプリケーションコードから認可処理を分離し、統一的な管理が可能に |
| セキュリティ要件変更時の対応工数を削減 | AuthorizationPolicyの変更のみで全サービスに適用可能 |
| 開発チームの負担軽減 | 各アプリケーションで認可機能を実装・保守する必要がなくなった |
| キャッチアップ工数の削減 | 認可処理が統一されたことにより、キャッチアップが必要なリソースが単一化された |
まとめ
本記事では、IstioのAuthorizationPolicyを活用したマイクロサービスの認可基盤の構築について紹介しました。
AuthorizationPolicyを導入することで、アプリケーションコードを変更せずに統一的なセキュリティポリシーを適用でき、認可処理の一元化を実現できました。また、宣言的な設定管理により、セキュリティ要件の変更にも柔軟に対応できるようになりました。
マイクロサービス環境での認可基盤の統一を検討している方がいれば、ぜひ参考にしてみてください。
ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください。