Why use ID Tokens instead of Access Tokens for Authorization?

In step 3-4 of the OIDC Authentication flow, the user sends the ID Token to API Server seemingly to authorize a kubectl command. Why does Kubernetes derive authorizations from identity information instead of just using access tokens? It would remove the need for RoleBinding/ClusterRoleBinding objects that are required to associate identities with permissions.

My guess is that reducing network load in the form of requests to the IdP to validate the token (in the case of an opaque access token) was more of a priority. Is that correct? What other factors am I missing?

1 Like

Conversation on the Slack about this question here

1 Like

I was curious about this too.

I went and made a Slack account, but for the sake of easy reading I’ll also paste the message log here.

I had to remove some links because there’s a 5 link limit for new users but I don’t think anything of value was lost, it was mostly just cleaning up Slack copy/paste noise.

Hope that helps!

Messages are from 2/14/24 in the #sig-auth channel

Nathan (the OP)

Hi #sig-auth, I’m working on an optimization on apiserver, which needs scrutiny from sig-auth. So any possibility to get some review on [prototype] Make apiserver admission plugins retrieve k8s objects dir… by linxiulei · Pull Request #121979 · kubernetes/kubernetes · GitHub? Thanks in advance.

After reading through the Kubernetes documentation for authorization/authentication and this issue thread, I am curious as to why the Kubernetes API Server derives authorization permissions from identity information via OIDC tokens instead of using Access Tokens? I have some guesses, but I would love to understand this decision better.

mlbiam (Marc Boorshtein)

From an oidc spec perspective the only difference between an id_token and an access_token is that an id_token must be a jwt, an access token can be anything (with many identity providers generating JWTs)

So if you want to use an access_token instead of an id_token you could do that assuming the access_token is a jwt, properly scoped, etc

If your access_token isn’t a jwt, then you’d need to write a webhook to both validate the token and provide the userInfo object back to the API server

Nathan

Thanks for replying so quickly! That tracks with my understanding. I think I’m also differentiating them by the info they could contain (identity claims vs permission scopes) where the latter has the exact information we’d be looking for to make an authorization decision. As I’m looking at securing my own API server, I’m trying to learn from the designs of you all big-brain folks. I’ve read several auth provider documentations (0auth, Okta, etc.) that warns against providing ID Tokens as credentials to API servers, and Kubernetes seems to be one of the few big projects that does this. Do you know what drove that decision instead of going the more customary route of using access tokens for authorization?

mlbiam

i don’t think i’d say “the more customary route of using access tokens”, access tokens are not persecriptive, so there’s really nothing that says what goes in there. they’re opaque and can have any format (or just be a random number or string). there’s nothing to say what should go into an access token

the use of a JWT is really the only format that could be used that has an existing standard. the fact that the JWT is an id_token or access_token isn’t really important

if you want to use a token that’s not a JWT, whether that’s an id_token or access_token or anything else, would require a custom webhook so that adds soemthing to your environment that could leave your cluster broken (which i’ve seen plenty of times)

Nathan

Sorry, I didn’t mean to infer that access tokens as JWTs were customary. Just that they seem to be the standard bearer token for authorization decisions on API servers. But that’s helpful insight! So Kubernetes really wanted to use JWTs and OIDC was the available standard. That makes sense. Do you know why Kubernetes wanted to use JWTs instead of the opaque access tokens?

mlbiam

kubernetes does support opaque tokens, you just need to implement a webhook

that’s how kubernetes integrates with amazon, google cloud, azure, etc native IAM

Kubernetes supports multiple mechanisms, use the one that’s best for you.

what Kubernetes didn’t implement was its own proprietary access token type. i wasn’t there and i’m sure the decission is buried in some github issue, but implementing a custom access token type would have meant every auth system would have had to implement it making it much harder to rovide auth to the kubernetes api

Nathan

I’m not trying to use a particular auth method with Kubernetes at the moment. I’m just trying to understand the design. I know you’ve recommended the webhook a few times, and I should have made my intentions more clear.

Okay, I’ll go digging in past issues to flesh that out more, thanks!

mlbiam

it’s not that i’m recommending a webhook. you’re asking “why did kubernetes choose not to implement opaque access tokens?”. The answer is that kubernetes does support opaque access tokens, through a webhook. Personally I would never recommend this route as build-your-own auth isn’t too far off from build-your-own encryption. if you’re designing your own api service, then you need to understand who’s going to be providing auth info. For Kubernetes, the desire was to provide multiple options. if your service doesn’t need that, then great. For instance AWS doesn’t directly support JWTs, you need to use an STS to exchange a JWT or SAML assertion for an access key

Nathan

I did ask that, but want I’m really trying to know is how to reconcile the documentation from 0auth and Okta explicitly stating that ID Tokens should not be used as credentials to a Resource Server with Kubernetes explicitly providing a flow for doing so. I’m not an auth expert, so I’m trying to understand what about the Kubernetes implementation is different.

mlbiam

Ahhh

Yes. So by the spec and the intent of the oidc spec writers okta is correct

But that’s just not how it’s been used across APIs (not just kube)

Defacto standards vs standards written

Nathan

Ohhh

Thank you for clearing that up! That sounds confusing to track lol

There is an ietf spec to do this properly by first getting an access token and then doing a token exchange to get an access token that’s a jwt, but I haven’t seen anyone bother to implement it.

mlbiam

There are 200+ rfcs to get all of oidc figured out, so don’t feel too bad

Nathan

Haha guess I have a lot more reading to do! Thank you again!

Also in the new structured authentication config we don’t refer to this as OIDC anymore, it’s just a JWT authenticator. If you can pass a JWT access token to it, go for it. SPIFFE SVID? Also fine. The security of the system is up to you as you have full control over the trust relationship.

mo (Mo Khan)

I think we only require the iss, aud, and exp claims

@aramase (Anish Ramasekar) we should make sure to document the minimum valid payload

sftim (Tim Bannister)

First step: please open an issue for that, ideally with detail enough to help reviewers confirm whether merging some PR would close it.

mo

@aramase opened jwt: min valid payload · Issue #123318 · kubernetes/kubernetes · GitHub to track making this obvious and permanent in all the places