外部トラフィックがイングレスゲートウェイを介してサービスメッシュに入る際、各リクエストが正当なユーザーからのものであることを検証する方法が必要です。Service Mesh (ASM) は、イングレスゲートウェイでの JSON Web トークン (JWT) 認証をサポートしており、リクエストがバックエンドサービスに到達する前にエンドユーザーの ID を検証できます。
ASM での JWT 認証は、2 つの Istio セキュリティリソースに依存しています:
RequestAuthentication -- JWT の検証方法 (発行者、署名キー) を定義します。*無効な*トークンを持つリクエストは拒否しますが、トークンが*ない*リクエストは引き続き許可します。
AuthorizationPolicy -- JWT の有無やクレームに基づいてアクセスルールを適用します。RequestAuthentication と組み合わせることで、有効なトークンがないリクエストをブロックします。
RequestAuthentication ポリシーだけでは、トークンレスのリクエストは拒否されません。すべてのリクエストで有効な JWT を要求するには、権限付与ポリシーによる JWT 要件の適用で説明されているように、AuthorizationPolicy も作成する必要があります。
このガイドでは、サンプルサービスのデプロイ、RequestAuthentication ポリシーの作成、トークン検証の確認、そしてトークン要件を適用するための AuthorizationPolicy ルールの追加という、一連の完全な例を解説します。
前提条件
ASM インスタンスに追加済みのクラスター。詳細については、「ASM インスタンスにクラスターを追加する」をご参照ください。
イングレスゲートウェイサービスがデプロイされていること。詳細については、「イングレスゲートウェイを作成する」をご参照ください。
httpbin テストサービスのデプロイ
このセクションでは、ASM イングレスゲートウェイの背後に httpbin サービスをデプロイします。すでにゲートウェイを介して公開されているサービスがある場合は、リクエスト認証ポリシーの作成に進んでください。
サイドカーの自動インジェクションの有効化
ASM コンソールにログインします。
左側のナビゲーションウィンドウで、[サービスメッシュ] > [メッシュ管理] を選択します。
ASM インスタンスの詳細ページで、左側のナビゲーションウィンドウから [ASM インスタンス] > [グローバル名前空間] を選択します。
[グローバル名前空間] ページで、default 名前空間を見つけ、[サイドカーの自動インジェクション] 列の [サイドカープロキシの自動インジェクションを有効にする] をクリックします。
[送信] メッセージで [OK] をクリックします。
httpbin のデプロイ
kubectl を使用して Container Service for Kubernetes (ACK) クラスターに接続します。詳細については、「クラスターの kubeconfig ファイルを取得し、kubectl を使用してクラスターに接続する」をご参照ください。
次の内容で httpbin.yaml ファイルを作成します:
apiVersion: v1 kind: ServiceAccount metadata: name: httpbin --- apiVersion: v1 kind: Service metadata: name: httpbin labels: app: httpbin service: httpbin spec: ports: - name: http port: 8000 targetPort: 80 selector: app: httpbin --- apiVersion: apps/v1 kind: Deployment metadata: name: httpbin spec: replicas: 1 selector: matchLabels: app: httpbin version: v1 template: metadata: labels: app: httpbin version: v1 spec: serviceAccountName: httpbin containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: httpbin ports: - containerPort: 80サービスをデプロイします:
kubectl apply -f httpbin.yaml -n default
Istio ゲートウェイと仮想サービスの作成
ASM コンソールにログインします。左側のナビゲーションウィンドウで、[サービスメッシュ] > [メッシュ管理] を選択します。
[メッシュ管理] ページで、ASM インスタンスの名前をクリックします。左側のナビゲーションウィンドウで、[ASM ゲートウェイ] > [ゲートウェイ] を選択します。表示されたページで、[YAML から作成] をクリックします。
[名前空間] ドロップダウンリストから [default] を選択し、次の YAML をコードエディターに貼り付けてから、[作成] をクリックします。
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: httpbin-gateway namespace: default spec: selector: istio: ingressgateway servers: - hosts: - '*' port: name: http number: 80 protocol: HTTPASM インスタンスの詳細ページで、左側のナビゲーションウィンドウから [トラフィック管理センター] > [VirtualService] を選択します。[YAML から作成] をクリックします。
[名前空間] ドロップダウンリストから [default] を選択し、次の YAML をコードエディターに貼り付けてから、[作成] をクリックします。
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin namespace: default spec: gateways: - httpbin-gateway hosts: - '*' http: - route: - destination: host: httpbin port: number: 8000
リクエスト認証ポリシーの作成
RequestAuthentication ポリシーを作成するには、まず署名検証用の JSON Web キー (JWK) を生成し、次に ASM コンソールでポリシーを構成します。
JWK の生成
OpenSSL を使用して 2048 ビットの RSA 秘密鍵を生成します:
openssl genrsa -out rsa-private-key.pem 2048公開鍵を抽出します:
openssl rsa -in rsa-private-key.pem -pubout -out rsa-public-key.pem公開鍵を JWK フォーマットに変換します。[JWK to PEM Convertor] オンラインツールを開き、[PEM-to-JWK (RSA Only)] を選択し、
rsa-public-key.pemの内容をコードエディターに貼り付けて、[submit] をクリックします。ツールは次のような JWK を出力します。この JWK を次のステップのために保存してください。{ "kty": "RSA", "e": "AQAB", "kid": "59399e22-7a9a-45ed-8c76-7add7863915c", "n": "2dnwOlDKEwII9Cyh9w7o59a5y3RS2gWUKYC3HSBJL1FhYIZa7sjTCKxwEuG-vCRQkR6augWxYWseSDfgtyivzi3CxxkF8WnQbECOCGm5xAYKmMcXeOpv0zsJTHN122Tt_tsd6K2OC3yGwKtmp7m-MOpHagqWRqFtvyEOm_1JW1-t0n1VsGSeWww8dvcmnJPKAKHbAU40jdV1hMn9AA3RfSpDY6nfrUkpXA5-aQ6rJRjMn36DatZ5ykVL4LKPOUxZdfK_yNIPkCnwIKesqiOpr4s-iCM8pMiZuejDZ1qoX-uBjggESf4G9_L-laDSeoDmXeOZ9kzN3Jw8ay69ihIFEQ" }
RequestAuthentication ポリシーの設定
ASM コンソールにログインします。
左側のナビゲーションウィンドウで、[サービスメッシュ] > [メッシュ管理] を選択します。
[メッシュ管理] ページで、ASM インスタンスを見つけ、その名前をクリックするか、[アクション] 列の [管理] をクリックします。
左側のナビゲーションウィンドウで [メッシュセキュリティセンター] > [RequestAuthentication] を選択します。[作成] をクリックします。
次のパラメーターを設定し、[作成] をクリックします。
パラメーター 値 名前空間 [istio-system] を選択します。 名前 ポリシーの名前を入力します。 一致ラベル [一致ラベルを追加] をクリックします。[名前] を istioに、[値] をingressgatewayに設定します。JWT ルールセット [追加] をクリックし、次の表で説明されているフィールドを設定します。 JWT ルールセットのフィールド:
フィールド 説明 値の例 issuer JWT 発行者の識別子。 testing@asm.test.ioaudiences JWT の使用を許可されるサービス。すべてのサービスを許可する場合は空のままにします。 (空) jwks 署名キーを {"keys":[<your-JWK>]}フォーマットで指定します。{"keys":[{"kty":"RSA","e":"AQAB","kid":"59399e22-7a9a-45ed-8c76-7add786****"}]}
リクエスト認証ポリシーの検証
テスト JWT の生成
JWT ツールを使用してテストトークンをエンコードします。[デコード済み] セクションで、次のフィールドを設定します:
ヘッダー:
algをRS256に、kidを JWK のキー ID に、typをJWTに設定します。ペイロード:
issをtesting@asm.test.ioに設定します。必要に応じて他のクレームを追加します。署名の検証:JWK の生成で生成した公開鍵と秘密鍵を貼り付けます。

[エンコード済み] セクションから JWT 文字列をコピーし、次のテストのために TOKEN 環境変数に保存します。
ポリシーのテスト
次のコマンドを実行します。<ingress-gateway-ip> は、ご利用のイングレスゲートウェイの IP アドレスに置き換えてください。
有効な JWT を使用したリクエスト:
curl -I -H "Authorization: Bearer $TOKEN" http://<ingress-gateway-ip>/期待されるレスポンス:
HTTP/1.1 200 OK
server: istio-envoy
date: Fri, 18 Mar 2022 07:27:54 GMT無効な JWT を使用したリクエスト:
curl -I -H "Authorization: Bearer invalidToken" http://<ingress-gateway-ip>/期待されるレスポンス:
HTTP/1.1 401 Unauthorized
www-authenticate: Bearer realm="http://<ingress-gateway-ip>/", error="invalid_token"
content-length: 79
content-type: text/plain
date: Fri, 18 Mar 2022 07:59:00 GMT
server: istio-envoyJWT なしのリクエスト:
curl -I http://<ingress-gateway-ip>/期待されるレスポンス:
HTTP/1.1 200 OK
server: istio-envoy
date: Fri, 18 Mar 2022 07:27:54 GMTこれらの結果は、RequestAuthentication ポリシーが正しく機能していることを示しています:
| リクエストタイプ | 期待される結果 | 理由 |
|---|---|---|
| 有効な JWT | 200 OK | トークンが署名と発行者の検証をパスします。 |
| 無効な JWT | 401 Unauthorized | トークンが署名検証に失敗します。 |
| JWT なし | 200 OK | RequestAuthentication はトークンレスのリクエストを拒否しません。 |
この時点では、トークンレスのリクエストはまだ成功します。すべてのリクエストで有効な JWT を要求するには、次のセクションで説明するように AuthorizationPolicy を作成します。
権限付与ポリシーによる JWT 要件の適用
すべてのリクエストに対する有効な JWT の要求
この AuthorizationPolicy は、有効な JWT を持たないリクエストをすべて拒否します。
ASM コンソールにログインします。
左側のナビゲーションウィンドウで、[サービスメッシュ] > [メッシュ管理] を選択します。
ASM インスタンスの名前をクリックするか、[管理] を [操作] 列でクリックします。
左側のナビゲーションウィンドウで [メッシュセキュリティセンター] > [AuthorizationPolicy] を選択します。[作成] をクリックします。
[作成] をクリックして、次のパラメーターを設定します。
RequestPrincipalsを*に設定すると、認証されたすべてのプリンシパルに一致するため、すべてのリクエストで有効な JWT が要求されます。パラメーター 値 名前 ポリシーの名前を入力します。 ポリシータイプ [ALLOW] を選択します。 ゲートウェイ スコープ [ゲートウェイスコープ] タブで、[ASM ゲートウェイ] を [ingressgateway] に設定します。[リクエストソースの追加] セクションで、[RequestPrincipals] をオンにして *を入力します。
検証
トークンなしのリクエスト (ブロックされる):
curl -I http://<ingress-gateway-ip>/期待されるレスポンス:
HTTP/1.1 401 Unauthorized
www-authenticate: Bearer realm="http://<ingress-gateway-ip>/", error="invalid_token"
content-length: 79
content-type: text/plain
date: Fri, 18 Mar 2022 07:59:00 GMT
server: istio-envoy有効なトークンを持つリクエスト (引き続き許可される):
curl -I -H "Authorization: Bearer $TOKEN" http://<ingress-gateway-ip>/期待されるレスポンス:
HTTP/1.1 200 OK
server: istio-envoy
date: Fri, 18 Mar 2022 07:27:54 GMTトークンレスのリクエストは 401 Unauthorized を返すようになり、AuthorizationPolicy が JWT 要件を適用していることが確認できます。
特定の発行者とサブジェクトへのアクセスの制限
この AuthorizationPolicy は、JWT に特定の発行者 *および* サブジェクトのクレームが含まれるリクエストのみを許可します。期待されるプリンシパルのフォーマットは <issuer>/<subject> です。
この例では、iss: testing@asm.test.io と sub: demo@asm.test.io を持つ JWT のみが受け入れられます。
ASM コンソールにログインします。
左側のナビゲーションウィンドウで、[サービスメッシュ] > [メッシュ管理] を選択します。
ASM インスタンスの名前をクリックするか、[アクション] 列の [管理] をクリックします。
左側のナビゲーションウィンドウで [メッシュセキュリティセンター] > [AuthorizationPolicy] を選択します。[作成] をクリックします。
次のパラメーターを設定し、[作成] をクリックします。
パラメーター 値 名前 ポリシーの名前を入力します。 ポリシータイプ [ALLOW] を選択します。 ゲートウェイスコープ [ゲートウェイスコープ] タブで、[ASM ゲートウェイ] を [ingressgateway] に設定します。[リクエストソースの追加] セクションで、[RequestPrincipals] を有効にし、値を testing@asm.test.io/demo@asm.test.ioに設定します。
検証
元の JWT (iss のみ、sub なし) を使用したリクエスト -- 拒否:
curl -I -H "Authorization: Bearer $TOKEN" http://<ingress-gateway-ip>/期待されるレスポンス:
HTTP/1.1 401 Unauthorized
www-authenticate: Bearer realm="http://<ingress-gateway-ip>/", error="invalid_token"
content-length: 79
content-type: text/plain
date: Fri, 18 Mar 2022 07:59:00 GMT
server: istio-envoyポリシーはプリンシパル testing@asm.test.io/demo@asm.test.io を要求しますが、元の JWT には sub クレームなしで iss: testing@asm.test.io しか含まれていないため、リクエストは拒否されます。
発行者とサブジェクトの両方を含む新しい JWT の生成:
JWT ツールで、[ペイロード] セクションを更新します:
{
"iss": "testing@asm.test.io",
"sub": "demo@asm.test.io"
}他のすべての設定は以前と同じままにします。

新しい JWT を使用したリクエスト -- 許可:
curl -I -H "Authorization: Bearer $TOKEN" http://<ingress-gateway-ip>/期待されるレスポンス:
HTTP/1.1 200 OK
server: istio-envoy
date: Fri, 18 Mar 2022 07:27:54 GMT正確な <issuer>/<subject> プリンシパルに一致する JWT のみが権限付与チェックをパスします。
ベストプラクティス
キーのローテーションのための jwksUri の使用
このガイドでは、キーマテリアルをポリシーに直接埋め込んだインラインの jwks を使用します。本番環境のデプロイでは、jwksUri フィールドを使用して、リモートの JSON Web キーセット (JWKS) エンドポイントを指定することを推奨します:
RequestAuthentication リソースを更新することなく、自動的なキーのローテーションをサポートします。
標準の OpenID Connect (OIDC) ディスカバリーパターンに従います。
ポリシー設定をクリーンで読みやすく保ちます。
デフォルト拒否の姿勢の採用
常に RequestAuthentication を AuthorizationPolicy と組み合わせて使用してください。RequestAuthentication だけではトークンレスのリクエストはブロックされず、*無効な*トークンを拒否するだけです。RequestPrincipals: * を指定した ALLOW ポリシーを作成して、すべてのリクエストで有効な JWT を要求するようにします。
ヘルスチェックパスの除外
すべてのパスで JWT 認証が必要なわけではありません。AuthorizationPolicy の to.operation.paths フィールドを使用して、/healthz や /readyz のようなパスをトークン要件から除外しつつ、アプリケーションのエンドポイントを保護します。
トラブルシューティング
有効なトークンを使用してもリクエストが 401 を返す
| 考えられる原因 | 解決策 |
|---|---|
| 期限切れのトークン | JWT ペイロードの exp クレームを確認します。期限切れの場合は、新しいトークンを生成します。 |
| 発行者の不一致 | iss クレームが RequestAuthentication ポリシーの issuer の値と一致することを確認します。 |
| キーの不一致 | ポリシー内の JWK が、トークンの署名に使用されたキーペアと一致することを確認します。必要に応じて両方を再生成します。 |
| クロックスキュー | クラスターノードの時刻が同期されていることを確認します。JWT の検証は時刻の差に敏感です。 |
AuthorizationPolicy を追加した後にリクエストが 403 を返す
| 考えられる原因 | 解決策 |
|---|---|
| プリンシパルの欠落 | RequestPrincipals: * を指定した ALLOW ポリシーでは、有効な JWT が必要です。トークンなしのリクエストは、認証されたプリンシパルを確立できないため拒否されます。 |
| プリンシパルのフォーマットが正しくない | 発行者とサブジェクトで制限する場合、期待されるフォーマットは <issuer>/<subject> です。JWT に iss と sub の両方のクレームが存在することを確認します。 |
JWKS のフェッチ失敗 (jwksUri を使用する場合)
JWKS エンドポイントの URL がメッシュ内からアクセス可能であることを確認します。
エンドポイントが
keys配列を含む有効な JSON を返すことを確認します。詳細なエラーメッセージについては、Envoy プロキシログを確認します:
kubectl logs <ingress-gateway-pod> -c istio-proxy
関連トピック
ASM での相互 TLS 認証の設定 -- メッシュ内でのサービス間通信を保護します。
Istio のセキュリティコンセプト -- RequestAuthentication と AuthorizationPolicy モデルについて詳しく学びます。