Skip to content

Commit

Permalink
update token in file listed in KUBECONFIG env var (fabric8io#6240)
Browse files Browse the repository at this point in the history
Signed-off-by: Andre Dietisheim <[email protected]>
  • Loading branch information
adietish committed Aug 22, 2024
1 parent 7dc77ee commit dacff5a
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ public class Config {
public static final String KUBERNETES_NAMESPACE_PATH = "/var/run/secrets/kubernetes.io/serviceaccount/namespace";
public static final String KUBERNETES_NAMESPACE_FILE = "kubenamespace";
public static final String KUBERNETES_NAMESPACE_SYSTEM_PROPERTY = "kubernetes.namespace";
@Deprecated
public static final String KUBERNETES_KUBECONFIG_FILE = "kubeconfig";
public static final String KUBERNETES_KUBECONFIG_FILES = "kubeconfig";
public static final String KUBERNETES_SERVICE_HOST_PROPERTY = "KUBERNETES_SERVICE_HOST";
public static final String KUBERNETES_SERVICE_PORT_PROPERTY = "KUBERNETES_SERVICE_PORT";
public static final String KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH = "/var/run/secrets/kubernetes.io/serviceaccount/token";
Expand Down Expand Up @@ -854,40 +856,41 @@ private static boolean tryKubeConfig(Config config, String context) {
if (!Utils.getSystemPropertyOrEnvVar(KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, true)) {
return false;
}
List<String> kubeConfigFilenames = Arrays.asList(getKubeconfigFilenames());
if (kubeConfigFilenames.isEmpty()) {
String[] kubeConfigFilenames = getKubeconfigFilenames();
if (kubeConfigFilenames == null
|| kubeConfigFilenames.length == 0) {
return false;
}
List<File> allKubeConfigFiles = kubeConfigFilenames.stream()
.map(File::new)
.collect(Collectors.toList());
File mainKubeConfig = allKubeConfigFiles.get(0);
io.fabric8.kubernetes.api.model.Config kubeConfig = createKubeconfig(mainKubeConfig);
List<File> allFiles = Arrays.stream(kubeConfigFilenames)
.map(File::new)
.collect(Collectors.toList());
File mainFile = allFiles.get(0);
io.fabric8.kubernetes.api.model.Config kubeConfig = createKubeconfig(mainFile);
if (kubeConfig == null) {
return false;
}
config.file = mainKubeConfig;
config.files = allKubeConfigFiles;
config.file = mainFile;
config.files = allFiles;

List<File> additionalConfigs = config.files.subList(1, allKubeConfigFiles.size());
List<File> additionalConfigs = config.files.subList(1, allFiles.size());
addAdditionalConfigs(kubeConfig, additionalConfigs);

return loadFromKubeconfig(config, context, mainKubeConfig);
return loadFromKubeconfig(config, context, kubeConfig);
}

private static void addAdditionalConfigs(io.fabric8.kubernetes.api.model.Config kubeConfig, List<File> files) {
if (files == null
|| files.isEmpty()) {
|| files.isEmpty()) {
return;
}
files.stream()
.map(Config::createKubeconfig)
.filter(Objects::nonNull)
.forEach(additionalConfig -> {
addTo(additionalConfig.getContexts(), kubeConfig::getContexts, kubeConfig::setContexts);
addTo(additionalConfig.getClusters(), kubeConfig::getClusters, kubeConfig::setClusters);
addTo(additionalConfig.getUsers(), kubeConfig::getUsers, kubeConfig::setUsers);
});
.map(Config::createKubeconfig)
.filter(Objects::nonNull)
.forEach(additionalConfig -> {
addTo(additionalConfig.getContexts(), kubeConfig::getContexts, kubeConfig::setContexts);
addTo(additionalConfig.getClusters(), kubeConfig::getClusters, kubeConfig::setClusters);
addTo(additionalConfig.getUsers(), kubeConfig::getUsers, kubeConfig::setUsers);
});
}

private static io.fabric8.kubernetes.api.model.Config createKubeconfig(File file) {
Expand Down Expand Up @@ -934,11 +937,13 @@ public static String getKubeconfigFilename() {

public static String[] getKubeconfigFilenames() {
String[] fileNames = null;
String fileName = Utils.getSystemPropertyOrEnvVar(KUBERNETES_KUBECONFIG_FILE);

fileNames = fileName.split(File.pathSeparator);
if (fileNames.length == 0) {
fileNames = new String[] { new File(getHomeDir(), ".kube" + File.separator + "config").toString() };
String fileName = Utils.getSystemPropertyOrEnvVar(KUBERNETES_KUBECONFIG_FILES);
if (fileName != null
&& !fileName.isEmpty()) {
fileNames = fileName.split(File.pathSeparator);
if (fileNames.length == 0) {
fileNames = new String[]{new File(getHomeDir(), ".kube" + File.separator + "config").toString()};
}
}
return fileNames;
}
Expand All @@ -954,21 +959,20 @@ private static String getKubeconfigContents(File kubeConfigFile) {
return kubeconfigContents;
}

private static boolean loadFromKubeconfig(Config config, String context, File kubeConfigFile) {
String contents = getKubeconfigContents(kubeConfigFile);
if (contents == null) {
return false;
}
return loadFromKubeconfig(config, context, contents);
}

// Note: kubeconfigPath is optional
// It is only used to rewrite relative tls asset paths inside kubeconfig when a file is passed, and in the case that
// the kubeconfig references some assets via relative paths.
private static boolean loadFromKubeconfig(Config config, String context, String kubeconfigContents) {
if (kubeconfigContents != null && !kubeconfigContents.isEmpty()) {
return loadFromKubeconfig(config, context, KubeConfigUtils.parseConfigFromString(kubeconfigContents));
} else {
return false;
}
}

private static boolean loadFromKubeconfig(Config config, String context, io.fabric8.kubernetes.api.model.Config kubeConfig) {
try {
if (kubeconfigContents != null && !kubeconfigContents.isEmpty()) {
io.fabric8.kubernetes.api.model.Config kubeConfig = KubeConfigUtils.parseConfigFromString(kubeconfigContents);
if (kubeConfig != null) {
mergeKubeConfigContents(config, context, kubeConfig);
return true;
}
Expand Down Expand Up @@ -1144,6 +1148,7 @@ protected static String getCommandWithFullyQualifiedPath(String command, String

private static Context setCurrentContext(String context, Config config, io.fabric8.kubernetes.api.model.Config kubeConfig) {
if (context != null) {
// override existing current-context
kubeConfig.setCurrentContext(context);
}
Context currentContext = null;
Expand Down Expand Up @@ -1734,17 +1739,73 @@ public NamedContext getCurrentContext() {
public void setCurrentContext(NamedContext context) {
this.currentContext = context;
}

/**
*
* Returns the path to the file that this configuration was loaded from. Returns {@code null} if no file was used.
* @deprecated use {@link #getFiles} instead.
*
* @return the path to the kubeConfig file
* @return the kubeConfig file
*/
@Deprecated
public File getFile() {
return file;
}

/**
* Returns the kube config files that are used to configure this client.
* Returns the files that are listed in the KUBERNETES_KUBECONFIG_FILES env or system variables.
* Returns the default kube config file if it's not set'.
*
* @return
*/
public List<File> getFiles() {
return files;
}

public KubeConfigFile getFile(String username) {
if (username == null
|| username.isEmpty()) {
return null;
}
return Arrays.stream(getKubeconfigFilenames())
.map(filename -> {
try {
return new KubeConfigFile(file, KubeConfigUtils.parseConfig(file));
} catch (IOException e) {
return null;
}
})
.filter(entry -> entry != null
&& entry.getConfig() != null
&& hasAuthInfo(username, entry.getConfig())
)
.findFirst()
.orElse(null);
}

private boolean hasAuthInfo(String username, io.fabric8.kubernetes.api.model.Config kubeConfig) {
return kubeConfig.getUsers().stream()
.anyMatch(namedAuthInfo -> username.equals(namedAuthInfo.getUser().getUsername()));
}

public static class KubeConfigFile {
private final File file;
private final io.fabric8.kubernetes.api.model.Config config;

private KubeConfigFile(File file, io.fabric8.kubernetes.api.model.Config config) {
this.file = file;
this.config = config;
}

public File getFile() {
return file;
}

public io.fabric8.kubernetes.api.model.Config getConfig() {
return config;
}
}

@JsonIgnore
public Readiness getReadiness() {
return Readiness.getInstance();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import io.fabric8.kubernetes.api.model.AuthProviderConfig;
import io.fabric8.kubernetes.api.model.NamedAuthInfo;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.Config.KubeConfigFile;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.http.HttpClient;
import io.fabric8.kubernetes.client.http.HttpRequest;
Expand Down Expand Up @@ -202,7 +201,7 @@ private static void persistOAuthTokenToFile(Config currentConfig, String token,
if (currentConfig.getFile() != null && currentConfig.getCurrentContext() != null) {
try {
final String userName = currentConfig.getCurrentContext().getContext().getUser();
KubeConfigFile kubeConfigFile = currentConfig.getFile(userName);
Config.KubeConfigFile kubeConfigFile = currentConfig.getFile(userName);
if (kubeConfigFile == null) {
LOGGER.warn("oidc: failure while persisting new tokens into KUBECONFIG: file for user {} not found", userName);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1230,4 +1230,29 @@ void givenEmptyKubeConfig_whenConfigCreated_thenShouldNotProduceNPE() throws URI
System.clearProperty("kubeconfig");
}
}

@Test
void givenKubeConfigWithSeveralFiles_whenAutoconfigured_thenShouldUseCurrentContextSetInFirstFile() throws URISyntaxException {
try {
// Given
System.setProperty(Config.KUBERNETES_KUBECONFIG_FILES,
// provides contexts, clusters, users
new File(Objects.requireNonNull(getClass().getResource(
"/test-kubeconfig-onlycurrentcontext")).toURI()).getAbsolutePath() + File.pathSeparator +
// only has current-context
new File(Objects.requireNonNull(getClass().getResource(
"/test-kubeconfig")).toURI()).getAbsolutePath()
);

// When
Config config = Config.autoConfigure(null); // dont override current context

// Then
assertThat(config.getCurrentContext()).isNotNull();
assertThat(config.getCurrentContext().getName()).isEqualTo("production/172-28-128-4:8443/root");
} finally {
System.clearProperty(Config.KUBERNETES_KUBECONFIG_FILES);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: Config
clusters: null
contexts: null
current-context: production/172-28-128-4:8443/root
preferences: {}
users: null

0 comments on commit dacff5a

Please sign in to comment.