Skip to content

Commit 28b1732

Browse files
committed
Draft implementation of #238: support client.authentication.k8s.io/v1beta1.
1 parent fb8544d commit 28b1732

File tree

1 file changed

+62
-0
lines changed

1 file changed

+62
-0
lines changed

util/src/main/java/io/kubernetes/client/util/KubeConfig.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,24 @@
1212
*/
1313
package io.kubernetes.client.util;
1414

15+
import com.google.gson.JsonElement;
16+
import com.google.gson.JsonObject;
17+
import com.google.gson.JsonParseException;
18+
import com.google.gson.JsonParser;
1519
import io.kubernetes.client.util.authenticators.Authenticator;
1620
import io.kubernetes.client.util.authenticators.AzureActiveDirectoryAuthenticator;
1721
import io.kubernetes.client.util.authenticators.GCPAuthenticator;
1822
import java.io.IOException;
23+
import java.io.InputStream;
24+
import java.io.InputStreamReader;
1925
import java.io.Reader;
2026
import java.nio.charset.StandardCharsets;
2127
import java.nio.file.FileSystems;
2228
import java.nio.file.Files;
2329
import java.nio.file.Paths;
2430
import java.util.ArrayList;
2531
import java.util.HashMap;
32+
import java.util.List;
2633
import java.util.Map;
2734
import org.apache.commons.codec.binary.Base64;
2835
import org.slf4j.Logger;
@@ -185,6 +192,7 @@ public String getPassword() {
185192
return getData(currentUser, "password");
186193
}
187194

195+
@SuppressWarnings("unchecked")
188196
public String getAccessToken() {
189197
if (currentUser == null) {
190198
return null;
@@ -214,6 +222,60 @@ public String getAccessToken() {
214222
}
215223
}
216224
}
225+
Object exec = currentUser.get("exec");
226+
if (exec != null) {
227+
// TODO extract to helper method for clarity
228+
Map<String, Object> execMap = (Map<String, Object>) exec;
229+
// https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins
230+
String apiVersion = (String) execMap.get("apiVersion");
231+
if ("client.authentication.k8s.io/v1beta1".equals(apiVersion)) { // TODO or v1alpha1 is apparently identical and could be supported
232+
String command = (String) execMap.get("command");
233+
List<Map<String, String>> env = (List) execMap.get("env");
234+
List<String> args = (List) execMap.get("args");
235+
// TODO relativize command to basedir of config file (requires KubeConfig to be given a basedir)
236+
List<String> argv = new ArrayList<>();
237+
argv.add(command);
238+
if (args != null) {
239+
argv.addAll(args);
240+
}
241+
ProcessBuilder pb = new ProcessBuilder(argv);
242+
if (env != null) {
243+
// TODO apply
244+
}
245+
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
246+
try {
247+
Process proc = pb.start();
248+
JsonElement root = null;
249+
try (InputStream is = proc.getInputStream();
250+
Reader r = new InputStreamReader(is, StandardCharsets.UTF_8)) {
251+
root = new JsonParser().parse(r);
252+
} catch (JsonParseException x) {
253+
log.error("Failed to parse output of " + command, x);
254+
}
255+
int r = proc.waitFor();
256+
if (r == 0) {
257+
if (root != null) {
258+
// TODO verify .apiVersion and .kind = ExecCredential
259+
JsonObject status = root.getAsJsonObject().get("status").getAsJsonObject();
260+
JsonElement token = status.get("token");
261+
if (token != null) {
262+
return token.getAsString();
263+
}
264+
// TODO handle clientCertificateData/clientKeyData (KubeconfigAuthentication is not yet set up for that to be dynamic)
265+
}
266+
} else {
267+
log.error("{} failed with exit code {}", command, r);
268+
}
269+
} catch (IOException | InterruptedException x) {
270+
log.error("Failed to run " + command, x);
271+
}
272+
// TODO cache tokens between calls, up to .status.expirationTimestamp
273+
// TODO a 401 is supposed to force a refresh, but KubeconfigAuthentication hard-codes AccessTokenAuthentication which does not support that
274+
// and anyway ClientBuilder only calls Authenticator.provide once per ApiClient; we would need to do it on every request
275+
} else {
276+
log.error("Unrecognized user.exec.apiVersion: {}", apiVersion);
277+
}
278+
}
217279
if (currentUser.containsKey("token")) {
218280
return (String) currentUser.get("token");
219281
}

0 commit comments

Comments
 (0)