diff --git a/util/src/main/java/io/kubernetes/client/util/ClientBuilder.java b/util/src/main/java/io/kubernetes/client/util/ClientBuilder.java index 28c737a662..ae0bfb4011 100644 --- a/util/src/main/java/io/kubernetes/client/util/ClientBuilder.java +++ b/util/src/main/java/io/kubernetes/client/util/ClientBuilder.java @@ -64,6 +64,7 @@ public class ClientBuilder { private boolean verifyingSsl = true; private Authentication authentication; private String keyStorePassphrase; + private String tlsServerName; // defaulting client protocols to HTTP1.1 and HTTP 2 private List protocols = Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1); // default to unlimited read timeout @@ -312,6 +313,11 @@ public static ClientBuilder kubeconfig(KubeConfig config, Duration tokenRefreshP } builder.setVerifyingSsl(config.verifySSL()); + String tlsServerName = config.getTlsServerName(); + if (tlsServerName != null && !tlsServerName.isEmpty()) { + builder.setTlsServerName(tlsServerName); + } + builder.setBasePath(server); builder.setAuthentication(new KubeconfigAuthentication(config, tokenRefreshPeriod)); return builder; @@ -436,6 +442,15 @@ public ClientBuilder setKeyStorePassphrase(String keyStorePassphrase) { return this; } + public String getTlsServerName() { + return tlsServerName; + } + + public ClientBuilder setTlsServerName(String tlsServerName) { + this.tlsServerName = tlsServerName; + return this; + } + public ApiClient getApiClient() { return this.apiClient; } @@ -466,6 +481,10 @@ public ApiClient build() { client.setVerifyingSsl(verifyingSsl); + if (tlsServerName != null && !tlsServerName.isEmpty()) { + client.setTlsServerName(tlsServerName); + } + if (authentication != null) { if (StringUtils.isNotEmpty(keyStorePassphrase)) { if (authentication instanceof KubeconfigAuthentication) { diff --git a/util/src/main/java/io/kubernetes/client/util/KubeConfig.java b/util/src/main/java/io/kubernetes/client/util/KubeConfig.java index ba4fb2a995..18f64f251b 100644 --- a/util/src/main/java/io/kubernetes/client/util/KubeConfig.java +++ b/util/src/main/java/io/kubernetes/client/util/KubeConfig.java @@ -176,6 +176,10 @@ public String getCertificateAuthorityFile() { return getData(currentCluster, "certificate-authority"); } + public String getTlsServerName() { + return getData(currentCluster, "tls-server-name"); + } + public String getClientCertificateFile() { return getData(currentUser, "client-certificate"); } diff --git a/util/src/test/java/io/kubernetes/client/util/ClientBuilderTest.java b/util/src/test/java/io/kubernetes/client/util/ClientBuilderTest.java index cfc5f054d9..bbecb6068e 100644 --- a/util/src/test/java/io/kubernetes/client/util/ClientBuilderTest.java +++ b/util/src/test/java/io/kubernetes/client/util/ClientBuilderTest.java @@ -48,6 +48,8 @@ class ClientBuilderTest { Resources.getResource("kubeconfig-https").getPath(); private static final String KUBECONFIG_HTTPS_X509_FILE_PATH = Resources.getResource("kubeconfig-https-x509").getPath(); + private static final String KUBECONFIG_TLS_SERVER_NAME_FILE_PATH = + Resources.getResource("kubeconfig-tls-server-name").getPath(); private static final String SSL_CA_CERT_PATH = new File(Resources.getResource("ca-cert.pem").getPath()).toString(); private static final String INVALID_SSL_CA_CERT_PATH = @@ -321,4 +323,22 @@ void detectsServerNotSet() { ClientBuilder.kubeconfig(kubeConfigWithoutServer); }).hasMessage("No server in kubeconfig").isInstanceOf(IllegalArgumentException.class); } + + @Test + void tlsServerNameSetFromKubeConfig() throws IOException { + ApiClient client = + ClientBuilder.kubeconfig( + KubeConfig.loadKubeConfig(new FileReader(KUBECONFIG_TLS_SERVER_NAME_FILE_PATH))) + .build(); + assertThat(client.getTlsServerName()).isEqualTo("my-cluster.example.com"); + } + + @Test + void tlsServerNameNotSetWhenNotInKubeConfig() throws IOException { + ApiClient client = + ClientBuilder.kubeconfig( + KubeConfig.loadKubeConfig(new FileReader(KUBECONFIG_HTTPS_FILE_PATH))) + .build(); + assertThat(client.getTlsServerName()).isNull(); + } } diff --git a/util/src/test/java/io/kubernetes/client/util/KubeConfigTest.java b/util/src/test/java/io/kubernetes/client/util/KubeConfigTest.java index d855283de0..6ac8ca57d1 100644 --- a/util/src/test/java/io/kubernetes/client/util/KubeConfigTest.java +++ b/util/src/test/java/io/kubernetes/client/util/KubeConfigTest.java @@ -425,4 +425,35 @@ void execCredentialsCertificate() { assertThat(kc.getCredentials()).containsEntry(KubeConfig.CRED_CLIENT_KEY_DATA_KEY, "key"); assertThat(kc.getCredentials().get(KubeConfig.CRED_TOKEN_KEY)).isNull(); } + + @Test + void tlsServerName() { + String configWithTlsServerName = + "apiVersion: v1\n" + + "clusters:\n" + + "- cluster:\n" + + " server: https://192.168.1.1:6443\n" + + " tls-server-name: my-cluster.example.com\n" + + " certificate-authority-data: dGVzdAo=\n" + + " name: test-cluster\n" + + "users:\n" + + "- user:\n" + + " token: test-token\n" + + " name: test-user\n" + + "contexts:\n" + + "- context:\n" + + " cluster: test-cluster\n" + + " user: test-user\n" + + " name: test-context\n" + + "current-context: test-context\n"; + + KubeConfig config = KubeConfig.loadKubeConfig(new StringReader(configWithTlsServerName)); + assertThat("my-cluster.example.com").isEqualTo(config.getTlsServerName()); + } + + @Test + void tlsServerNameNotPresent() { + KubeConfig config = KubeConfig.loadKubeConfig(new StringReader(KUBECONFIG_TOKEN)); + assertThat(config.getTlsServerName()).isNull(); + } } diff --git a/util/src/test/resources/kubeconfig-tls-server-name b/util/src/test/resources/kubeconfig-tls-server-name new file mode 100644 index 0000000000..41493a063f --- /dev/null +++ b/util/src/test/resources/kubeconfig-tls-server-name @@ -0,0 +1,17 @@ +apiVersion: v1 +clusters: + - cluster: + server: https://192.168.1.1:6443 + tls-server-name: my-cluster.example.com + certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJkekNDQVIyZ0F3SUJBZ0lCQURBS0JnZ3Foa2pPUFFRREFqQWpNU0V3SHdZRFZRUUREQmhyTTNNdGMyVnkKZG1WeUxXTmhRREUzTXpNMU1qYzFPVGN3SGhjTk1qUXhNREkzTVRnek1ETTNXaGNOTXpReE1ESTFNVGd6TURNMwpXakFqTVNFd0h3WURWUVFEREJock0zTXRjMlZ5ZG1WeUxXTmhRREUzTXpNMU1qYzFPVGN3V1RBVEJnY3Foa2pPClBRSUJCZ2dxaGtqT1BRTUJCd05DQUFUMmY5dzdYZEJLRktDN2ptQUxYaDFlNVgyWjNYL0h5K2JYR0MxV1VoeHUKS3BZUUJ5Q0oxcU5RUjhQWHhOWEdvd3BJUFp0ekU0T2NQdjFRUlJyd0hvNkZvMEl3UURBT0JnTlZIUThCQWY4RQpCQU1DQXFRd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlZIUTRFRmdRVXdYam5rdWRSek55T1N2VmY2Mm1PCnFqc2FxREF3Q2dZSUtvWkl6ajBFQXdJRFNBQXdSUUlnRGRYelNuYTRnS2x6akJ2MllLVDJqM0VlSzY1WndPa2cKNGMxaG1nK29CVHdDSVFEdTBGR2NjRVE3OXE2U0pGTkF1bUhsd0JaY3lmeE5sOWhDb3hSRUdWVy93Zz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K + name: test-cluster +users: + - user: + token: test-token + name: test-user +contexts: + - context: + cluster: test-cluster + user: test-user + name: test-context +current-context: test-context