在服务网格中配置JWT(JSON Web Token)请求授权,可以实现来源认证,又称为最终用户认证。在接收用户请求时,该配置用于认证请求头信息中的Access Token是否可信,并授权给来源合法的请求。本文介绍如何在ASM中对入口网关进行JWT请求鉴权,使之通过入口网关访问服务时,必须带有可信的Access Token。
前提条件
- 已添加集群到ASM实例。具体操作,请参见添加集群到ASM实例。
- 已部署入口网关服务。具体操作,请参见创建入口网关。
背景信息
本文以httpbin服务为例,使用请求身份认证对通过入口网关访问服务的请求进行限制,实现只有带有正确的JWT Token才能访问服务成功,错误的JWT Token将访问服务失败,但是不带有JWT Token也能访问服务成功。在此基础上,您可以使用授权策略对请求进行进一步限制,分为两个场景:
使用授权策略,使之请求必须带有JWT Token,才能通过入口网关访问服务成功。
使用授权策略,使之请求必须带有固定颁发者的JWT Token,才能通过入口网关访问服务成功。
步骤一:部署示例服务
为default命名空间开启自动注入。
登录ASM控制台。
在左侧导航栏,选择 。
在网格详情页面左侧导航栏,选择 。
在全局命名空间页面,单击default右侧自动注入列下的启用 Sidecar 网格代理自动注入。
在确认对话框单击确定。
部署示例服务。
使用以下内容,创建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
执行以下命令,创建httpbin应用。
kubectl apply -f httpbin.yaml -n default
步骤二:创建网关规则和虚拟服务
创建网关规则。
登录ASM控制台,在左侧导航栏,选择 。
在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择 ,然后单击使用YAML创建。
设置命名空间为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
创建虚拟服务。
在网格详情页面左侧导航栏,选择 ,然后在右侧页面,单击使用YAML创建。
设置命名空间为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
步骤三:创建请求身份认证
创建JWK。
在openssl中执行以下命令,生成2048位的RSA私钥。
openssl genrsa -out rsa-private-key.pem 2048
执行以下命令,通过私钥生成公钥。
openssl rsa -in rsa-private-key.pem -pubout -out rsa-public-key.pem
在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"}
创建请求身份认证。
登录ASM控制台。
在左侧导航栏,选择 。
在网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理。
在网格详情页面左侧导航栏选择 ,然后在右侧页面单击创建。
在创建页面配置相关信息,然后单击创建。
配置项
描述
命名空间
设置命名空间为istio-system。
名称
输入名称。
匹配标签
匹配标签用于匹配请求身份认证生效的服务。
单击新增匹配标签,设置名称为istio,值为ingressgateway。
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****"}]}
。
步骤四:验证请求身份认证是否生效
使用JWT工具将JWT请求信息编码成JWT Token。
在Decoded区域输入以下JWT请求信息,在Encode区域将自动转换成JWT Token。
HEADRE:设置加密算法为RS256,输入JWK中的kid,设置类型为JWT。
PAYLOAD:设置iss为testing@asm.test.io,您还可以添加自定义的额外信息。
VERIFY SIGNATURE:输入步骤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
执行以下命令,带有无效的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
执行以下命令,不带有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,才能通过入口网关访问服务。
登录ASM控制台。
在左侧导航栏,选择 。
在网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理。
在网格详情页面左侧导航栏,选择 ,然后在右侧页面,单击创建。
在创建页面配置相关信息,然后单击创建。
配置项
说明
名称
输入授权策略的名称。
策略类型
设置策略类型为允许。
网关生效
单击网关生效页签,设置ASM网关为ingressgateway。在添加请求来源区域,打开请求JWT主体(RequestPrincipals)开关,在对应文本框中输入*。
验证使用授权策略对访问服务的请求进行限制是否成功。
执行以下命令,不带有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
执行以下命令,使用带有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,才能通过入口网关访问服务。
登录ASM控制台。
在左侧导航栏,选择 。
在网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理。
在网格详情页面左侧导航栏,选择 ,然后在右侧页面,单击创建。
在创建页面配置相关信息,然后单击创建。
配置项
说明
名称
输入授权策略的名称。
策略类型
设置策略类型为允许。
网关生效
单击网关生效页签,设置ASM网关为ingressgateway。在添加请求来源区域,打开请求JWT主体(RequestPrincipals)开关,在对应文本框中输入testing@asm.test.io/demo@asm.test.io。
验证使用授权策略对访问服务的请求的颁发者进行限制是否成功。
执行以下命令,使用带有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请求访问失败。
修改JWT Token的颁发者为testing@asm.test.io/demo@asm.test.io。
执行以下命令,使用上文生成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颁发者进行限制成功。