使用 istio ingress/gateway 将 JWT 声明复制到标头
我正在尝试使用未记录的DYNAMIC_METADATA
功能来实现添加 JWT 声明作为请求标头,如 此 github 问题评论 和在此 Google 文档功能提案<中作为“现有解决方案”进行了更详细的解释/a>.顺便问一下,是否有一个地方可以跟踪这些功能提案?我想获得有关该提案状态的更多信息,它在路线图上的任何位置吗?
我正在谈论的具体部分是这样的:
解决方案 3:使用 VirtualService 中未记录的功能
Istio VirtualService 支持使用 DYNAMIC_METADATA 键从动态属性设置标头。这可以与 JWT 元数据结合起来,将声明复制到标头。
请参阅下面的示例api版本:networking.istio.io/v1alpha3 种类:虚拟服务 元数据: 名称:评论路线 规格: 主持人: -reviews.prod.svc.cluster.local http: - 标题: 要求: 放: # 将组声明复制到 x-istio-jwt-group 标头 x-istio-jwt-组: '%DYNAMIC_METADATA(["istio_authn", "request.auth.claims", "group"])%'
作为 POC,我部署了一个应用程序,该应用程序侦听 /echo-header
并回显 whatever-id
的值它收到的任何请求的标头。该应用程序称为web
,并且有一个附带的种类:服务
,称为web-svc
。我配置了多个AuthorizationPolicy
资源和一个RequestAuthentication
资源,以便只能使用有效的 JWT 访问此服务。当我在没有 JWT 或过期 JWT 的情况下发出请求时,我收到 401 错误,这部分工作正常。 VirtualService
和Gateway
资源使服务可用于外部请求。到目前为止,一切都很好。
从现在开始,我将复制 JWT 上存在的 whatever-id
声明的值(在 jwt.io) 到 whatever-id
标头中。
然后,我修改了功能提案中提到的VirtualService
,如下所示:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: web
spec:
hosts:
- example.com
gateways:
- web-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
host: web-svc
port:
number: 80
headers:
request:
set:
whatever-id: '%DYNAMIC_METADATA(["istio_authn", "request.auth.claims", "whatever-id"])%'
# whatever-id: "testing"
但这不起作用。我通过注释/取消注释最后两行来验证标头转换部分,然后从我的 POC 应用程序返回测试
字符串。但是,当我将配置与应将声明值复制到标头的行一起使用时,标头未在请求中设置。
当我将日志记录设置为rbac:debug
时,我可以在发出请求时看到以下日志:
2022-02-23T14:04:05.708454Z debug envoy rbac checking request: requestedServerName: outbound_.80_._.web-svc.route-echo.svc.cluster.local, sourceIP: 172.16.36.22:50722, directRemoteIP: 172.16.36.22:50722, remoteIP: 172.16.36.35:0,localAddress: 172.16.36.57:80, ssl: uriSanPeerCertificate: spiffe://cluster.local/ns/istio-ingress/sa/istio-ingress, dnsSanPeerCertificate: , subjectPeerCertificate: , headers: ':authority', 'example.com'
':path', '/echo-header'
':method', 'GET'
':scheme', 'https'
... <removed irrelevant headers for brevity>
, dynamicMetadata: filter_metadata {
key: "envoy.filters.http.jwt_authn"
value {
fields {
key: "<redacted issuer url>"
value {
struct_value {
... <removed all irrelevant claims for brevity>
fields {
key: "whatever-id"
value {
string_value: "98a5b3ea-f5e7-4012-8cf5-9cfb5cf9e65f"
}
}
}
}
}
}
}
filter_metadata {
key: "istio_authn"
value {
fields {
key: "request.auth.audiences"
value {
string_value: "account"
}
}
fields {
key: "request.auth.claims"
value {
struct_value {
... <removed all irrelevant claims for brevity>
fields {
key: "whatever-id"
value {
list_value {
values {
string_value: "98a5b3ea-f5e7-4012-8cf5-9cfb5cf9e65f"
}
}
}
}
}
}
}
fields {
key: "request.auth.presenter"
value {
string_value: "poc"
}
}
fields {
key: "request.auth.principal"
value {
string_value: "<redacted>"
}
}
fields {
key: "request.auth.raw_claims"
value {
string_value: "<redacted>"
}
}
}
}
查看此内容时我注意到的第一件事是dynamicMetadata
(我假设可以使用解决方案中提到的 %DYNAMIC_METADATA()%
语法进行访问)不包含istio_authn
字段,它包含的唯一字段是envoy.filters.http.jwt_auth
字段,其键值等于我的 JWT 的颁发者 URL,在属于该密钥的值下,有一个 whatever-id
字段,其中包含我想将其添加到标头中,因此我尝试将 VirtualService 中的标头值更改为:
whatever-id: '%DYNAMIC_METADATA(["envoy.filters.http.jwt_authn", "<issuer url>", "whatever-id"])%'
遗憾的是,这也不起作用。
我还注意到,解决方案中使用的密钥("istio_authn"、"request.auth.claims"
)可在 filter_metadata
属性下使用日志(与dynamicMetadata
属性相对)。
那么也许可以使用另一种语法来访问这些filter_metadata
属性?
环境详细信息:
- Kubernetes 版本 1.22.6
- 使用 Azure AKS
- Istio 1.13.0 使用 Helm Chart 部署
I'm trying to implement adding JWT claims as request headers, using the undocumented DYNAMIC_METADATA
feature as mentioned in this github issue comment and explained in more detail as an 'existing solution' in this google doc feature proposal. By the way, is there a place where these feature proposals are tracked? I would like to get more information about the state of this proposal, is it anywhere on the roadmap?
The specific part I'm talking about this this:
Solution 3: Use an undocumented feature in VirtualService
Istio VirtualService supports setting headers from dynamic attributes using the DYNAMIC_METADATA key. This can be combined with the JWT metadata to copy claims to headers.
See example belowapiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: reviews-route spec: hosts: - reviews.prod.svc.cluster.local http: - headers: request: set: # Copy the group claim to the x-istio-jwt-group header x-istio-jwt-group: '%DYNAMIC_METADATA(["istio_authn", "request.auth.claims", "group"])%'
As a POC, I have deployed an app which listens on /echo-header
and will echo back the value of the whatever-id
header of any request it receives. The app is called web
and has an accompanying kind: Service
called web-svc
. I have configured several AuthorizationPolicy
resources and one RequestAuthentication
resource to make it so that this service can only be accessed with a valid JWT. This part works as I get a 401 when I make a request without JWT or with expired JWT. A VirtualService
and Gateway
resource make the service available for external requests. So far so good.
My from from here on out is to copy the value of the whatever-id
claim which exists on my JWT (verified on jwt.io) into the whatever-id
header.
I Have then modified the VirtualService
as mentioned in the feature proposal like so:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: web
spec:
hosts:
- example.com
gateways:
- web-gateway
http:
- match:
- uri:
prefix: /
route:
- destination:
host: web-svc
port:
number: 80
headers:
request:
set:
whatever-id: '%DYNAMIC_METADATA(["istio_authn", "request.auth.claims", "whatever-id"])%'
# whatever-id: "testing"
This however does not work. I verified the header transformation part, by commenting/uncommenting the last 2 lines, after which I did the testing
string back from my POC application. But when I use the config with the line that should copy the claim value into the header, the header is not set on the request.
When I set logging to rbac:debug
I can see the following log when making a request:
2022-02-23T14:04:05.708454Z debug envoy rbac checking request: requestedServerName: outbound_.80_._.web-svc.route-echo.svc.cluster.local, sourceIP: 172.16.36.22:50722, directRemoteIP: 172.16.36.22:50722, remoteIP: 172.16.36.35:0,localAddress: 172.16.36.57:80, ssl: uriSanPeerCertificate: spiffe://cluster.local/ns/istio-ingress/sa/istio-ingress, dnsSanPeerCertificate: , subjectPeerCertificate: , headers: ':authority', 'example.com'
':path', '/echo-header'
':method', 'GET'
':scheme', 'https'
... <removed irrelevant headers for brevity>
, dynamicMetadata: filter_metadata {
key: "envoy.filters.http.jwt_authn"
value {
fields {
key: "<redacted issuer url>"
value {
struct_value {
... <removed all irrelevant claims for brevity>
fields {
key: "whatever-id"
value {
string_value: "98a5b3ea-f5e7-4012-8cf5-9cfb5cf9e65f"
}
}
}
}
}
}
}
filter_metadata {
key: "istio_authn"
value {
fields {
key: "request.auth.audiences"
value {
string_value: "account"
}
}
fields {
key: "request.auth.claims"
value {
struct_value {
... <removed all irrelevant claims for brevity>
fields {
key: "whatever-id"
value {
list_value {
values {
string_value: "98a5b3ea-f5e7-4012-8cf5-9cfb5cf9e65f"
}
}
}
}
}
}
}
fields {
key: "request.auth.presenter"
value {
string_value: "poc"
}
}
fields {
key: "request.auth.principal"
value {
string_value: "<redacted>"
}
}
fields {
key: "request.auth.raw_claims"
value {
string_value: "<redacted>"
}
}
}
}
First thing I noticed when looking at this, is that the dynamicMetadata
(which I assumed can be accessed by using the %DYNAMIC_METADATA()%
synxtax as mentioned in the solution) does not contain an istio_authn
field, the only field it contains is the envoy.filters.http.jwt_auth
field, which has the key value equal to the issuer URL of my JWT, and under the value belonging to that key, there is a whatever-id
field, which has the value which I want to add to my header, so I tried changing the header value in my VirtualService to:
whatever-id: '%DYNAMIC_METADATA(["envoy.filters.http.jwt_authn", "<issuer url>", "whatever-id"])%'
Sadly this did not work either.
What I also noticed, is that the keys used in the solution ("istio_authn", "request.auth.claims"
) are available under the filter_metadata
property of the log (as opposed to the dynamicMetadata
property).
So maybe it is possible to use another syntax to access those filter_metadata
properties?
Environment details:
- Kubernetes version 1.22.6
- Using Azure AKS
- Istio 1.13.0 deployed using helm chart
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论