int128 / kubelogin

kubectl plugin for Kubernetes OpenID Connect authentication (kubectl oidc-login)
Apache License 2.0
1.7k stars 193 forks source link

Add new `--oidc-use-access-token` flag to `get-token` #1084

Closed adkafka closed 1 month ago

adkafka commented 5 months ago

Implements https://github.com/int128/kubelogin/issues/1083. See description there for context.

In its current form, this PR is bare bones functionality. I have not yet added any tests to confirm this behavior. Additionally, we could consider updating some of the naming. It is confusing to return a TokenSet where IDToken actually has an accessToken. I'm open to feedback on how best to improve this. However, changes to this may effect which token is cached and validated. So I'm hesitant to make this change unless we think it is necessary.

However, this PR is functional. I have validated it locally. Without adding --oidc-use-access-token, and id_token is successfully returned. Adding --oidc-use-access-token results in an access_token being successfully returned.

adkafka commented 4 months ago

I realize I have some tests failing because I haven't updated the mocks (mockery --all --inpackage --with-expecter). Fixing that and adding at least one test shortly.

EDIT: This actually isn't so easy. The version of mockery used previously (v2.13.1) seems incompatible with our current go version. We are running into this issue: https://vektra.github.io/mockery/v2.35/notes/#internal-error-package-without-types-was-imported

adkafka commented 4 months ago

@int128 Are you able to take a look at this PR when you have a chance? I'm happy to update if you have suggestions. I wasn't sure if there are any better unit tests to add than the ones I added. And I'm unsure if it is worth updating TokenSet fields such that we actually store the AccessToken as opposed to overloading the IDToken field. Thanks!

jsphpl commented 4 months ago

I can confirm that the --oidc-use-access-token works as intended.

However, I had to disable verification of the access_token because I passed --oidc-auth-request-extra-params="audience=CLUSTER_CLIENT_ID". Verifying the access_token is not necessary anyway, see my comments above.

Btw. verifying the id_token isn't necessay either, because we're just the client. Verification has to happen on the resource server (k8s API). We're not granting the user any access – we're merely passing the token to the resource server. Or are we?

adkafka commented 3 months ago

However, I had to disable verification of the access_token because I passed --oidc-auth-request-extra-params="audience=CLUSTER_CLIENT_ID". Verifying the access_token is not necessary anyway, see my comments above.

This should be resolved now, after I pushed https://github.com/int128/kubelogin/pull/1084/commits/1add63b506925f34181007c871086e86e7954b6a.

glaberge commented 2 months ago

We use Okta and would also benefit from this as it would solve this issue as well (https://github.com/int128/kubelogin/issues/863) because the id_token has a hard coded lifetime of 60 minutes where the access token is configurable.

glaberge commented 2 months ago

@adkafka I was not able to use your patch with Okta. Probably something wrong with my config but essentially I'm using this:

kind: Config
preferences: {}
users:
    - name: okta
      user:
        exec:
            apiVersion: client.authentication.k8s.io/v1beta1
            args:
                - oidc-login-custom
                - get-token
                - --oidc-use-access-token=true
                - --oidc-issuer-url=https://paramountcommerce.okta.com/oauth2/<redacted>
                - --oidc-client-id=<redacted>
                - --oidc-extra-scope=email
                - --oidc-extra-scope=offline_access
                - --oidc-extra-scope=profile
                - --oidc-extra-scope=openid
                - --v=5
                - --force-refresh
                #- --skip-open-browser
            command: kubectl

I'm able to get a token that I can see in the cache, also getting a message that my token is valid (for 8 hours now yeah!), but I get 2 browser windows opening/closing one after the other. Verbose logging seems to indicate is makes 8 requests, 6 200OK and 2 401Unauthorized, and still ends up with a message from kubectl that error: You must be logged in to the server (Unauthorized). Removing - --oidc-use-access-token=true works as usual with your patch.

Just wondering if you have an idea of what's happening.

I tried various combinations within kubelogin and Okta but can't seem to get it to work.

adkafka commented 2 months ago

@adkafka I was not able to use your patch with Okta. Probably something wrong with my config but essentially I'm using this:

kind: Config
preferences: {}
users:
    - name: okta
      user:
        exec:
            apiVersion: client.authentication.k8s.io/v1beta1
            args:
                - oidc-login-custom
                - get-token
                - --oidc-use-access-token=true
                - --oidc-issuer-url=https://paramountcommerce.okta.com/oauth2/<redacted>
                - --oidc-client-id=<redacted>
                - --oidc-extra-scope=email
                - --oidc-extra-scope=offline_access
                - --oidc-extra-scope=profile
                - --oidc-extra-scope=openid
                - --v=5
                - --force-refresh
                #- --skip-open-browser
            command: kubectl

I'm able to get a token that I can see in the cache, also getting a message that my token is valid (for 8 hours now yeah!), but I get 2 browser windows opening/closing one after the other. Verbose logging seems to indicate is makes 8 requests, 6 200OK and 2 401Unauthorized, and still ends up with a message from kubectl that error: You must be logged in to the server (Unauthorized). Removing - --oidc-use-access-token=true works as usual with your patch.

Just wondering if you have an idea of what's happening.

I tried various combinations within kubelogin and Okta but can't seem to get it to work.

I don't know off hand what the issue is. When I run in debug logging, I also do see some 4xx errors on some calls. Seems like the underlying library does some probing on the endpoints during the flow which can result in errors, but the flow itself can still work.

The browser window opening twice is interesting, I'm not sure what would cause that. Are you able to determine at what part of the flow the window opens?

Can you independently check that the JWT used (logged in debug mode) is valid, signed by the expected issuer, and has the expected audience (and any other checks) that you have configured your kubernetes cluster to perform? Given that the kube-login tool is able to successfully grab the token and use it against your kubernetes cluster (but the usage of the token fails), I suspect that the issue lies in the server-side configuration you have for your kubernetes cluster. IME, kubectl returns an opaque error such as the one you mentioned when the token used is not valid based on the kubernetes server-side configuration.

glaberge commented 2 months ago

For anyone using Okta and EKS, here's how I managed to fix this: In your custom auth server

adkafka commented 2 months ago

@int128 Are you able to review this PR? It seems to have already helped three people in the community (myself, @jsphpl and @glaberge). It would be great to get your review so others can benefit as well. Thanks!