在ASM中对入口网关进行JWT请求鉴权

服务网格中配置JWT(JSON Web Token)请求授权,可以实现来源认证,又称为最终用户认证。在接收用户请求时,该配置用于认证请求头信息中的Access Token是否可信,并授权给来源合法的请求。本文介绍如何在ASM中对入口网关进行JWT请求鉴权,使之通过入口网关访问服务时,必须带有可信的Access Token。

前提条件

背景信息

本文以httpbin服务为例,使用请求身份认证对通过入口网关访问服务的请求进行限制,实现只有带有正确的JWT Token才能访问服务成功,错误的JWT Token将访问服务失败,但是不带有JWT Token也能访问服务成功。在此基础上,您可以使用授权策略对请求进行进一步限制,分为两个场景:

  • 使用授权策略,使之请求必须带有JWT Token,才能通过入口网关访问服务成功。

  • 使用授权策略,使之请求必须带有固定颁发者的JWT Token,才能通过入口网关访问服务成功。

步骤一:部署示例服务

  1. 为default命名空间开启自动注入。

    1. 登录ASM控制台

    2. 在左侧导航栏,选择服务网格 > 网格管理

    3. 在网格详情页面左侧导航栏,选择网格实例 > 全局命名空间

    4. 全局命名空间页面,单击default右侧自动注入列下的启用 Sidecar 网格代理自动注入

    5. 确认对话框单击确定

  2. 部署示例服务。

    1. 获取集群KubeConfig并通过kubectl工具连接集群

    2. 使用以下内容,创建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
    3. 执行以下命令,创建httpbin应用。

      kubectl apply -f httpbin.yaml -n default

步骤二:创建网关规则和虚拟服务

  1. 创建网关规则。

    1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理

    2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择ASM网关 > 网关规则,然后单击使用YAML创建

    3. 设置命名空间default,输入以下内容到文本框,然后单击创建

      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: HTTP
  2. 创建虚拟服务。

    1. 在网格详情页面左侧导航栏,选择流量管理中心 > 虚拟服务,然后在右侧页面,单击使用YAML创建

    2. 设置命名空间default,输入以下内容到文本框,然后单击创建

      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

步骤三:创建请求身份认证

  1. 创建JWK。

    1. openssl中执行以下命令,生成2048位的RSA私钥。

      openssl genrsa -out rsa-private-key.pem 2048
    2. 执行以下命令,通过私钥生成公钥。

      openssl rsa -in rsa-private-key.pem -pubout -out rsa-public-key.pem
    3. JWK to PEM Convertor online工具中选中PEM-to-JWK (RSA Only),输入公钥,单击submit,将公钥转化为JWK。

      {"kty":"RSA","e":"AQAB","kid":"59399e22-7a9a-45ed-8c76-7add7863915c","n":"2dnwOlDKEwII9Cyh9w7o59a5y3RS2gWUKYC3HSBJL1FhYIZa7sjTCKxwEuG-vCRQkR6augWxYWseSDfgtyivzi3CxxkF8WnQbECOCGm5xAYKmMcXeOpv0zsJTHN122Tt_tsd6K2OC3yGwKtmp7m-MOpHagqWRqFtvyEOm_1JW1-t0n1VsGSeWww8dvcmnJPKAKHbAU40jdV1hMn9AA3RfSpDY6nfrUkpXA5-aQ6rJRjMn36DatZ5ykVL4LKPOUxZdfK_yNIPkCnwIKesqiOpr4s-iCM8pMiZuejDZ1qoX-uBjggESf4G9_L-laDSeoDmXeOZ9kzN3Jw8ay69ihIFEQ"}
  2. 创建请求身份认证。

    1. 登录ASM控制台

    2. 在左侧导航栏,选择服务网格 > 网格管理

    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理

    4. 在网格详情页面左侧导航栏选择网格安全中心 > 请求身份认证,然后在右侧页面单击创建

    5. 创建页面配置相关信息,然后单击创建

      请求身份认证

      配置项

      描述

      命名空间

      设置命名空间istio-system

      名称

      输入名称。

      匹配标签

      匹配标签用于匹配请求身份认证生效的服务。

      单击新增匹配标签,设置名称istioingressgateway

      jwt规则集

      单击jwt规则集右侧的添加,设置JWT规则:

      • issuer:JWT的颁发者,本文设置为testing@asm.test.io

      • audiences:JWT受众列表。设置哪些服务可以使用JWT Token访问目标服务。本文设置为空,表示对访问的服务不受限制。

      • jwks:设置JWT信息,本文设置为{"keys":[步骤1创建的JWK]},例如步骤1创建的JWK为{"kty":"RSA","e":"AQAB","kid":"59399e22-7a9a-45ed-8c76-7add786****"},则jwks为{"keys":[{"kty":"RSA","e":"AQAB","kid":"59399e22-7a9a-45ed-8c76-7add786****"}]}

步骤四:验证请求身份认证是否生效

  1. 使用JWT工具将JWT请求信息编码成JWT Token。

    Decoded区域输入以下JWT请求信息,在Encode区域将自动转换成JWT Token。

    • HEADRE:设置加密算法为RS256,输入JWK中的kid,设置类型为JWT。

    • PAYLOAD:设置iss为testing@asm.test.io,您还可以添加自定义的额外信息。

    • VERIFY SIGNATURE:输入步骤1的创建的公钥和私钥。

    JWT
  2. 通过入口网关访问服务。

    1. 执行以下命令,带有步骤1创建的JWT Token的请求访问服务。

      curl -I -H "Authorization: Bearer $TOKEN" http://{您的ASM网关地址}/

      预期输出:

      HTTP/1.1 200 OK
      server: istio-envoy
      date: Fri, 18 Mar 2022 07:27:54 GMT
    2. 执行以下命令,带有无效的JWT Token的请求访问服务。

      curl -I  -H "Authorization: Bearer invalidToken" http://{您的ASM网关地址}/

      预期输出:

      HTTP/1.1 401 Unauthorized
      www-authenticate: Bearer realm="http://47.98.25*.***/", error="invalid_token"
      content-length: 79
      content-type: text/plain
      date: Fri, 18 Mar 2022 07:59:00 GMT
      server: istio-envoy
    3. 执行以下命令,不带有JWT Token的请求访问服务。

      curl -I http://{您的ASM网关地址}/

      预期输出:

      HTTP/1.1 200 OK
      server: istio-envoy
      date: Fri, 18 Mar 2022 07:27:54 GMT

    根据以上结果,可以看到带有正确的JWT Token或不带有JWT Token的请求访问服务成功,带有错误的JWT Token的请求访问服务失败,说明请求身份认证生效。

步骤五:创建授权策略

场景一:使用授权策略对访问服务的请求进行限制

创建授权策略,使之请求必须带有JWT Token,才能通过入口网关访问服务。

  1. 登录ASM控制台

  2. 在左侧导航栏,选择服务网格 > 网格管理

  3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理

  4. 在网格详情页面左侧导航栏,选择网格安全中心 > 授权策略,然后在右侧页面,单击创建

  5. 创建页面配置相关信息,然后单击创建

    授权策略

    配置项

    说明

    名称

    输入授权策略的名称。

    策略类型

    设置策略类型允许

    网关生效

    单击网关生效页签,设置ASM网关ingressgateway。在添加请求来源区域,打开请求JWT主体(RequestPrincipals)开关,在对应文本框中输入*

  6. 验证使用授权策略对访问服务的请求进行限制是否成功。

    1. 执行以下命令,不带有JWT Token的请求访问服务。

      curl -I http://{您的ASM网关地址}/

      预期输出:

      HTTP/1.1 401 Unauthorized
      www-authenticate: Bearer realm="http://47.98.25*.***/", error="invalid_token"
      content-length: 79
      content-type: text/plain
      date: Fri, 18 Mar 2022 07:59:00 GMT
      server: istio-envoy
    2. 执行以下命令,使用带有JWT Token的请求访问服务。

      curl -I -H "Authorization: Bearer $TOKEN" http://{您的ASM网关地址}/

      预期输出:

      HTTP/1.1 200 OK
      server: istio-envoy
      date: Fri, 18 Mar 2022 07:27:54 GMT

    可以看到不带有JWT Token的请求访问服务失败,带有JWT Token的请求访问服务成功,说明使用授权策略对访问服务的请求进行限制成功。

场景二:使用授权策略对访问服务的请求的JWT Token颁发者进行限制

创建授权策略,使之请求必须带有颁发者为testing@asm.test.io的JWT Token,才能通过入口网关访问服务。

  1. 登录ASM控制台

  2. 在左侧导航栏,选择服务网格 > 网格管理

  3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理

  4. 在网格详情页面左侧导航栏,选择网格安全中心 > 授权策略,然后在右侧页面,单击创建

  5. 创建页面配置相关信息,然后单击创建

    授权策略场景二

    配置项

    说明

    名称

    输入授权策略的名称。

    策略类型

    设置策略类型允许

    网关生效

    单击网关生效页签,设置ASM网关ingressgateway。在添加请求来源区域,打开请求JWT主体(RequestPrincipals)开关,在对应文本框中输入testing@asm.test.io/demo@asm.test.io

  6. 验证使用授权策略对访问服务的请求的颁发者进行限制是否成功。

    1. 执行以下命令,使用带有JWT Token的请求访问服务。

      curl -I -H "Authorization: Bearer $TOKEN" http://{您的ASM网关地址}/

      预期输出:

      HTTP/1.1 401 Unauthorized
      www-authenticate: Bearer realm="http://47.98.25*.***/", error="invalid_token"
      content-length: 79
      content-type: text/plain
      date: Fri, 18 Mar 2022 07:59:00 GMT
      server: istio-envoy

      授权策略限制了访问服务的请求的JWT Token的颁发者必须为testing@asm.test.io/demo@asm.test.io,所以带有颁发者为testing@asm.test.io的JWT Token请求访问失败。

    2. 修改JWT Token的颁发者为testing@asm.test.io/demo@asm.test.io。

      JWT工具中PAYLOAD中设置iss为testing@asm.test.io,sub为demo@asm.test.io。其他配置和步骤1保持相同。jwt2

    3. 执行以下命令,使用上文生成JWT Token的请求访问服务。

      curl -I -H "Authorization: Bearer $TOKEN" http://{您的ASM网关地址}/

      预期输出:

      HTTP/1.1 200 OK
      server: istio-envoy
      date: Fri, 18 Mar 2022 07:27:54 GMT

      带有颁发者为testing@asm.test.io/demo@asm.test.io的JWT Token请求访问服务成功,说明使用授权策略对访问服务的请求的JWT Token颁发者进行限制成功。