Closed philomory closed 1 year ago
Hey,
Thank you for your feedback. My goal was to make a simple oauth-proxy that can be used to protect all the apps in the cluster as opposed to 1:1.
In terms of this feature, I plan to look into this in the next week to two.
This feature was released in 1.7.0. Give it a try and let me know if it works for you.
Sounds great I'll give it a shot for sure!
So, this seems great, although I've run into one minor issue: we use Auth0 as our OAuth2 provider, and Auth0 recommends using "namespaced" custom claims, of the form http://example.com/foo
rather than just foo
. We've followed their recommendations, so, e.g. our custom groups claim is of the form "http://magicmemories.com/groups":[...]
. Unfortunately, :
characters are not valid characters in HTTP header names (/
also seems like it might be disallowed, although opinions and implementations seem to vary).
I can think of three ways this could be addressed:
magicmemories.com|groups
, etc).ingress-nginx-validate-jwt
could automatically convert disallowed characters in header names to e.g. -
ingress-nginx-validate-jwt
could include a mechanism for specifying how to map claim names to header names, e.g. replacing &inject-claims=http%3A%3F%3Fmagicmemories.com%3Fgroups
with &inject-claims=http%3A%3F%3Fmagicmemories.com%3Fgroups%3Dgroups
, might map the custom claim http://magicmemories.com/groups
to the header groups
.On a separate note, this doesn't affect us, but if you don't go for option 3, it's also possible that some users might have JWT claims whose names match "standard" headers like Expires
or Age
(I mean, it doesn't seem very likely, but, I've seen weirder things); if option 3 above is chosen, then it can be left to the user to decide what these should map to, but otherwise you may want to consider prepending a prefix not used by any standard headers, e.g. mapping a claim foo
to jwt-claim-foo
or similar.
I like option 3. I'll code this in the next couple days.
Version 1.8.0 has a new parameter, see here https://github.com/IvanJosipovic/ingress-nginx-validate-jwt#inject-claims-as-headers-with-custom-name
Let me know how this works out.
The new setup works pretty well, although I do still run into a few issues:
System.InvalidOperationException: Sequence contains no matching element
). This mostly matters in the case where an API secured by JWT has both human and machine users; in our case authorization of human users if often controlled by a "groups" claim, while authorization of machine users is handled by the default scope
claim (and typically machine users will not have any groups claim in their token).{"sub":"foo","iss":"...","groups":["foo","bar","baz"]}
. Currently, if you request the injection of the groups
claim from such a token, you get only groups=foo
as your header, without any retention of bar
or baz
.
I'm not a C# or .NET developer, but I did some digging and it appears to me that System.IdentityModel.Tokens.Jwt
claims are always string-valued; I'm not sure if that means that the framework turns "groups":["foo","bar","baz"]
into three separate claims (["key":"groups","value":"foo"},{"key":"groups","value":"bar"},{"key":"groups","value":"baz"}]
), or if it simply discards any value from a multi-valued claim beyond the first, and expects users to encode such claims as strings rather than using the "native" multi-valued claims specified by the various RFCs.Either or both of the above issues can be worked around on our end, of course, but I thought they were worth pointing out. At the very least, both limitations should probably be documented.
Thanks for the awesome feedback. I have pushed v1.9.0 which should address all the issues above. I have removed "inject-claims" in favor of "inject-claim" and made it not required. I also added support for arrays.
Beautiful, that's basically perfect for our use-case. Thanks!
If you want to include an example of usage of the inject-claims
feature in an Ingress, something like this should be appropriate:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: emojivoto-2
annotations:
nginx.ingress.kubernetes.io/auth-url: http://ingress-nginx-validate-jwt.ingress-nginx-validate-jwt.svc.cluster.local:8080/auth?aud=11111111-11111-1111111111&inject-claim=https%3A%2F%2Fexample.com%2Fgroups,groups&inject-claim=scope
nginx.ingress.kubernetes.io/configuration-snippet: |
auth_request_set $groups $upstream_http_groups;
auth_request_set $scope $upstream_http_scope;
proxy_set_header JWT-Claim-Groups $groups;
proxy_set_header JWT-Claim-Scope $scope;
(and, contrary to my original, the appropriate nginx directives are auth_request_set
and proxy_set_header
, not auth_request_set
and add_header
)
Is there any way to extract the values of JWT claims and set them as response headers, so that the ingress controller can then pass them along to the actual backend using
auth_request_set
andadd_header
? Withoauth2-proxy
you can do this using the--set-xauthrequest
flag for basic configuration, or using theinjectResponseHeaders.*.values.*.claim
alpha configuration for advanced configuration.I'd love to see similar functionality here, because this tool seems much easier to use when different Ingress objects need different configurations; maybe something along the lines of:
nginx.ingress.kubernetes.io/auth-url: http://ingress-nginx-validate-jwt.ingress-nginx-validate-jwt.svc.cluster.local:8080/auth?tid=11111111-1111-1111-1111-111111111111&aud=22222222-2222-2222-2222-222222222222&aud=33333333-3333-3333-3333-333333333333&inject-claims=user,groups