Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KubeConfig.runExec doesn't work with kubeconfig exec command #3240

Open
nicolas-goudry opened this issue Mar 22, 2024 · 4 comments
Open

KubeConfig.runExec doesn't work with kubeconfig exec command #3240

nicolas-goudry opened this issue Mar 22, 2024 · 4 comments

Comments

@nicolas-goudry
Copy link

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

@brendandburns
Copy link
Contributor

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.

@nicolas-goudry
Copy link
Author

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?

@brendandburns
Copy link
Contributor

brendandburns commented Mar 23, 2024

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.

@nicolas-goudry
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants