-
Notifications
You must be signed in to change notification settings - Fork 311
Pass cluster info to exec credential plugins (provideClusterInfo) #1808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
3749bdf
5e2729f
615741e
cce84f7
df9c643
4db8289
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| using System.Net; | ||
| using System.Runtime.InteropServices; | ||
| using System.Text; | ||
| using System.Text.Json.Nodes; | ||
|
|
||
| namespace k8s | ||
| { | ||
|
|
@@ -306,15 +307,16 @@ private void SetClusterDetails(K8SConfiguration k8SConfig, Context activeContext | |
| { | ||
| if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthorityData)) | ||
| { | ||
| var data = clusterDetails.ClusterEndpoint.CertificateAuthorityData; | ||
| var pemText = Encoding.UTF8.GetString(Convert.FromBase64String(data)); | ||
| CaData = clusterDetails.ClusterEndpoint.CertificateAuthorityData; | ||
| var pemText = Encoding.UTF8.GetString(Convert.FromBase64String(CaData)); | ||
| SslCaCerts = CertUtils.LoadFromPemText(pemText); | ||
| } | ||
| else if (!string.IsNullOrEmpty(clusterDetails.ClusterEndpoint.CertificateAuthority)) | ||
| { | ||
| SslCaCerts = CertUtils.LoadPemFileCert(GetFullPath( | ||
| k8SConfig, | ||
| clusterDetails.ClusterEndpoint.CertificateAuthority)); | ||
| var caBytes = File.ReadAllBytes(GetFullPath(k8SConfig, clusterDetails.ClusterEndpoint.CertificateAuthority)); | ||
| CaData = Convert.ToBase64String(caBytes); | ||
| var pemText = Encoding.UTF8.GetString(caBytes); | ||
| SslCaCerts = CertUtils.LoadFromPemText(pemText); | ||
| } | ||
|
mutsaddi-deshaw marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
@@ -426,7 +428,25 @@ private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext) | |
| throw new KubeConfigException("External command execution missing ApiVersion key"); | ||
| } | ||
|
|
||
| var response = ExecuteExternalCommand(userDetails.UserCredentials.ExternalExecution); | ||
| ClusterEndpoint clusterEndpoint = null; | ||
| if (userDetails.UserCredentials.ExternalExecution.ProvideClusterInfo) | ||
| { | ||
| var clusterDetails = k8SConfig.Clusters.FirstOrDefault(c => c.Name.Equals( | ||
| activeContext.ContextDetails.Cluster, | ||
| StringComparison.OrdinalIgnoreCase)); | ||
| var rawCluster = clusterDetails?.ClusterEndpoint; | ||
|
|
||
| clusterEndpoint = new ClusterEndpoint | ||
| { | ||
| Server = this.Host, | ||
| SkipTlsVerify = this.SkipTlsVerify, | ||
| TlsServerName = this.TlsServerName, | ||
| CertificateAuthorityData = this.CaData, | ||
| Extensions = rawCluster?.Extensions, | ||
| }; | ||
| } | ||
|
|
||
| var response = ExecuteExternalCommand(userDetails.UserCredentials.ExternalExecution, clusterEndpoint); | ||
| AccessToken = response.Status.Token; | ||
| // When reading ClientCertificateData from a config file it will be base64 encoded, and code later in the system (see CertUtils.GeneratePfx) | ||
| // expects ClientCertificateData and ClientCertificateKeyData to be base64 encoded because of this. However the string returned by external | ||
|
|
@@ -439,7 +459,7 @@ private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext) | |
| // TODO: support client certificates here too. | ||
| if (AccessToken != null) | ||
| { | ||
| TokenProvider = new ExecTokenProvider(userDetails.UserCredentials.ExternalExecution); | ||
| TokenProvider = new ExecTokenProvider(userDetails.UserCredentials.ExternalExecution, clusterEndpoint); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -450,23 +470,86 @@ private void SetUserDetails(K8SConfiguration k8SConfig, Context activeContext) | |
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Converts a <see cref="ClusterEndpoint"/> (kubeconfig model) into the | ||
| /// <c>spec.cluster</c> JSON representation defined by the exec credential plugin | ||
| /// protocol (client.authentication.k8s.io/v1). Returns <c>null</c> if | ||
| /// <paramref name="cluster"/> is <c>null</c>. | ||
| /// </summary> | ||
| /// <seealso href="https://kubernetes.io/docs/reference/config-api/client-authentication.v1/#Cluster"/> | ||
| internal static JsonNode ToExecClusterInfo(ClusterEndpoint cluster) | ||
| { | ||
| if (cluster == null) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| var node = new JsonObject | ||
| { | ||
| ["server"] = cluster.Server, | ||
| }; | ||
|
|
||
| if (cluster.SkipTlsVerify) | ||
| { | ||
| node["insecure-skip-tls-verify"] = true; | ||
| } | ||
|
|
||
| if (!string.IsNullOrEmpty(cluster.CertificateAuthorityData)) | ||
| { | ||
| node["certificate-authority-data"] = cluster.CertificateAuthorityData; | ||
| } | ||
|
|
||
| if (!string.IsNullOrEmpty(cluster.TlsServerName)) | ||
| { | ||
| node["tls-server-name"] = cluster.TlsServerName; | ||
| } | ||
|
|
||
| var execExtension = cluster.Extensions? | ||
| .FirstOrDefault(e => e.Name == "client.authentication.k8s.io/exec"); | ||
|
mutsaddi-deshaw marked this conversation as resolved.
Outdated
|
||
| if (execExtension != null) | ||
| { | ||
| object extConfig = execExtension.Extension; | ||
| if (extConfig != null) | ||
| { | ||
| node["config"] = JsonNode.Parse(JsonSerializer.Serialize(extConfig)); | ||
| } | ||
|
Comment on lines
+517
to
+521
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as #1808 (comment) |
||
| } | ||
|
Comment on lines
+513
to
+522
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
mutsaddi-deshaw marked this conversation as resolved.
|
||
|
|
||
| return node; | ||
| } | ||
|
|
||
| public static Process CreateRunnableExternalProcess(ExternalExecution config, EventHandler<DataReceivedEventArgs> captureStdError = null) | ||
| { | ||
| return CreateRunnableExternalProcess(config, captureStdError, null); | ||
| } | ||
|
|
||
| public static Process CreateRunnableExternalProcess(ExternalExecution config, EventHandler<DataReceivedEventArgs> captureStdError, ClusterEndpoint cluster) | ||
| { | ||
| if (config == null) | ||
| { | ||
| throw new ArgumentNullException(nameof(config)); | ||
| } | ||
|
|
||
| var execInfo = new Dictionary<string, dynamic> | ||
| var spec = new JsonObject { ["interactive"] = Environment.UserInteractive }; | ||
| if (config.ProvideClusterInfo) | ||
| { | ||
| var clusterNode = ToExecClusterInfo(cluster); | ||
| if (clusterNode != null) | ||
| { | ||
| spec["cluster"] = clusterNode; | ||
| } | ||
| } | ||
|
mutsaddi-deshaw marked this conversation as resolved.
mutsaddi-deshaw marked this conversation as resolved.
|
||
|
|
||
| var execInfo = new JsonObject | ||
| { | ||
| { "apiVersion", config.ApiVersion }, | ||
| { "kind", "ExecCredentials" }, | ||
| { "spec", new Dictionary<string, bool> { { "interactive", Environment.UserInteractive } } }, | ||
| ["apiVersion"] = config.ApiVersion, | ||
| ["kind"] = "ExecCredentials", | ||
| ["spec"] = spec, | ||
| }; | ||
|
|
||
| var process = new Process(); | ||
|
|
||
| process.StartInfo.EnvironmentVariables.Add("KUBERNETES_EXEC_INFO", JsonSerializer.Serialize(execInfo)); | ||
| process.StartInfo.EnvironmentVariables.Add("KUBERNETES_EXEC_INFO", execInfo.ToJsonString()); | ||
| if (config.EnvironmentVariables != null) | ||
| { | ||
| foreach (var configEnvironmentVariable in config.EnvironmentVariables) | ||
|
|
@@ -510,14 +593,19 @@ public static Process CreateRunnableExternalProcess(ExternalExecution config, Ev | |
| /// The token, client certificate data, and the client key data received from the external command execution | ||
| /// </returns> | ||
| public static ExecCredentialResponse ExecuteExternalCommand(ExternalExecution config) | ||
| { | ||
| return ExecuteExternalCommand(config, null); | ||
| } | ||
|
|
||
| public static ExecCredentialResponse ExecuteExternalCommand(ExternalExecution config, ClusterEndpoint cluster) | ||
| { | ||
| if (config == null) | ||
| { | ||
| throw new ArgumentNullException(nameof(config)); | ||
| } | ||
|
|
||
| var captureStdError = ExecStdError; | ||
| var process = CreateRunnableExternalProcess(config, captureStdError); | ||
| var process = CreateRunnableExternalProcess(config, captureStdError, cluster); | ||
|
|
||
| try | ||
| { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.