<p>I have come to the (preliminary) conclusion that this cannot be done.</p>
<p>First, I had set the wrong <code>idp-issuer-url</code>. I had selected the IDP that normally serves during OIDC authentication to the Kubernetes cluster. But <code>$token</code> (or <code>$CI_JOB_JWT</code> in GitLab CI/CD parlance) was not generated there but by GitLab instead. Inspection e.g. at <a href="https://jwt.io/" rel="nofollow noreferrer">jwt.io</a> indicates <code>&quot;iss&quot;: &quot;kubernetes/serviceaccount&quot;</code>, so <code>--auth-provider-arg idp-issuer-url=kubernetes/serviceaccount</code> should be a better choice.</p>
<p>But this inspection also reveals that the JWT does carry a claim <code>aud</code>, hence no client-id. <code>kubectl</code> in particular (and perhaps OIDC in general) apparently insist on a non-empty client-id (otherwise: &quot;error: Must provide client-id&quot;). So I guess what happens is that <code>kubectl</code> checks the issuer (signer) and client-id for <code>$token</code> (claims <code>iss</code> and <code>aud</code> in its JWT payload) before it will use it. The check for client-id must fail, at which point <code>kubectl</code> tries a token refresh and that fails again.</p>
<p>If that diagnosis is correct this cannot be done because <code>kubectl</code> insists on a client-id whereas GitLab does not provide one in <code>$token</code>. I guess the reason for the discrepancy is that GitLab's is a general JWT token, whereas <code>kubectl</code> (more specifically, its OIDC autentication provider)  expects a OIDC id tokens in particular (unless it is invoked with <code>--token</code>, which apparently bypasses kubeconfig and hence the OIDC authentication provider).</p>

CC BY-SA 4.0
2021-06-02T11:28:16.413Z
2021-06-02T11:28:16.413Z
rookie099
<p>I can connect to the Kubernetes API from a container running inside the cluster with an OIDC token like so:</p>
<pre><code>kubectl —token $token get pod
</code></pre>
<p>I would now like to prepare a kubeconfig such that other programs that don’t support <code>--token</code> can connect as well. I am trying this in the specific context of <code>docker buildx create --driver kubernetes ...; docker buildx build .</code> where the 2nd part needs to create a <code>deployment</code>. Here's how I have proceeded:</p>
<pre><code>tmp=$(mktemp -p $PWD)
kubectl config --kubeconfig $tmp set-cluster cluster \
  --server https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT \
  --certificate-authority /var/run/secrets/kubernetes.io/serviceaccount/ca.crt 
kubectl config --kubeconfig $tmp set-credentials user --auth-provider oidc \
  --auth-provider-arg idp-issuer-url=... \
  --auth-provider-arg client-id=... \
  --auth-provider-arg id-token=$token
kubectl config --kubeconfig $tmp set-context context --cluster cluster --user user
kubectl config --kubeconfig $tmp use-context context
export KUBECONFIG=$tmp
kubectl get pod
</code></pre>
<p><code>kubectl get pod</code> now fails with &quot;Unable to connect to the server: No valid id-token, and cannot refresh without refresh-token&quot;. Why does it deem <code>$token</code> invalid when it has worked just before with <code>kubectl get pod --token</code> (and still does)? How can create a kubeconfig &quot;envelope&quot; around <code>$token</code> such that <code>kubectl get pod</code> will accept it and won't fail? (I've not specified <code>refresh-token</code> because it shouldn't be needed in the case of a valid token and because I don't have it readily available inside the container.)</p>

<docker><kubernetes><security><kubectl>
OIDC token invalid when put into kubeconfig
rookie099
# OIDC token invalid when put into kubeconfig

(Asked by: username_0 on 2021-06-02)

I can connect to the Kubernetes API from a container running inside the cluster with an OIDC token like so:
kubectl —token $token get pod

I would now like to prepare a kubeconfig such that other programs that don’t support --token can connect as well. I am trying this in the specific context of docker buildx create --driver kubernetes ...; docker buildx build . where the 2nd part needs to create a deployment. Here's how I have proceeded:
tmp=$(mktemp -p $PWD)
kubectl config --kubeconfig $tmp set-cluster cluster \
  --server https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT \
  --certificate-authority /var/run/secrets/kubernetes.io/serviceaccount/ca.crt 
kubectl config --kubeconfig $tmp set-credentials user --auth-provider oidc \
  --auth-provider-arg idp-issuer-url=... \
  --auth-provider-arg client-id=... \
  --auth-provider-arg id-token=$token
kubectl config --kubeconfig $tmp set-context context --cluster cluster --user user
kubectl config --kubeconfig $tmp use-context context
export KUBECONFIG=$tmp
kubectl get pod

kubectl get pod now fails with "Unable to connect to the server: No valid id-token, and cannot refresh without refresh-token". Why does it deem $token invalid when it has worked just before with kubectl get pod --token (and still does)? How can create a kubeconfig "envelope" around $token such that kubectl get pod will accept it and won't fail? (I've not specified refresh-token because it shouldn't be needed in the case of a valid token and because I don't have it readily available inside the container.)

**Tags:** docker, kubernetes, security, kubectl


---

## 1 answers

### Answer by username_0 on 2021-06-02. Score: 1 | Accepted answer

I have come to the (preliminary) conclusion that this cannot be done.

First, I had set the wrong `idp-issuer-url`. I had selected the IDP that normally serves during OIDC authentication to the Kubernetes cluster. But `$token` (or `$CI_JOB_JWT` in GitLab CI/CD parlance) was not generated there but by GitLab instead. Inspection e.g. at [jwt.io](https://jwt.io/) indicates `"iss": "kubernetes/serviceaccount"`, so `--auth-provider-arg idp-issuer-url=kubernetes/serviceaccount` should be a better choice.

But this inspection also reveals that the JWT does carry a claim `aud`, hence no client-id. `kubectl` in particular (and perhaps OIDC in general) apparently insist on a non-empty client-id (otherwise: "error: Must provide client-id"). So I guess what happens is that `kubectl` checks the issuer (signer) and client-id for `$token` (claims `iss` and `aud` in its JWT payload) before it will use it. The check for client-id must fail, at which point `kubectl` tries a token refresh and that fails again.

If that diagnosis is correct this cannot be done because `kubectl` insists on a client-id whereas GitLab does not provide one in `$token`. I guess the reason for the discrepancy is that GitLab's is a general JWT token, whereas `kubectl` (more specifically, its OIDC autentication provider) expects a OIDC id tokens in particular (unless it is invoked with `--token`, which apparently bypasses kubeconfig and hence the OIDC authentication provider).


---

