kubernetes exec-credential command for OIDC Authorization flow with PKCE#1840
kubernetes exec-credential command for OIDC Authorization flow with PKCE#1840d-honeybadger wants to merge 3 commits intodigitalocean:mainfrom
Conversation
| @@ -0,0 +1,162 @@ | |||
| <!DOCTYPE html> | |||
| @@ -0,0 +1,164 @@ | |||
| <!DOCTYPE html> | |||
d5c453d to
b8b6e22
Compare
|
|
||
| // in case we ever want to change this, or let folks configure it... | ||
| func defaultConfigHome() string { | ||
| var defaultConfigHome = func() string { |
There was a problem hiding this comment.
So that it can be stubbed in tests.
| return filepath.Join(kubeconfigCachePath(), id+".json") | ||
| } | ||
|
|
||
| func cachedSSOExecCredentialPath(id string) string { |
There was a problem hiding this comment.
Separate files for SSO tokens
b8b6e22 to
84c9897
Compare
|
|
||
| server := &http.Server{ | ||
| Handler: t.ssoServer, | ||
| Addr: fmt.Sprintf(":%d", t.port), |
There was a problem hiding this comment.
":8080" listens on every interface, the browser only needs to reach localhost. Suggested to use fmt.Sprintf("127.0.0.1:%d", t.port)
There was a problem hiding this comment.
Good point, thanks!
| } | ||
|
|
||
| t.logger.Println("Received an authorization code, exchanging for ID token") | ||
| token, err := t.oauth2Config.Exchange(ctx, code, oauth2.S256ChallengeOption(t.codeVerifier), oauth2.VerifierOption(t.codeVerifier)) |
There was a problem hiding this comment.
Is CodeChallenge required to be passed in token exchange step?
There was a problem hiding this comment.
Yes. Maybe some IDPs don't expect it (code challenge should be enough?) but Auth0 throws me an error if the verifier is not provided:
Error: Failed to get ID token: exchanging authorization code for ID token: oauth2: "invalid_request" "Parameter 'code_verifier' is required"
There was a problem hiding this comment.
@d-honeybadger I agree the verifier is required, but as per the PKCE standard I don’t think we need to pass code_challenge and code_challenge_method in the token request, which are currently being passed as the third argument in this function call.
As per the spec, the token exchange request should include the code_verifier, while code_challenge and code_challenge_method are only used during the authorization request.
Reference for token request:
https://www.oauth.com/oauth2-servers/pkce/authorization-code-exchange/
What are your thoughts?
| return "", time.Time{}, errors.New("no ID token found") | ||
| } | ||
|
|
||
| return idToken, token.Expiry, nil |
There was a problem hiding this comment.
Can we verify the ID token locally before returning it. We are pulling id_token out of the token response and forward it to kubectl as-is — no signature, iss, aud, or exp check
There was a problem hiding this comment.
This command doesn't authorize the user to do anything though, it just returns a token that will be passed to kube-apiserver which will perform all the necessary verifications. I added a simple verification, but I think we can be pretty minimal here and not duplicate kube-apiserver's job - WDYT?
|
|
||
| execCredDesc := "INTERNAL: This hidden command is for printing a cluster's exec credential" | ||
| cmdExecCredential := CmdBuilder(cmd, k8sCmdService.RunKubernetesKubeconfigExecCredential, "exec-credential <cluster-id>", execCredDesc, execCredDesc, Writer, hiddenCmd()) | ||
| cmdExecCredential := CmdBuilder(cmd, k8sCmdService.RunKubernetesKubeconfigExecCredential, "exec-credential <cluster-id>", execCredDesc, execCredDesc, Writer) //, hiddenCmd()) |
There was a problem hiding this comment.
If we’re making this command non-hidden, should we also update the execCredDesc accordingly?
Just a small clarification — should the command here be |


Adds a set of flags to
doctl kubernetes kubeconfig exec-credentialcommand to be able to handle OIDC authorization.Currently,
doctl kubernetes kubeconfig exec-credentialis used to fetch a DO PAT from DOKS API, and this PAT is used by kubectl to authenticate inside the k8s cluster.The additional flags enable
doctl kubernetes kubeconfig exec-credentialto instead receive a token (ID token) from an OIDC idendity provider such as Okta, Auth0.The authorization flow implemented here is similar to how OSS kubectl plugins do it (e.g. https://github.com/int128/kubelogin) but with our own implementation we get seamless UX (users don't have to install and configure third-party plugins) and flexibility in adjusting & fixing any issies.