JWTクレームに基づくルーティング

このタスクでは、リクエスト認証と仮想サービスを使用して、Istioイングレスゲートウェイ上のJWTクレームに基づいてリクエストをルーティングする方法を示します。

注:この機能は Istio Ingress Gateway のみをサポートしており、JWTクレームに基づいて適切に検証およびルーティングを行うためには、リクエスト認証と仮想サービスの両方を使用する必要があります。

始める前に

  • Istioの認証ポリシー仮想サービスの概念を理解してください。

  • Istioインストールガイドを使用してIstioをインストールしてください。

  • ワークロードhttpbinを名前空間(例:foo)にデプロイし、このコマンドでIstio Ingress Gatewayを通して公開します。

    ZipZip
    $ kubectl create ns foo
    $ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin.yaml@) -n foo
    $ kubectl apply -f @samples/httpbin/httpbin-gateway.yaml@ -n foo
    
  • Ingress IPとポートの決定の指示に従って、INGRESS_HOSTINGRESS_PORTの環境変数を定義します。

  • このコマンドを使用して、httpbinワークロードとIngress Gatewayが期待どおりに動作していることを確認します。

    $ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n"
    200
    

JWTクレームに基づくイングレスルーティングの設定

Istio Ingress Gatewayは、認証済みのJWTに基づいてルーティングをサポートしており、エンドユーザーのIDに基づいてルーティングするのに役立ち、認証されていないHTTP属性(例:パスやヘッダー)を使用するよりも安全です。

  1. JWTクレームに基づいてルーティングするには、まずJWT検証を有効にするためのリクエスト認証を作成します。

    $ kubectl apply -f - <<EOF
    apiVersion: security.istio.io/v1
    kind: RequestAuthentication
    metadata:
      name: ingress-jwt
      namespace: istio-system
    spec:
      selector:
        matchLabels:
          istio: ingressgateway
      jwtRules:
      - issuer: "testing@secure.istio.io"
        jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.24/security/tools/jwt/samples/jwks.json"
    EOF
    

    リクエスト認証により、Istio Ingress GatewayでのJWT検証が有効になり、検証済みのJWTクレームを後でルーティングの目的で仮想サービスで使用できるようになります。

    JWTクレームベースのルーティングはIngress Gatewayでのみサポートされているため、リクエスト認証はIngress Gatewayに適用されます。

    注:リクエスト認証は、リクエストにJWTが存在する場合にのみJWTをチェックします。JWTを必須にして、JWTが含まれていない場合にリクエストを拒否するには、タスクで指定されているように、認可ポリシーを適用してください。

  2. 検証済みのJWTクレームに基づいてルーティングするように仮想サービスを更新します。

    $ kubectl apply -f - <<EOF
    apiVersion: networking.istio.io/v1
    kind: VirtualService
    metadata:
      name: httpbin
      namespace: foo
    spec:
      hosts:
      - "*"
      gateways:
      - httpbin-gateway
      http:
      - match:
        - uri:
            prefix: /headers
          headers:
            "@request.auth.claims.groups":
              exact: group1
        route:
        - destination:
            port:
              number: 8000
            host: httpbin
    EOF
    

    仮想サービスは、予約されたヘッダー"@request.auth.claims.groups"を使用して、JWTクレームgroupsと一致させます。プレフィックス@は、HTTPヘッダーではなく、JWT検証から派生したメタデータと一致していることを示します。

    文字列型、文字列リスト型、およびネストされたクレームがサポートされています。ネストされたクレーム名には、セパレーターとして.または[]を使用します。たとえば、"@request.auth.claims.name.givenName"または"@request.auth.claims[name][givenName]"は、ネストされたクレームnamegivenNameに一致します。これらはここで同等です。クレーム名に.が含まれている場合は、セパレーターとして[]のみを使用できます。

JWTクレームに基づくイングレスルーティングの検証

  1. JWTがない場合にIngress GatewayがHTTPコード404を返すことを検証します。

    $ curl -s -I "http://$INGRESS_HOST:$INGRESS_PORT/headers"
    HTTP/1.1 404 Not Found
    ...
    

    JWTがない場合にHTTPコード403でリクエストを明示的に拒否する認可ポリシーを作成することもできます。

  2. 無効なJWTの場合にIngress GatewayがHTTPコード401を返すことを検証します。

    $ curl -s -I "http://$INGRESS_HOST:$INGRESS_PORT/headers" -H "Authorization: Bearer some.invalid.token"
    HTTP/1.1 401 Unauthorized
    ...
    

    401は、JWTが検証に失敗したため、リクエスト認証によって返されます。

  3. クレームgroups: group1を含む有効なJWTトークンでリクエストがIngress Gatewayによってルーティングされることを検証します。

    $ TOKEN_GROUP=$(curl https://raw.githubusercontent.com/istio/istio/release-1.24/security/tools/jwt/samples/groups-scope.jwt -s) && echo "$TOKEN_GROUP" | cut -d '.' -f2 - | base64 --decode
    {"exp":3537391104,"groups":["group1","group2"],"iat":1537391104,"iss":"testing@secure.istio.io","scope":["scope1","scope2"],"sub":"testing@secure.istio.io"}
    
    $ curl -s -I "http://$INGRESS_HOST:$INGRESS_PORT/headers" -H "Authorization: Bearer $TOKEN_GROUP"
    HTTP/1.1 200 OK
    ...
    
  4. 有効なJWTではあるが、クレームgroups: group1が含まれていない場合、Ingress GatewayがHTTPコード404を返すことを検証します。

    $ TOKEN_NO_GROUP=$(curl https://raw.githubusercontent.com/istio/istio/release-1.24/security/tools/jwt/samples/demo.jwt -s) && echo "$TOKEN_NO_GROUP" | cut -d '.' -f2 - | base64 --decode
    {"exp":4685989700,"foo":"bar","iat":1532389700,"iss":"testing@secure.istio.io","sub":"testing@secure.istio.io"}
    
    $ curl -s -I "http://$INGRESS_HOST:$INGRESS_PORT/headers" -H "Authorization: Bearer $TOKEN_NO_GROUP"
    HTTP/1.1 404 Not Found
    ...
    

クリーンアップ

  • 名前空間fooを削除します。

    $ kubectl delete namespace foo
    
  • リクエスト認証を削除します。

    $ kubectl delete requestauthentication ingress-jwt -n istio-system
    
この情報は役立ちましたか?
改善のための提案はありますか?

フィードバックありがとうございます!