/// <summary> /// Tries to get the full path to a file referenced from the Kubernetes configuration. /// </summary> /// <param name="configuration"> /// The Kubernetes configuration. /// </param> /// <param name="path"> /// The path to resolve. /// </param> /// <returns> /// When possible a fully qualified path to the file. /// </returns> /// <remarks> /// For example, if the configuration file is at "C:\Users\me\kube.config" and path is "ca.crt", /// this will return "C:\Users\me\ca.crt". Similarly, if path is "D:\ca.cart", this will return /// "D:\ca.crt". /// </remarks> private static string GetFullPath(IK8SConfiguration configuration, string path) { // If we don't have a file name, if (string.IsNullOrWhiteSpace(configuration.FileName) || Path.IsPathRooted(path)) { return(path); } else { return(Path.Combine(Path.GetDirectoryName(configuration.FileName), path)); } }
private void SetClusterDetails(IK8SConfiguration k8SConfig, Context activeContext) { var clusterDetails = k8SConfig.Clusters.FirstOrDefault(c => c.Name.Equals(activeContext.ContextDetails.Cluster, StringComparison.OrdinalIgnoreCase)); if (clusterDetails?.ClusterEndpoint == null) { throw new KubeConfigException($"Cluster not found for context {activeContext} in kubeconfig"); } if (string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.Server)) { throw new KubeConfigException($"Server not found for current-context {activeContext} in kubeconfig"); } Host = clusterDetails.ClusterEndpoint.Server; SkipTlsVerify = clusterDetails.ClusterEndpoint.SkipTlsVerify; try { var uri = new Uri(Host); if (uri.Scheme == "https") { // check certificate for https if (!clusterDetails.ClusterEndpoint.SkipTlsVerify && string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.CertificateAuthorityData) && string.IsNullOrWhiteSpace(clusterDetails.ClusterEndpoint.CertificateAuthority)) { throw new KubeConfigException( $"neither certificate-authority-data nor certificate-authority not found for current-context :{activeContext} in kubeconfig"); } if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthorityData)) { var data = clusterDetails.ClusterEndpoint.CertificateAuthorityData; SslCaCert = new X509Certificate2(Convert.FromBase64String(data)); } else if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthority)) { SslCaCert = new X509Certificate2(GetFullPath(k8SConfig, clusterDetails.ClusterEndpoint.CertificateAuthority)); } } } catch (UriFormatException e) { throw new KubeConfigException("Bad Server host url", e); } }
/// <summary> /// Validates and Intializes Client Configuration /// </summary> /// <param name="k8SConfig">Kubernetes Configuration</param> /// <param name="currentContext">Current Context</param> private void InitializeContext(IK8SConfiguration k8SConfig, string currentContext) { // current context var activeContext = k8SConfig.Contexts.FirstOrDefault( c => c.Name.Equals(currentContext, StringComparison.OrdinalIgnoreCase)); if (activeContext == null) { throw new KubeConfigException($"CurrentContext: {currentContext} not found in contexts in kubeconfig"); } CurrentContext = activeContext.Name; // cluster SetClusterDetails(k8SConfig, activeContext); // user SetUserDetails(k8SConfig, activeContext); // namespace Namespace = activeContext.Namespace; }
/// <summary> /// Initializes a new instance of the <see cref="Kubernetes" /> class. /// </summary> /// <param name='k8SConfiguration'> /// The configuration file for connection to Kubernetes /// </param> public Kubernetes(IK8SConfiguration k8SConfiguration) { var config = KubernetesClientConfiguration.BuildConfigFromConfigObject(k8SConfiguration); InitKubernetes(config); }
/// <summary> /// Initializes a new instance of <see cref="KubernetesClientConfiguration"/> from pre-loaded config object. /// </summary> /// <param name="k8sConfig">A <see cref="K8SConfiguration"/>, for example loaded from <see cref="LoadKubeConfigAsync(string, bool)" /></param> /// <param name="currentContext">Override the current context in config, set null if do not want to override</param> /// <param name="masterUrl">Override the Kubernetes API server endpoint, set null if do not want to override</param> public static KubernetesClientConfiguration BuildConfigFromConfigObject(IK8SConfiguration k8SConfig, string currentContext = null, string masterUrl = null) => GetKubernetesClientConfiguration(currentContext, masterUrl, k8SConfig);
private void SetUserDetails(IK8SConfiguration k8SConfig, Context activeContext) { if (string.IsNullOrWhiteSpace(activeContext.ContextDetails.User)) { return; } var userDetails = k8SConfig.Users.FirstOrDefault(c => c.Name.Equals(activeContext.ContextDetails.User, StringComparison.OrdinalIgnoreCase)); if (userDetails == null) { throw new KubeConfigException("User not found for context {activeContext.Name} in kubeconfig"); } if (userDetails.UserCredentials == null) { throw new KubeConfigException($"User credentials not found for user: {userDetails.Name} in kubeconfig"); } var userCredentialsFound = false; // Basic and bearer tokens are mutually exclusive if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.Token)) { AccessToken = userDetails.UserCredentials.Token; userCredentialsFound = true; } else if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.UserName) && !string.IsNullOrWhiteSpace(userDetails.UserCredentials.Password)) { Username = userDetails.UserCredentials.UserName; Password = userDetails.UserCredentials.Password; userCredentialsFound = true; } // Token and cert based auth can co-exist if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientCertificateData) && !string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientKeyData)) { ClientCertificateData = userDetails.UserCredentials.ClientCertificateData; ClientCertificateKeyData = userDetails.UserCredentials.ClientKeyData; userCredentialsFound = true; } if (!string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientCertificate) && !string.IsNullOrWhiteSpace(userDetails.UserCredentials.ClientKey)) { ClientCertificateFilePath = GetFullPath(k8SConfig, userDetails.UserCredentials.ClientCertificate); ClientKeyFilePath = GetFullPath(k8SConfig, userDetails.UserCredentials.ClientKey); 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 expiresOn = Int32.Parse(config["expires-on"]); DateTimeOffset expires; #if NET452 var epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); expires = epoch.AddSeconds(expiresOn); #else expires = DateTimeOffset.FromUnixTimeSeconds(expiresOn); #endif 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( $"User: {userDetails.Name} does not have appropriate auth credentials in kubeconfig"); } }
private static KubernetesClientConfiguration GetKubernetesClientConfiguration(string currentContext, string masterUrl, IK8SConfiguration k8SConfig) { var k8SConfiguration = new KubernetesClientConfiguration(); currentContext = currentContext ?? k8SConfig.CurrentContext; // only init context if context if set if (currentContext != null) { k8SConfiguration.InitializeContext(k8SConfig, currentContext); } if (!string.IsNullOrWhiteSpace(masterUrl)) { k8SConfiguration.Host = masterUrl; } if (string.IsNullOrWhiteSpace(k8SConfiguration.Host)) { throw new KubeConfigException("Cannot infer server host url either from context or masterUrl"); } return(k8SConfiguration); }