diff --git a/src/KubernetesClient/KubeConfigModels/AuthProvider.cs b/src/KubernetesClient/KubeConfigModels/AuthProvider.cs
new file mode 100644
index 0000000..70f76cc
--- /dev/null
+++ b/src/KubernetesClient/KubeConfigModels/AuthProvider.cs
@@ -0,0 +1,24 @@
+namespace k8s.KubeConfigModels
+{
+ using System.Collections.Generic;
+ using YamlDotNet.RepresentationModel;
+ using YamlDotNet.Serialization;
+
+ ///
+ /// Contains information that describes identity information. This is use to tell the kubernetes cluster who you are.
+ ///
+ public class AuthProvider {
+ ///
+ /// Gets or sets the nickname for this auth provider.
+ ///
+ [YamlMember(Alias = "name")]
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the configuration for this auth provider
+ ///
+ [YamlMember(Alias = "config")]
+ public Dictionary Config { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/src/KubernetesClient/KubeConfigModels/UserCredentials.cs b/src/KubernetesClient/KubeConfigModels/UserCredentials.cs
index d8f794d..37073bc 100644
--- a/src/KubernetesClient/KubeConfigModels/UserCredentials.cs
+++ b/src/KubernetesClient/KubeConfigModels/UserCredentials.cs
@@ -3,82 +3,82 @@ namespace k8s.KubeConfigModels
using System.Collections.Generic;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;
-
+
///
/// Contains information that describes identity information. This is use to tell the kubernetes cluster who you are.
///
public class UserCredentials
- {
+ {
///
/// Gets or sets PEM-encoded data from a client cert file for TLS. Overrides .
///
[YamlMember(Alias = "client-certificate-data", ApplyNamingConventions = false)]
public string ClientCertificateData { get; set; }
-
+
///
/// Gets or sets the path to a client cert file for TLS.
///
[YamlMember(Alias = "client-certificate", ApplyNamingConventions = false)]
public string ClientCertificate { get; set; }
-
+
///
/// Gets or sets PEM-encoded data from a client key file for TLS. Overrides .
///
[YamlMember(Alias = "client-key-data", ApplyNamingConventions = false)]
public string ClientKeyData { get; set; }
-
+
///
/// Gets or sets the path to a client key file for TLS.
///
[YamlMember(Alias = "client-key", ApplyNamingConventions = false)]
public string ClientKey { get; set; }
-
+
///
/// Gets or sets the bearer token for authentication to the kubernetes cluster.
///
[YamlMember(Alias = "token")]
public string Token { get; set; }
-
+
///
/// Gets or sets the username to imperonate. The name matches the flag.
- ///
- [YamlMember(Alias = "as")]
- public string Impersonate { get; set; }
-
+ ///
+ [YamlMember(Alias = "as")]
+ public string Impersonate { get; set; }
+
///
/// Gets or sets the groups to imperonate.
- ///
- [YamlMember(Alias = "as-groups", ApplyNamingConventions = false)]
- public IEnumerable ImpersonateGroups { get; set; } = new string[0];
-
+ ///
+ [YamlMember(Alias = "as-groups", ApplyNamingConventions = false)]
+ public IEnumerable ImpersonateGroups { get; set; } = new string[0];
+
///
/// Gets or sets additional information for impersonated user.
- ///
- [YamlMember(Alias = "as-user-extra", ApplyNamingConventions = false)]
- public Dictionary ImpersonateUserExtra { get; set; } = new Dictionary();
-
+ ///
+ [YamlMember(Alias = "as-user-extra", ApplyNamingConventions = false)]
+ public Dictionary ImpersonateUserExtra { get; set; } = new Dictionary();
+
///
/// Gets or sets the username for basic authentication to the kubernetes cluster.
///
[YamlMember(Alias = "username")]
public string UserName { get; set; }
-
+
///
/// Gets or sets the password for basic authentication to the kubernetes cluster.
///
[YamlMember(Alias = "password")]
public string Password { get; set; }
-
+
///
/// Gets or sets custom authentication plugin for the kubernetes cluster.
///
[YamlMember(Alias = "auth-provider", ApplyNamingConventions = false)]
- public Dictionary AuthProvider { get; set; }
-
+ public AuthProvider AuthProvider { get; set; }
+
///
/// Gets or sets additional information. This is useful for extenders so that reads and writes don't clobber unknown fields.
- ///
- [YamlMember(Alias = "extensions")]
+ ///
+ [YamlMember(Alias = "extensions")]
public IDictionary Extensions { get; set; }
}
}
diff --git a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs
index ecdd85d..41afcae 100644
--- a/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs
+++ b/src/KubernetesClient/KubernetesClientConfiguration.ConfigFile.cs
@@ -28,8 +28,8 @@ namespace k8s
/// Initializes a new instance of the from config file
///
/// kube api server endpoint
- /// Explicit file path to kubeconfig. Set to null to use the default file path
- /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// Explicit file path to kubeconfig. Set to null to use the default file path
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
/// file is located. When , the paths will be considered to be relative to the current working directory.
public static KubernetesClientConfiguration BuildConfigFromConfigFile(string kubeconfigPath = null,
string currentContext = null, string masterUrl = null, bool useRelativePaths = true)
@@ -42,8 +42,8 @@ namespace k8s
///
/// Fileinfo of the kubeconfig, cannot be null
/// override the context in config file, set null if do not want to override
- /// override the kube api server endpoint, set null if do not want to override
- /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// override the kube api server endpoint, set null if do not want to override
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
/// file is located. When , the paths will be considered to be relative to the current working directory.
public static KubernetesClientConfiguration BuildConfigFromConfigFile(FileInfo kubeconfig,
string currentContext = null, string masterUrl = null, bool useRelativePaths = true)
@@ -239,6 +239,27 @@ namespace k8s
userCredentialsFound = true;
}
+ if (userDetails.UserCredentials.AuthProvider != null) {
+ if (userDetails.UserCredentials.AuthProvider.Name == "azure" &&
+ userDetails.UserCredentials.AuthProvider.Config != null &&
+ userDetails.UserCredentials.AuthProvider.Config.ContainsKey("access-token")) {
+ var config = userDetails.UserCredentials.AuthProvider.Config;
+ if (config.ContainsKey("expires-on")) {
+ var expires = DateTimeOffset.FromUnixTimeSeconds(Int32.Parse(config["expires-on"]));
+ if (DateTimeOffset.Compare(expires, DateTimeOffset.Now) <= 0) {
+ var tenantId = config["tenant-id"];
+ var clientId = config["client-id"];
+ var apiServerId = config["apiserver-id"];
+ var refresh = config["refresh-token"];
+ var newToken = RenewAzureToken(tenantId, clientId, apiServerId, refresh);
+ config["access-token"] = newToken;
+ }
+ }
+ AccessToken = config["access-token"];
+ userCredentialsFound = true;
+ }
+ }
+
if (!userCredentialsFound)
{
throw new KubeConfigException(
@@ -246,11 +267,15 @@ namespace k8s
}
}
+ public static string RenewAzureToken(string tenantId, string clientId, string apiServerId, string refresh) {
+ throw new KubeConfigException("Refresh not supported.");
+ }
+
///
/// Loads entire Kube Config from default or explicit file path
///
- /// Explicit file path to kubeconfig. Set to null to use the default file path
- /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// Explicit file path to kubeconfig. Set to null to use the default file path
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
/// file is located. When , the paths will be considered to be relative to the current working directory.
/// Instance of the class
public static async Task LoadKubeConfigAsync(string kubeconfigPath = null, bool useRelativePaths = true)
@@ -263,8 +288,8 @@ namespace k8s
///
/// Loads entire Kube Config from default or explicit file path
///
- /// Explicit file path to kubeconfig. Set to null to use the default file path
- /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// Explicit file path to kubeconfig. Set to null to use the default file path
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
/// file is located. When , the paths will be considered to be relative to the current working directory.
/// Instance of the class
public static K8SConfiguration LoadKubeConfig(string kubeconfigPath = null, bool useRelativePaths = true)
@@ -275,8 +300,8 @@ namespace k8s
//
/// Loads Kube Config
///
- /// Kube config file contents
- /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// Kube config file contents
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
/// file is located. When , the paths will be considered to be relative to the current working directory.
/// Instance of the class
public static async Task LoadKubeConfigAsync(FileInfo kubeconfig, bool useRelativePaths = true)
@@ -288,12 +313,12 @@ namespace k8s
using (var stream = kubeconfig.OpenRead())
{
- var config = await Yaml.LoadFromStreamAsync(stream);
-
- if (useRelativePaths)
- {
- config.FileName = kubeconfig.FullName;
- }
+ var config = await Yaml.LoadFromStreamAsync(stream);
+
+ if (useRelativePaths)
+ {
+ config.FileName = kubeconfig.FullName;
+ }
return config;
}
@@ -302,8 +327,8 @@ namespace k8s
///
/// Loads Kube Config
///
- /// Kube config file contents
- /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
+ /// Kube config file contents
+ /// When , the paths in the kubeconfig file will be considered to be relative to the directory in which the kubeconfig
/// file is located. When , the paths will be considered to be relative to the current working directory.
/// Instance of the class
public static K8SConfiguration LoadKubeConfig(FileInfo kubeconfig, bool useRelativePaths = true)
diff --git a/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs b/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs
index b8b1da7..400dec7 100755
--- a/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs
+++ b/tests/KubernetesClient.Tests/KubernetesClientConfigurationTests.cs
@@ -1,7 +1,7 @@
using System.IO;
-using System.Linq;
+using System.Linq;
using k8s.Exceptions;
-using k8s.KubeConfigModels;
+using k8s.KubeConfigModels;
using Xunit;
namespace k8s.Tests
@@ -272,8 +272,8 @@ namespace k8s.Tests
public void DeletedConfigurationFile()
{
var assetFileInfo = new FileInfo("assets/kubeconfig.yml");
- var tempFileInfo = new FileInfo(Path.GetTempFileName());
-
+ var tempFileInfo = new FileInfo(Path.GetTempFileName());
+
File.Copy(assetFileInfo.FullName, tempFileInfo.FullName, /* overwrite: */ true);
KubernetesClientConfiguration config;
@@ -321,125 +321,125 @@ namespace k8s.Tests
{
var filePath = "assets/kubeconfig.as-user-extra.yml";
- var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(filePath, null, null, useRelativePaths: false);
+ var cfg = KubernetesClientConfiguration.BuildConfigFromConfigFile(filePath, null, null, useRelativePaths: false);
Assert.NotNull(cfg.Host);
- }
-
+ }
+
///
/// Ensures Kube config file is loaded from explicit file
- ///
- [Fact]
- public void LoadKubeConfigExplicitFilePath()
- {
- var txt = File.ReadAllText("assets/kubeconfig.yml");
- var expectedCfg = Yaml.LoadFromString(txt);
-
- var cfg = KubernetesClientConfiguration.LoadKubeConfig("assets/kubeconfig.yml");
-
- Assert.NotNull(cfg);
- AssertConfigEqual(expectedCfg, cfg);
- }
-
- [Fact]
- public void LoadKubeConfigFileInfo()
- {
- var filePath = "assets/kubeconfig.yml";
- var txt = File.ReadAllText(filePath);
- var expectedCfg = Yaml.LoadFromString(txt);
-
- var fileInfo = new FileInfo(filePath);
- var cfg = KubernetesClientConfiguration.LoadKubeConfig(fileInfo);
-
- Assert.NotNull(cfg);
- AssertConfigEqual(expectedCfg, cfg);
- }
-
- [Fact]
- public void LoadKubeConfigStream()
- {
- var filePath = "assets/kubeconfig.yml";
- var txt = File.ReadAllText(filePath);
- var expectedCfg = Yaml.LoadFromString(txt);
-
- var fileInfo = new FileInfo(filePath);
- K8SConfiguration cfg;
- using (var stream = fileInfo.OpenRead())
- {
- cfg = KubernetesClientConfiguration.LoadKubeConfig(stream);
- }
-
- Assert.NotNull(cfg);
- AssertConfigEqual(expectedCfg, cfg);
- }
-
- private void AssertConfigEqual(K8SConfiguration expected, K8SConfiguration actual)
- {
- Assert.Equal(expected.ApiVersion, actual.ApiVersion);
- Assert.Equal(expected.CurrentContext, actual.CurrentContext);
-
- foreach (var expectedContext in expected.Contexts)
- {
- // Will throw exception if not found
- var actualContext = actual.Contexts.First(c => c.Name.Equals(expectedContext.Name));
- AssertContextEqual(expectedContext, actualContext);
- }
-
- foreach (var expectedCluster in expected.Clusters)
- {
- // Will throw exception if not found
- var actualCluster = actual.Clusters.First(c => c.Name.Equals(expectedCluster.Name));
- AssertClusterEqual(expectedCluster, actualCluster);
- }
-
- foreach (var expectedUser in expected.Users)
- {
- // Will throw exception if not found
- var actualUser = actual.Users.First(u => u.Name.Equals(expectedUser.Name));
- AssertUserEqual(expectedUser, actualUser);
- }
- }
-
- private void AssertContextEqual(Context expected, Context actual)
- {
- Assert.Equal(expected.Name, actual.Name);
- Assert.Equal(expected.Namespace, actual.Namespace);
- Assert.Equal(expected.ContextDetails.Cluster, actual.ContextDetails.Cluster);
- Assert.Equal(expected.ContextDetails.User, actual.ContextDetails.User);
- Assert.Equal(expected.ContextDetails.Namespace, actual.ContextDetails.Namespace);
- }
-
- private void AssertClusterEqual(Cluster expected, Cluster actual)
- {
- Assert.Equal(expected.Name, actual.Name);
- Assert.Equal(expected.ClusterEndpoint.CertificateAuthority, actual.ClusterEndpoint.CertificateAuthority);
- Assert.Equal(expected.ClusterEndpoint.CertificateAuthorityData, actual.ClusterEndpoint.CertificateAuthorityData);
- Assert.Equal(expected.ClusterEndpoint.Server, actual.ClusterEndpoint.Server);
- Assert.Equal(expected.ClusterEndpoint.SkipTlsVerify, actual.ClusterEndpoint.SkipTlsVerify);
- }
-
- private void AssertUserEqual(User expected, User actual)
- {
- Assert.Equal(expected.Name, actual.Name);
-
- var expectedCreds = expected.UserCredentials;
- var actualCreds = actual.UserCredentials;
-
- Assert.Equal(expectedCreds.ClientCertificateData, actualCreds.ClientCertificateData);
- Assert.Equal(expectedCreds.ClientCertificate, actualCreds.ClientCertificate);
- Assert.Equal(expectedCreds.ClientKeyData, actualCreds.ClientKeyData);
- Assert.Equal(expectedCreds.ClientKey, actualCreds.ClientKey);
- Assert.Equal(expectedCreds.Token, actualCreds.Token);
- Assert.Equal(expectedCreds.Impersonate, actualCreds.Impersonate);
- Assert.Equal(expectedCreds.UserName, actualCreds.UserName);
- Assert.Equal(expectedCreds.Password, actualCreds.Password);
-
- Assert.True(expectedCreds.ImpersonateGroups.All(x => actualCreds.ImpersonateGroups.Contains(x)));
- Assert.True(expectedCreds.ImpersonateUserExtra.All(x => actualCreds.ImpersonateUserExtra.Contains(x)));
-
- if (expectedCreds.AuthProvider != null)
- {
- Assert.True(expectedCreds.AuthProvider.All(x => actualCreds.AuthProvider.Contains(x)));
- }
+ ///
+ [Fact]
+ public void LoadKubeConfigExplicitFilePath()
+ {
+ var txt = File.ReadAllText("assets/kubeconfig.yml");
+ var expectedCfg = Yaml.LoadFromString(txt);
+
+ var cfg = KubernetesClientConfiguration.LoadKubeConfig("assets/kubeconfig.yml");
+
+ Assert.NotNull(cfg);
+ AssertConfigEqual(expectedCfg, cfg);
+ }
+
+ [Fact]
+ public void LoadKubeConfigFileInfo()
+ {
+ var filePath = "assets/kubeconfig.yml";
+ var txt = File.ReadAllText(filePath);
+ var expectedCfg = Yaml.LoadFromString(txt);
+
+ var fileInfo = new FileInfo(filePath);
+ var cfg = KubernetesClientConfiguration.LoadKubeConfig(fileInfo);
+
+ Assert.NotNull(cfg);
+ AssertConfigEqual(expectedCfg, cfg);
+ }
+
+ [Fact]
+ public void LoadKubeConfigStream()
+ {
+ var filePath = "assets/kubeconfig.yml";
+ var txt = File.ReadAllText(filePath);
+ var expectedCfg = Yaml.LoadFromString(txt);
+
+ var fileInfo = new FileInfo(filePath);
+ K8SConfiguration cfg;
+ using (var stream = fileInfo.OpenRead())
+ {
+ cfg = KubernetesClientConfiguration.LoadKubeConfig(stream);
+ }
+
+ Assert.NotNull(cfg);
+ AssertConfigEqual(expectedCfg, cfg);
+ }
+
+ private void AssertConfigEqual(K8SConfiguration expected, K8SConfiguration actual)
+ {
+ Assert.Equal(expected.ApiVersion, actual.ApiVersion);
+ Assert.Equal(expected.CurrentContext, actual.CurrentContext);
+
+ foreach (var expectedContext in expected.Contexts)
+ {
+ // Will throw exception if not found
+ var actualContext = actual.Contexts.First(c => c.Name.Equals(expectedContext.Name));
+ AssertContextEqual(expectedContext, actualContext);
+ }
+
+ foreach (var expectedCluster in expected.Clusters)
+ {
+ // Will throw exception if not found
+ var actualCluster = actual.Clusters.First(c => c.Name.Equals(expectedCluster.Name));
+ AssertClusterEqual(expectedCluster, actualCluster);
+ }
+
+ foreach (var expectedUser in expected.Users)
+ {
+ // Will throw exception if not found
+ var actualUser = actual.Users.First(u => u.Name.Equals(expectedUser.Name));
+ AssertUserEqual(expectedUser, actualUser);
+ }
+ }
+
+ private void AssertContextEqual(Context expected, Context actual)
+ {
+ Assert.Equal(expected.Name, actual.Name);
+ Assert.Equal(expected.Namespace, actual.Namespace);
+ Assert.Equal(expected.ContextDetails.Cluster, actual.ContextDetails.Cluster);
+ Assert.Equal(expected.ContextDetails.User, actual.ContextDetails.User);
+ Assert.Equal(expected.ContextDetails.Namespace, actual.ContextDetails.Namespace);
+ }
+
+ private void AssertClusterEqual(Cluster expected, Cluster actual)
+ {
+ Assert.Equal(expected.Name, actual.Name);
+ Assert.Equal(expected.ClusterEndpoint.CertificateAuthority, actual.ClusterEndpoint.CertificateAuthority);
+ Assert.Equal(expected.ClusterEndpoint.CertificateAuthorityData, actual.ClusterEndpoint.CertificateAuthorityData);
+ Assert.Equal(expected.ClusterEndpoint.Server, actual.ClusterEndpoint.Server);
+ Assert.Equal(expected.ClusterEndpoint.SkipTlsVerify, actual.ClusterEndpoint.SkipTlsVerify);
+ }
+
+ private void AssertUserEqual(User expected, User actual)
+ {
+ Assert.Equal(expected.Name, actual.Name);
+
+ var expectedCreds = expected.UserCredentials;
+ var actualCreds = actual.UserCredentials;
+
+ Assert.Equal(expectedCreds.ClientCertificateData, actualCreds.ClientCertificateData);
+ Assert.Equal(expectedCreds.ClientCertificate, actualCreds.ClientCertificate);
+ Assert.Equal(expectedCreds.ClientKeyData, actualCreds.ClientKeyData);
+ Assert.Equal(expectedCreds.ClientKey, actualCreds.ClientKey);
+ Assert.Equal(expectedCreds.Token, actualCreds.Token);
+ Assert.Equal(expectedCreds.Impersonate, actualCreds.Impersonate);
+ Assert.Equal(expectedCreds.UserName, actualCreds.UserName);
+ Assert.Equal(expectedCreds.Password, actualCreds.Password);
+
+ Assert.True(expectedCreds.ImpersonateGroups.All(x => actualCreds.ImpersonateGroups.Contains(x)));
+ Assert.True(expectedCreds.ImpersonateUserExtra.All(x => actualCreds.ImpersonateUserExtra.Contains(x)));
+
+ if (expectedCreds.AuthProvider != null)
+ {
+ Assert.True(expectedCreds.AuthProvider.Config.All(x => actualCreds.AuthProvider.Config.Contains(x)));
+ }
}
}
}