本文介紹JWT相關的常見問題。
ASM支持哪些JWT算法?
ASM版本<1.13,只支持RSA算法。
ASM版本≥1.13,支持JWT算法,包括ES256、ES384、ES512、HS256、HS384、HS512、RS256、RS384、RS512、PS256、PS384、PS512和EdDSA。
如何在ASM中使用JwksUri?
您需要使用阿里云服務網格ASM的1.13及以上版本進行設置。使用JwksUri主要分為以下兩種情況:
JwksUri的地址為集群內部的服務:可以直接進行配置。
JwksUri為集群外部的服務:需要配置對應的ServiceEntry。
本文以Istio官方的JWT和Jwks為例進行說明,詳情請參見JWT和Jwks。
使用集群內的JwksUri地址
本文假設JwksUri地址是服務網格ASM管理的集群中的地址,nginx-proxy是集群內的一個服務,在80端口的/get_jwks
接口會返回jwks
公鑰信息,JwksUri
為http://nginx-proxy.{Namespace}.svc.cluster.local:80/get_jwks
。
執行以下命令,查看集群的get_jwks接口是否可用。
curl nginx-proxy/get_jwks
預期輸出:
{ "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-e****","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65p****-P7KfIupjf59vsdo91bSP9C8H07pSAGQ****_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5****_pbhLdKXbi66GlVeK6ABZOUW3WYt****-91gVuoeJT_DwtGGcp4ignkgXfkiE****-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoU****_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZ****_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqT****_EyxOGuHJrLsn00****"}]}
輸出如上結果,表示get_jwks接口可用。
創建請求認證。
登錄ASM控制臺。
在左側導航欄,選擇 。
在網格管理頁面,找到待配置的實例,單擊實例的名稱或在操作列中單擊管理。
在左側導航欄單擊 。
在請求身份認證頁面,單擊使用YAML創建,選擇目標命名空間和任意場景模板,配置如下YAML,然后單擊創建。
apiVersion: security.istio.io/v1beta1 kind: RequestAuthentication metadata: name: jwt-example namespace: foo spec: jwtRules: - issuer: testing@secure.istio.io jwksUri: 'http://nginx-proxy/get_jwks' selector: matchLabels: app: httpbin
使用數據面KubeConfig,執行以下命令,訪問httpbin服務。
# 設置TOKEN環境變量。 TOKEN=$(curl https://raw.githubusercontent.com/istio/istio/release-1.14/security/tools/jwt/samples/demo.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decode - # 從sleep的Pod中帶上JWT訪問httpbin服務。 kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -sS -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"
返回
200
,說明訪問成功。
使用集群外的JwksUri地址
下文示例基于HTTP協議。如果您需要使用HTTPS來獲取Jwks,請為ServiceEntry配置額外的目標規則。
為遠端地址創建ServiceEntry。
使用以下YAML內容,創建service-entry.yaml。
apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: external-svc-https namespace: foo spec: addresses: - 11.11.XX.XX # 替換為您的外部Jwks服務地址。 endpoints: - address: 11.11.XX.XX # 替換為您的外部Jwks服務地址。 hosts: - 11.11.XX.XX # 替換為您的外部Jwks服務地址。 location: MESH_EXTERNAL ports: - name: http number: 80 protocol: HTTP - name: https number: 443 protocol: HTTPS resolution: STATIC
關于ServiceEntry的配置說明,請參見集群外服務(Service Entry)CRD說明。
執行以下命令,部署ServiceEntry。
kubectl apply -f service-entry.yaml
(可選)如果您的jwks服務需要使用HTTPS協議,需要額外為該ServiceEntry配置一個DestinationRule。
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: external-svc-https namespace: foo spec: host: ${ServiceEntry對應的host} trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: SIMPLE
創建請求認證。
登錄ASM控制臺。
在左側導航欄,選擇 。
在網格管理頁面,找到待配置的實例,單擊實例的名稱或在操作列中單擊管理。
在左側導航欄單擊 。
在請求身份認證頁面單擊使用YAML創建,選擇目標命名空間和任意場景模板,配置如下YAML,然后單擊創建。
apiVersion: security.istio.io/v1beta1 kind: RequestAuthentication metadata: name: jwt-example namespace: foo spec: jwtRules: - issuer: tes****@secure.istio.io jwksUri: '${外部jwksUri}' selector: matchLabels: app: httpbin
執行以下命令,在sleep Pod中進行訪問測試。
# 從sleep的Pod中帶上JWT訪問httpbin服務。 kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -sS -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"
返回
200
,說明訪問成功。
如何配置特定路徑不進行請求的JWT鑒權?
ASM控制臺提供了授權策略功能,您可以在授權策略中配置“排除匹配”,選擇對某些路徑之外的請求進行鑒權。
部署并訪問服務。
在ASM關聯的集群中部署Bookinfo應用示例。具體操作,請參見在ASM實例關聯的集群中部署應用。
執行以下命令,訪問如下三個服務,確保各個路徑可用。
curl "http://${ASM網關地址}/productpage" -sS -o /dev/null -w "%{http_code}\n" curl "http://${ASM網關地址}/api/v1/products/0" -sS -o /dev/null -w "%{http_code}\n" curl "http://${ASM網關地址}/api/v1/products/1" -sS -o /dev/null -w "%{http_code}\n"
三個服務均返回
200
,說明訪問成功。
創建RequestAuthentication。
登錄ASM控制臺。
在左側導航欄,選擇 。
在網格管理頁面,找到待配置的實例,單擊實例的名稱或在操作列中單擊管理。
在左側導航欄單擊 。
在請求身份認證頁面單擊使用YAML創建,選擇目標命名空間和任意場景模板,配置如下YAML,然后單擊創建。
apiVersion: security.istio.io/v1beta1 kind: RequestAuthentication metadata: name: jwt-example namespace: istio-system spec: jwtRules: - issuer: testing@secure.istio.io jwks: >- { "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-e****","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65pHymX-P7KfIupjf59vsdo91bSP9C8H07pSAGQ****_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5****_pbhLdKXbi66GlVeK6ABZOUW3WYtnNHD-91gVu****_DwtGGcp4ignkgXfkiEm4sw-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoU****_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZ****_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqT****_EyxOGuHJrLsn00****"}]} selector: matchLabels: app: istio-ingressgateway
這個請求身份認證會被應用于ASM網關上,所有經過網關的請求生效。配置好RequestAuthentication之后,不帶有JWT和帶有正確的JWT的請求都會被通過,只有攜帶錯誤JWT的請求會被拒絕。
創建AuthorizationPolicy。
設置特定路徑的請求不需要攜帶JWT,其余路徑的請求必須攜帶JWT。本文以/productpage路徑為例,對于/productpage路徑不進行JWT鑒權;對于除了/productpage路徑以外的兩個路徑,請求必須攜帶正確的JWT才可以通過。
登錄ASM控制臺。
在左側導航欄,選擇 。
在網格管理頁面,找到待配置的實例,單擊實例的名稱或在操作列中單擊管理。
在左側導航欄單擊 。
在授權策略頁面單擊使用YAML創建,選擇目標命名空間和任意場景模板,配置如下YAML,然后單擊創建。
apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: test-exclude namespace: istio-system spec: action: DENY rules: - from: - source: notRequestPrincipals: - '*' to: - operation: notPaths: - /productpage selector: matchLabels: app: istio-ingressgateway
這個AuthorizationPolicy同樣作用于ASM網關,主要配置了一條DENY規則:對于除了/productpage路徑以外的請求,如果沒有攜帶正確的JWT,就會拒絕訪問。
進行訪問測試。
執行以下命令,將請求攜帶的JWT設置為環境變量TOKEN。
export TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1****.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5p****.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9****-LS9qd_vpdLG4Tn1A15NxfCjp5f7Q****-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZz****__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCg****_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvH****_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8****
執行以下命令,訪問三個服務路徑。
所有請求都不攜帶JWT:
curl "http://${ASM網關地址}/productpage" -sS -o /dev/null -w "%{http_code}\n" 200 curl "http://${ASM網關地址}/api/v1/products/0" -sS -o /dev/null -w "%{http_code}\n" 403 curl "http://${ASM網關地址}/api/v1/products/1" -sS -o /dev/null -w "%{http_code}\n" 403
可以看到,只有/productpage路徑可以被訪問,其余路徑都返回
403
。所有請求都攜帶JWT:
curl "http://${ASM網關地址}/productpage" -H "Authorization: Bearer $TOKEN" -sS -o /dev/null -w "%{http_code}\n" 200 curl "http://${ASM網關地址}/api/v1/products/0" -H "Authorization: Bearer $TOKEN" -sS -o /dev/null -w "%{http_code}\n" 200 curl "http://${ASM網關地址}/api/v1/products/1" -H "Authorization: Bearer $TOKEN" -sS -o /dev/null -w "%{http_code}\n" 200
可以看到,三個路徑均返回
200
,表示都可以被訪問。