java icon indicating copy to clipboard operation
java copied to clipboard

KubeConfig.runExec doesn't work with kubeconfig exec command

Open nicolas-goudry opened this issue 1 year ago • 4 comments
trafficstars

Describe the bug

This issue occurs with any kubeconfig file which uses an exec command to get user credentials.

When instantiating the ApiClient class through ClientBuilder.kubeconfig and a kubeconfig file built with KubeConfig.loadKubeConfig, the following error occurs:

java.lang.NullPointerException: Cannot invoke "java.io.File.toPath()" because "this.file" is null
    at io.kubernetes.client.util.KubeConfig.runExec (KubeConfig.java:333)
    at io.kubernetes.client.util.KubeConfig.getCredentialsViaExecCredential (KubeConfig.java:291)
    at io.kubernetes.client.util.KubeConfig.getCredentials (KubeConfig.java:239)
    at io.kubernetes.client.util.credentials.KubeconfigAuthentication.<init> (KubeconfigAuthentication.java:59)
    at io.kubernetes.client.util.ClientBuilder.kubeconfig (ClientBuilder.java:300)
    at io.kubernetes.client.examples.KubeConfigFileClientExample.main (KubeConfigFileClientExample.java:43)
    at org.codehaus.mojo.exec.ExecJavaMojo.lambda$execute$0 (ExecJavaMojo.java:283)
    at java.lang.Thread.run (Thread.java:833)

It seems that the KubeConfig.runExec method expects the kubeconfig to be provided as a file rather than a KubeConfig object.

The KubeConfigFileClientExample.java example can be fixed with the following changes:

diff --git a/examples/examples-release-20/src/main/java/io/kubernetes/client/examples/KubeConfigFileClientExample.java b/examples/examples-release-20/src/main/java/io/kubernetes/client/examples/KubeConfigFileClientExample.java
index 7a0ba4dcf..bb62b7365 100644
--- a/examples/examples-release-20/src/main/java/io/kubernetes/client/examples/KubeConfigFileClientExample.java
+++ b/examples/examples-release-20/src/main/java/io/kubernetes/client/examples/KubeConfigFileClientExample.java
@@ -22,6 +22,7 @@ import io.kubernetes.client.util.ClientBuilder;
 import io.kubernetes.client.util.KubeConfig;
 import java.io.FileReader;
 import java.io.IOException;
+import java.nio.file.Paths;
 
 /**
  * A simple example of how to use the Java API from an application outside a kubernetes cluster
@@ -37,10 +38,12 @@ public class KubeConfigFileClientExample {
     // file path to your KubeConfig
 
     String kubeConfigPath = System.getenv("HOME") + "/.kube/config";
+    KubeConfig kubeconfig = KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath));
+    kubeconfig.setFile(Paths.get(kubeConfigPath).toFile());
 
     // loading the out-of-cluster config, a kubeconfig from file-system
     ApiClient client =
-        ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath))).build();
+        ClientBuilder.kubeconfig(kubeconfig).build();
 
     // set the global default api-client to the in-cluster one from above
     Configuration.setDefaultApiClient(client);

Client Version

20

Kubernetes Version

1.28.6

Java Version

17

To Reproduce

Generate a kubeconfig file in $HOME/.kube/config which uses an exec command to get user credentials.

cd examples/examples-release-20
mvn -X clean install exec:java -Dexec.mainClass="io.kubernetes.client.examples.KubeConfigFileClientExample"

Expected behavior

Everything works fine

KubeConfig

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: REDACTED
    server: REDACTED
    tls-server-name: REDACTED
  name: REDACTED
contexts:
- context:
    cluster: REDACTED
    extensions:
    - extension: sandbox
      name: teleport.kube.name
    user: REDACTED
  name: REDACTED
current-context: REDACTED
kind: Config
preferences: {}
users:
- name: REDACTED
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      args:
      - kube
      - credentials
      - --kube-cluster=sandbox
      - --teleport-cluster=REDACTED
      - --proxy=REDACTED
      command: tsh
      env: null
      provideClusterInfo: false

Server (please complete the following information):

  • OS: Linux
  • Environment: system
  • Cloud: Azure

Additional context

nicolas-goudry avatar Mar 22 '24 15:03 nicolas-goudry

Ah yes, I see the problem. I think in cases where the file for the kubeconfig isn't present, we should just use the current working directory.

brendandburns avatar Mar 22 '24 23:03 brendandburns

In this case the kubeconfig file is not even in the current directory, it’s located in its default location ($HOME/.kube/config).

Wouldn’t it be best to just use the data loaded into the KubeConfig object instead? I don’t know Java very well, but from what I understand of the code, it seems that the required information is present in the object. Since we have the contexts and the users, I guess it should be possible to extract the exec command from the user of the current context. WDYT?

nicolas-goudry avatar Mar 23 '24 08:03 nicolas-goudry

I looked at the code and I don't think that the kubeconfig you supplied could have triggered this exception.

The code is here:

https://github.com/kubernetes-client/java/blob/release-20/util/src/main/java/io/kubernetes/client/util/KubeConfig.java#L333

And in order to throw that exception, your command needs to have a slash in it (/ or \) but in your example above, there's no slash it's just tsh

I think that there actually is a bug here, but to debug properly I need the correct kubeconfig which you used.

brendandburns avatar Mar 23 '24 15:03 brendandburns

And in order to throw that exception, your command needs to have a slash in it (/ or \) but in your example above, there's no slash it's just tsh

I think that there actually is a bug here, but to debug properly I need the correct kubeconfig which you used.

That's my bad, I copied the kubeconfig example on the three issues I opened at once and since I did multiple tests to try to make each of them work, I kept the command as tsh but in fact it's an absolute path from my root.

I don't think the real path is super relevant but it's something like that: /nix/store/xyz-tsh/bin/tsh.

Sorry about that and thanks for the quick fix! If you wish me to, I can test the fix tomorrow and let you know.

nicolas-goudry avatar Mar 23 '24 17:03 nicolas-goudry

The Kubernetes project currently lacks enough contributors to adequately respond to all issues.

This bot triages un-triaged issues according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Mark this issue as fresh with /remove-lifecycle stale
  • Close this issue with /close
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle stale

k8s-triage-robot avatar Jun 21 '24 17:06 k8s-triage-robot

Fixed by #3244

nicolas-goudry avatar Jun 22 '24 07:06 nicolas-goudry