本文介绍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为集群外部的服务:
    • 使用IP访问服务:通过直接配置服务IP来使用JwksUri,需要在网格中添加对应的ServiceEntry。
    • 使用域名访问服务:出于安全方面考虑,目前还未开放支持。若您需要使用此方式,可以通过在集群内配置Nginx反向代理实现。目前并不推荐使用此方式。
本文以Istio官方的JWT和Jwks为例进行说明,详情请参见JWTJwks

使用集群内的JwksUri地址

本文假设JwksUri地址是服务网格ASM管理的集群中的地址,nginx-proxy是集群内的一个服务,在80端口的/get_jwks接口会返回jwks公钥信息,JwksUrihttp://nginx-proxy.{Namespace}.svc.cluster.local:80/get_jwks

  1. 执行以下命令,查看集群的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接口可用。
  2. 创建请求认证。
    1. 登录ASM控制台
    2. 在左侧导航栏,选择服务网格 > 网格管理
    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在左侧导航栏单击网络安全中心 > 请求身份认证
    5. 请求身份认证页面单击使用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
  3. 使用数据面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的远端地址,并且需要为远端地址创建ServiceEntry。

  1. 为远端地址创建ServiceEntry。
    1. 使用以下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
        resolution: STATIC                           
    2. 执行以下命令,部署ServiceEntry。
      kubectl apply -f service-entry.yaml
  2. 创建请求认证。
    1. 登录ASM控制台
    2. 在左侧导航栏,选择服务网格 > 网格管理
    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在左侧导航栏单击网络安全中心 > 请求身份认证
    5. 请求身份认证页面单击使用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
  3. 执行以下命令,在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控制台提供了授权策略功能,您可以在授权策略中配置“排除匹配”,选择对某些路径之外的请求进行鉴权。

  1. 部署并访问服务。
    1. 在ASM中部署Bookinfo应用示例。具体操作,请参见部署应用到ASM实例
    2. 执行以下命令,访问如下三个服务,确保各个路径可用。
      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,说明访问成功。
  2. 创建RequestAuthentication。
    1. 登录ASM控制台
    2. 在左侧导航栏,选择服务网格 > 网格管理
    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在左侧导航栏单击网络安全中心 > 请求身份认证
    5. 请求身份认证页面单击使用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的请求会被拒绝。
  3. 创建AuthorizationPolicy。
    设置特定路径的请不需要携带JWT,其余路径的请求必须携带JWT。本文以/productpage路径为例,对于/productpage路径不进行JWT鉴权;对于除了/productpage路径以外的两个路径,请求必须携带正确的JWT才可以通过。
    1. 登录ASM控制台
    2. 在左侧导航栏,选择服务网格 > 网格管理
    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理
    4. 在左侧导航栏单击网络安全中心 > 授权策略
    5. 授权策略页面单击使用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,就会拒绝访问。
  4. 进行访问测试。
    1. 执行以下命令,将请求携带的JWT设置为环境变量TOKEN。
      export TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1****.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5p****.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9****-LS9qd_vpdLG4Tn1A15NxfCjp5f7Q****-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZz****__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCg****_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvH****_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8****
    2. 执行以下命令,访问三个服务路径。
      • 所有请求都不携带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,表示都可以被访问。