基于 JWT 声明的路由
本任务将向您展示如何使用 Istio 入口网关上的请求身份验证和虚拟服务,根据 JWT 声明路由请求。
注意:此功能仅支持 Istio 入口网关,需要同时使用请求身份验证和虚拟服务才能正确验证和根据 JWT 声明进行路由。
开始之前
使用 Istio 安装指南 安装 Istio。
部署一个工作负载(例如
httpbin
)到一个命名空间(例如foo
),并使用以下命令通过 Istio 入口网关将其暴露出来$ kubectl create ns foo $ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin.yaml@) -n foo $ kubectl apply -f @samples/httpbin/httpbin-gateway.yaml@ -n foo
按照 确定入口 IP 和端口 中的说明定义
INGRESS_HOST
和INGRESS_PORT
环境变量。使用以下命令验证
httpbin
工作负载和入口网关是否按预期工作$ curl "$INGRESS_HOST:$INGRESS_PORT"/headers -s -o /dev/null -w "%{http_code}\n" 200
基于 JWT 声明配置入口路由
Istio 入口网关支持基于经过身份验证的 JWT 进行路由,这对于根据最终用户身份进行路由很有用,并且与使用未经身份验证的 HTTP 属性(例如路径或标头)相比更安全。
为了根据 JWT 声明进行路由,首先创建请求身份验证以启用 JWT 验证
$ kubectl apply -f - <<EOF apiVersion: security.istio.io/v1 kind: RequestAuthentication metadata: name: ingress-jwt namespace: istio-system spec: selector: matchLabels: istio: ingressgateway jwtRules: - issuer: "[email protected]" jwksUri: "https://raw.githubusercontent.com/istio/istio/release-1.24/security/tools/jwt/samples/jwks.json" EOF
请求身份验证在 Istio 入口网关上启用 JWT 验证,以便随后在虚拟服务中使用经过验证的 JWT 声明进行路由。
请求身份验证应用于入口网关,因为基于 JWT 声明的路由仅在入口网关上受支持。
注意:请求身份验证仅在请求中存在 JWT 时才会检查 JWT。要使 JWT 成为必需项,并在未包含 JWT 时拒绝请求,请应用 任务 中指定的授权策略。
更新虚拟服务以根据经过验证的 JWT 声明进行路由
$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: httpbin namespace: foo spec: hosts: - "*" gateways: - httpbin-gateway http: - match: - uri: prefix: /headers headers: "@request.auth.claims.groups": exact: group1 route: - destination: port: number: 8000 host: httpbin EOF
虚拟服务使用保留的标头
"@request.auth.claims.groups"
与 JWT 声明groups
进行匹配。前缀@
表示它与从 JWT 验证中获取的元数据匹配,而不是与 HTTP 标头匹配。支持字符串、字符串列表和嵌套声明类型的声明。使用
.
或[]
作为嵌套声明名称的分隔符。例如,"@request.auth.claims.name.givenName"
或"@request.auth.claims[name][givenName]"
匹配嵌套声明name
和givenName
,它们在这里是等效的。当声明名称包含.
时,只能使用[]
作为分隔符。
基于 JWT 声明验证入口路由
验证入口网关在没有 JWT 时返回 HTTP 代码 404
$ curl -s -I "http://$INGRESS_HOST:$INGRESS_PORT/headers" HTTP/1.1 404 Not Found ...
您也可以创建授权策略,在 JWT 丢失时明确拒绝请求,返回 HTTP 代码 403。
验证入口网关在 JWT 无效时返回 HTTP 代码 401
$ curl -s -I "http://$INGRESS_HOST:$INGRESS_PORT/headers" -H "Authorization: Bearer some.invalid.token" HTTP/1.1 401 Unauthorized ...
由于 JWT 验证失败,请求身份验证返回 401。
验证入口网关是否使用包含声明
groups: group1
的有效 JWT 令牌路由请求$ TOKEN_GROUP=$(curl https://raw.githubusercontent.com/istio/istio/release-1.24/security/tools/jwt/samples/groups-scope.jwt -s) && echo "$TOKEN_GROUP" | cut -d '.' -f2 - | base64 --decode {"exp":3537391104,"groups":["group1","group2"],"iat":1537391104,"iss":"[email protected]","scope":["scope1","scope2"],"sub":"[email protected]"}
$ curl -s -I "http://$INGRESS_HOST:$INGRESS_PORT/headers" -H "Authorization: Bearer $TOKEN_GROUP" HTTP/1.1 200 OK ...
验证入口网关在使用有效 JWT 但不包含声明
groups: group1
时是否返回 HTTP 代码 404$ TOKEN_NO_GROUP=$(curl https://raw.githubusercontent.com/istio/istio/release-1.24/security/tools/jwt/samples/demo.jwt -s) && echo "$TOKEN_NO_GROUP" | cut -d '.' -f2 - | base64 --decode {"exp":4685989700,"foo":"bar","iat":1532389700,"iss":"[email protected]","sub":"[email protected]"}
$ curl -s -I "http://$INGRESS_HOST:$INGRESS_PORT/headers" -H "Authorization: Bearer $TOKEN_NO_GROUP" HTTP/1.1 404 Not Found ...
清理
删除命名空间
foo
$ kubectl delete namespace foo
删除请求身份验证
$ kubectl delete requestauthentication ingress-jwt -n istio-system