Answers: <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>
  
Answers: CC BY-SA 4.0
Answers: 2021-06-02T11:28:16.413Z
Answers: 2021-06-02T11:28:16.413Z
Answers: rookie099
Body: <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>
  
Tags: <docker><kubernetes><security><kubectl>
Title: OIDC token invalid when put into kubeconfig
UserDisplayName: rookie099
ThreadText: # 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).
  
  
  ---
  
  