当您需要在服务网格中验证和授权HTTP请求来源时,可以配置JWT(JSON Web Token)请求鉴权,实现来源认证(最终用户认证)。在处理请求时,该配置能够准确核实请求头中Access Token的有效性,只允许来源可信的请求访问服务,提高服务的安全性,并简化服务间身份验证的复杂性。
前提条件
已添加集群到ASM实例,且ASM实例版本为1.6及以上。
背景信息
服务网格包含两种认证方式:
传输认证:基于双向TLS技术,常用于服务间通信认证。
来源认证:基于JWT技术,常用于客户端和服务之间的请求认证。
JWT是一种用于双方之间传递安全信息的表述性声明规范。关于JWT的更多信息,请参见JWT官方文档。
步骤一:创建命名空间并部署示例服务
创建foo命名空间,设置标签名称为istio-injection,值为enabled。具体操作,请参见管理全局命名空间。
使用以下内容,创建httpbin.yaml和sleep.yaml。
通过kubectl连接集群,分别执行以下命令,在foo命名空间部署httpbin和sleep服务。
关于如何通过kubectl连接集群,请参见获取集群KubeConfig并通过kubectl工具连接集群。
kubectl apply -f httpbin.yaml -n foo kubectl apply -f sleep.yaml -n foo
通过sleep服务访问httpbin服务。
执行以下命令,进入sleep环境开启bash。
kubectl exec -it deploy/sleep -- sh
执行以下命令,向httpbin服务发送请求。
curl -I httpbin.foo.svc.cluster.local:8000
预期输出:
HTTP/1.1 200 OK server: envoy date: Thu, 21 Dec 2023 07:39:55 GMT content-type: text/html; charset=utf-8 content-length: 9593 access-control-allow-origin: * access-control-allow-credentials: true x-envoy-upstream-service-time: 14
返回
200 OK
,表明请求成功。
步骤二:创建请求身份认证
登录ASM控制台,在左侧导航栏,选择 。
在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择 ,然后单击使用YAML创建。
设置命名空间为foo,然后在文本框中输入请求身份认证的YAML内容,单击创建。
以下YAML表示当请求
httpbin
服务时,需匹配jwtRules
中定义的规则,即请求头中如果包含Access Token信息,解码后的iss
的值必须为testing@secure.istio.io
。jwks
中定义了Token生成的相关信息。更多信息,请参见JWT官方文档。apiVersion: "security.istio.io/v1beta1" kind: "RequestAuthentication" metadata: name: "jwt-example" namespace: foo spec: selector: matchLabels: app: httpbin jwtRules: - issuer: "testing@secure.istio.io" jwks: '{ "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-envvQ","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65pHymX-P7KfIupjf59vsdo91bSP9C8H07pSAGQO1MV_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5DXIg_pbhLdKXbi66GlVeK6ABZOUW3WYtnNHD-91gVuoeJT_DwtGGcp4ignkgXfkiEm4sw-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoUqgBo_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZbDAa_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqTZ0BJ_EyxOGuHJrLsn00fnMQ"}]}'
解析Token。
本示例使用的Token信息如下所示。
TOKEN='eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg'
执行以下命令,解析Token。
echo $TOKEN | cut -d '.' -f2 - | base64 --decode -
预期输出:
{"exp":4685989700,"foo":"bar","iat":1532389700,"iss":"testing@secure.istio.io","sub":"testing@secure.istio.io"}
JWT官网也提供了同样的解析Token能力,图形化输出如下图所示。
通过sleep服务访问httpbin服务。
执行以下命令,进入sleep环境开启bash。
kubectl exec -it deploy/sleep -- sh
执行以下命令,向httpbin服务发送请求,请求头中包含合法的Access Token。
请将
your_valid_access_token_here
替换为实际的合法访问令牌。TOKEN=your_valid_access_token_here curl -I -H "Authorization: Bearer $TOKEN" httpbin.foo.svc.cluster.local:8000
预期输出:
HTTP/1.1 200 OK
执行以下命令,向httpbin服务发送请求,请求头中包含非法的Access Token。
请将
your_invalid_access_token_here
替换为实际的非法访问令牌。INVALID_TOKEN=your_invalid_access_token_here curl -I -H "Authorization: Bearer $INVALID_TOKEN" httpbin.foo.svc.cluster.local:8000
返回
401 Unauthorized
表示请求被身份认证拒绝,访问失败。
步骤三:创建JWT授权策略
登录ASM控制台,在左侧导航栏,选择 。
在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择 ,然后单击使用YAML创建。
设置命名空间为foo,然后在文本框中输入授权策略的YAML内容,单击创建。
以下YAML表示请求
httpbin
服务时,只有请求头Token解码后,符合iss
的值+/
+sub
的值(即source.requestPrincipals
)为testing@secure.istio.io/testing@secure.istio.io
,请求权限才为ALLOW
。apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: require-jwt namespace: foo spec: selector: matchLabels: app: httpbin action: ALLOW rules: - from: - source: requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
解析Token。
本示例使用的Token信息如下所示。
TOKEN='eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg'
执行以下命令,解析Token。
echo $TOKEN | cut -d '.' -f2 - | base64 --decode -
预期输出:
{"exp":4685989700,"foo":"bar","iat":1532389700,"iss":"testing@secure.istio.io","sub":"testing@secure.istio.io"}
通过sleep服务访问httpbin服务。
执行以下命令,进入sleep环境开启bash。
kubectl exec -it deploy/sleep -- sh
执行以下命令,向httpbin服务发送请求,请求头中包含合法的Access Token。
请将
your_valid_access_token_here
替换为实际的合法访问令牌。TOKEN=your_valid_access_token_here curl -I -H "Authorization: Bearer $TOKEN" httpbin.foo.svc.cluster.local:8000
预期输出:
HTTP/1.1 200 OK
执行以下命令,向httpbin服务发送请求,请求头中包含非法的Access Token。
请将
your_invalid_access_token_here
替换为实际的非法访问令牌。INVALID_TOKEN=your_invalid_access_token_here curl -I -H "Authorization: Bearer $INVALID_TOKEN" httpbin.foo.svc.cluster.local:8000
返回
403 Forbidden
表示请求被授权策略拒绝,访问失败。
步骤四:追加JWT授权策略
登录ASM控制台,在左侧导航栏,选择 。
在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择 。
在授权策略页面,单击require-jwt策略右侧的查看YAML。
在编辑对话框,补充以下内容,然后单击确定。
when: - key: request.auth.claims[groups] values: ["group1"]
完整的YAML示例如下。YAML表示请求
httpbin
服务时,只有请求头Token解码后,符合groups
的值包含group1,请求权限才为ALLOW
。apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: require-jwt namespace: foo spec: selector: matchLabels: app: httpbin action: ALLOW rules: - from: - source: requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"] when: - key: request.auth.claims[groups] values: ["group1"]
解析Token。
本示例使用的Token信息如下所示。
TOKEN_GROUP='eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjM1MzczOTExMDQsImdyb3VwcyI6WyJncm91cDEiLCJncm91cDIiXSwiaWF0IjoxNTM3MzkxMTA0LCJpc3MiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyIsInNjb3BlIjpbInNjb3BlMSIsInNjb3BlMiJdLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.EdJnEZSH6X8hcyEii7c8H5lnhgjB5dwo07M5oheC8Xz8mOllyg--AHCFWHybM48reunF--oGaG6IXVngCEpVF0_P5DwsUoBgpPmK1JOaKN6_pe9sh0ZwTtdgK_RP01PuI7kUdbOTlkuUi2AO-qUyOm7Art2POzo36DLQlUXv8Ad7NBOqfQaKjE9ndaPWT7aexUsBHxmgiGbz1SyLH879f7uHYPbPKlpHU6P9S-DaKnGLaEchnoKnov7ajhrEhGXAQRukhDPKUHO9L30oPIr5IJllEQfHYtt6IZvlNUGeLUcif3wpry1R5tBXRicx2sXMQ7LyuDremDbcNy_iE76Upg'
执行以下命令,解析Token。
echo "$TOKEN_GROUP" | cut -d '.' -f2 - | base64 --decode - | jq
预期输出:
{ "exp": 3537391104, "groups": [ "group1", "group2" ], "iat": 1537391104, "iss": "testing@secure.istio.io", "scope": [ "scope1", "scope2" ], "sub": "testing@secure.istio.io" }
通过sleep服务访问httpbin服务。
执行以下命令,进入sleep环境开启bash。
kubectl exec -it deploy/sleep -- sh
执行以下命令,向httpbin服务发送请求,请求头中包含合法的Access Token。
请将
your_valid_access_token_here
替换为实际的合法访问令牌。TOKEN=your_valid_access_token_here curl -I -H "Authorization: Bearer $TOKEN" httpbin.foo.svc.cluster.local:8000
返回
200 OK
表示请求通过授权策略认证,访问成功。执行以下命令,向httpbin服务发送请求,请求头中包含非法的Access Token。
请将
your_invalid_access_token_here
替换为实际的非法访问令牌。INVALID_TOKEN=your_invalid_access_token_here curl -I -H "Authorization: Bearer $INVALID_TOKEN" httpbin.foo.svc.cluster.local:8000
返回
403 Forbidden
表示请求被授权策略拒绝,访问失败。
相关文档
如果您想了解ASM支持的JWT算法、如何使用JwksUri、如何配置特定路径不进行请求的JWT鉴权,请参见JWT FAQ。