基於 JWT 宣告的路由

此任務向您展示如何使用請求驗證和虛擬服務,根據 Istio 入口閘道上的 JWT 宣告來路由請求。

注意:此功能僅支援 Istio 入口閘道,並且需要同時使用請求驗證和虛擬服務,才能正確驗證並根據 JWT 宣告進行路由。

開始之前

  • 了解 Istio 驗證策略虛擬服務 概念。

  • 使用 Istio 安裝指南 安裝 Istio。

  • 在命名空間中部署一個工作負載,例如 foo 中的 httpbin,並使用以下命令通過 Istio 入口閘道公開它

    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
    
  • 按照確定入口 IP 和端口中的說明,定義 INGRESS_HOSTINGRESS_PORT 環境變數。

  • 使用以下命令驗證 httpbin 工作負載和入口閘道是否按預期運作

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

根據 JWT 宣告設定入口路由

Istio 入口閘道支援基於已驗證的 JWT 的路由,這對於基於最終用戶身份進行路由非常有用,並且比使用未經身份驗證的 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 入口閘道上啟用 JWT 驗證,以便稍後可以在虛擬服務中使用經過驗證的 JWT 聲明進行路由。

    請求身份驗證應用於入口閘道,因為基於 JWT 聲明的路由僅在入口閘道上支援。

    注意:請求身份驗證僅在請求中存在 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。前綴 @ 表示它與從 JWT 驗證衍生的元數據匹配,而不是與 HTTP 標頭匹配。

    支援字串類型、字串列表和巢狀聲明的聲明。使用 .[] 作為巢狀聲明名稱的分隔符。例如,"@request.auth.claims.name.givenName""@request.auth.claims[name][givenName]" 匹配巢狀聲明 namegivenName,它們在這裡是等效的。當聲明名稱包含 . 時,只能使用 [] 作為分隔符。

驗證基於 JWT 宣告的入口路由

  1. 驗證入口閘道在沒有 JWT 的情況下返回 HTTP 代碼 404

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

    您還可以創建授權策略,以便在缺少 JWT 時明確拒絕請求並返回 HTTP 代碼 403。

  2. 驗證入口閘道在 JWT 無效的情況下返回 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 令牌路由請求

    $ 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 的情況下返回 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
    
此資訊是否有用?
您有任何改進建議嗎?

感謝您的回饋!