From 4e5860915955cdec584e27a8e305cb53a8a5e87a Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Thu, 28 Jan 2021 00:19:48 -0800 Subject: [PATCH] Support wildcard IPv4 and IPv6 addresses (#550) Some tools can generate kubeconfig files which use wildcard IPv4 or IPv6 addresses. For example, using k3d with --api-server=https://0.0.0.0:6433/ would generate a kubeconfig file like this: ``` apiVersion: v1 clusters: - cluster: certificate-authority-data: (...) server: https://0.0.0.0:6433 name: k3d-k3s-default ``` Standard Kubernetes tools (like kubectl or Helm) correctly parse the 0.0.0.0 IP address and transform it 127.0.0.1; 3rd party tools like curl or wget will do the same on Unix systems. This is default behavior on Unix but not on Windows. As a result, the .NET Kubernetes client will fail to work with kubeconfig files like this and you'll get HTTP exceptions. Go has explicit workarounds for this (see https://github.com/golang/go/commit/1a0b1cca4c26d41fe7508ffdb355de78b4ea2a19), and this PR attemps to replicate these workarounds in the .NET client. --- ...ubernetesClientConfiguration.ConfigFile.cs | 17 ++++++++++++ .../KubernetesClientConfigurationTests.cs | 27 +++++++++++++++++++ .../assets/kubeconfig.wildcard-ipv4.yml | 21 +++++++++++++++ .../assets/kubeconfig.wildcard-ipv6.yml | 21 +++++++++++++++ .../assets/kubeconfig.wildcard-ipv6_2.yml | 21 +++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv4.yml create mode 100644 tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv6.yml create mode 100644 tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv6_2.yml diff --git a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs index a703dad..9737115 100644 --- a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs +++ b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs @@ -10,6 +10,7 @@ using System.Threading.Tasks; using k8s.Authentication; using k8s.Exceptions; using k8s.KubeConfigModels; +using System.Net; namespace k8s { @@ -273,6 +274,22 @@ namespace k8s throw new KubeConfigException($"Bad server host URL `{Host}` (cannot be parsed)"); } + if (IPAddress.TryParse(uri.Host, out var ipAddress)) + { + if (IPAddress.Equals(IPAddress.Any, ipAddress)) + { + var builder = new UriBuilder(Host); + builder.Host = $"{IPAddress.Loopback}"; + Host = builder.ToString(); + } + else if (IPAddress.Equals(IPAddress.IPv6Any, ipAddress)) + { + var builder = new UriBuilder(Host); + builder.Host = $"{IPAddress.IPv6Loopback}"; + Host = builder.ToString(); + } + } + if (uri.Scheme == "https") { if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthorityData)) diff --git a/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs b/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs index 5ee560c..0583f10 100644 --- a/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs +++ b/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs @@ -381,6 +381,33 @@ namespace k8s.Tests var cfg = await KubernetesClientConfiguration.BuildConfigFromConfigFileAsync(new FileInfo(path)).ConfigureAwait(false); } + [Fact] + public void ContextWithWildcardIPv4() + { + var path = Path.GetFullPath("assets/kubeconfig.wildcard-ipv4.yml"); + + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(path); + Assert.Equal("https://127.0.0.1:443/", cfg.Host); + } + + [Fact] + public void ContextWithWildcardIPv6() + { + var path = Path.GetFullPath("assets/kubeconfig.wildcard-ipv6.yml"); + + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(path); + Assert.Equal("https://[::1]:443/", cfg.Host); + } + + [Fact] + public void ContextWithWildcardIPv62() + { + var path = Path.GetFullPath("assets/kubeconfig.wildcard-ipv6.yml"); + + var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(path); + Assert.Equal("https://[::1]:443/", cfg.Host); + } + /// /// Ensures Kube config file is loaded from explicit file /// diff --git a/tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv4.yml b/tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv4.yml new file mode 100644 index 0000000..d6d6c58 --- /dev/null +++ b/tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv4.yml @@ -0,0 +1,21 @@ +# Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ +# WARNING: File includes minor fixes +--- +current-context: federal-context +apiVersion: v1 +clusters: +- cluster: + server: https://0.0.0.0:443 + name: horse-cluster +contexts: +- context: + cluster: horse-cluster + namespace: chisel-ns + user: green-user + name: federal-context +kind: Config +users: +- name: green-user + user: + password: secret + username: admin diff --git a/tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv6.yml b/tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv6.yml new file mode 100644 index 0000000..af24e98 --- /dev/null +++ b/tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv6.yml @@ -0,0 +1,21 @@ +# Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ +# WARNING: File includes minor fixes +--- +current-context: federal-context +apiVersion: v1 +clusters: +- cluster: + server: https://[::]:443 + name: horse-cluster +contexts: +- context: + cluster: horse-cluster + namespace: chisel-ns + user: green-user + name: federal-context +kind: Config +users: +- name: green-user + user: + password: secret + username: admin diff --git a/tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv6_2.yml b/tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv6_2.yml new file mode 100644 index 0000000..072a597 --- /dev/null +++ b/tests/KubernetesClient.Tests/assets/kubeconfig.wildcard-ipv6_2.yml @@ -0,0 +1,21 @@ +# Sample file based on https://kubernetes.io/docs/tasks/access-application-cluster/authenticate-across-clusters-kubeconfig/ +# WARNING: File includes minor fixes +--- +current-context: federal-context +apiVersion: v1 +clusters: +- cluster: + server: https://[0:0:0:0:0:0:0:0]:443 + name: horse-cluster +contexts: +- context: + cluster: horse-cluster + namespace: chisel-ns + user: green-user + name: federal-context +kind: Config +users: +- name: green-user + user: + password: secret + username: admin