diff --git a/src/config/apis.rs b/src/config/apis.rs index 1a52f4adc..bd238a892 100644 --- a/src/config/apis.rs +++ b/src/config/apis.rs @@ -92,6 +92,8 @@ pub struct AuthInfo { #[serde(rename = "auth-provider")] pub auth_provider: Option, + + pub exec: Option, } /// AuthProviderConfig stores auth for specified cloud provider. @@ -101,6 +103,16 @@ pub struct AuthProviderConfig { pub config: HashMap, } +/// ExecConfig stores credential-plugin configuration. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ExecConfig { + #[serde(rename = "apiVersion")] + pub api_version: Option, + pub args: Option>, + pub command: String, + pub env: Option>>, +} + /// NamedContext associates name with context. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct NamedContext { @@ -145,7 +157,9 @@ impl AuthInfo { self.token = Some(provider.config["access-token"].clone()); if utils::is_expired(&provider.config["expiry"]) { let client = oauth2::CredentialsClient::new()?; - let token = client.request_token(&vec!["https://www.googleapis.com/auth/cloud-platform".to_string()])?; + let token = client.request_token(&vec![ + "https://www.googleapis.com/auth/cloud-platform".to_string(), + ])?; self.token = Some(token.access_token); } } diff --git a/src/config/exec.rs b/src/config/exec.rs new file mode 100644 index 000000000..dd88b52ce --- /dev/null +++ b/src/config/exec.rs @@ -0,0 +1,55 @@ +use std::process::Command; + +use failure::Error; +use serde_json; + +use config::apis; + +/// ExecCredentials is used by exec-based plugins to communicate credentials to +/// HTTP transports. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ExecCredential { + pub kind: Option, + #[serde(rename = "apiVersion")] + pub api_version: Option, + pub spec: Option, + pub status: Option, +} + +/// ExecCredenitalSpec holds request and runtime specific information provided +/// by transport. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ExecCredentialSpec {} + +/// ExecCredentialStatus holds credentials for the transport to use. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ExecCredentialStatus { + #[serde(rename = "expirationTimestamp")] + pub expiration_timestamp: Option>, + pub token: Option, + #[serde(rename = "clientCertificateData")] + pub client_certificate_data: Option, + #[serde(rename = "clientKeyData")] + pub client_key_data: Option, +} + +pub fn auth_exec(auth: &apis::ExecConfig) -> Result { + let mut cmd = Command::new(&auth.command); + if let Some(args) = &auth.args { + cmd.args(args); + } + if let Some(env) = &auth.env { + let envs = env + .iter() + .flat_map(|env| match (env.get("name"), env.get("value")) { + (Some(name), Some(value)) => Some((name, value)), + _ => None, + }); + cmd.envs(envs); + } + let out = cmd.output()?; + if !out.status.success() { + return Err(format_err!("command `{:?}` failed: {:?}", cmd, out)); + } + serde_json::from_slice(&out.stdout).map_err(Error::from) +} diff --git a/src/config/mod.rs b/src/config/mod.rs index faf426c44..2a14a4285 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -1,4 +1,5 @@ mod apis; +mod exec; mod incluster_config; mod kube_config; mod utils; @@ -39,6 +40,21 @@ pub fn load_kube_config() -> Result { .ok_or(format_err!("Unable to load kubeconfig"))?; let loader = KubeConfigLoader::load(kubeconfig)?; + let token = match &loader.user.token { + Some(token) => Some(token.clone()), + None => { + if let Some(exec) = &loader.user.exec { + let creds = exec::auth_exec(exec)?; + let status = creds + .status + .ok_or(format_err!("exec-plugin response did not contain a status"))?; + status.token + } else { + None + } + } + }; + let mut client_builder = Client::builder(); if let Some(ca) = loader.ca() { @@ -61,7 +77,7 @@ pub fn load_kube_config() -> Result { let mut headers = header::HeaderMap::new(); match ( - utils::data_or_file(&loader.user.token, &loader.user.token_file), + utils::data_or_file(&token, &loader.user.token_file), (loader.user.username, loader.user.password), ) { (Ok(token), _) => { diff --git a/src/lib.rs b/src/lib.rs index d877fa5c9..1141ace39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ extern crate http; extern crate openssl; extern crate reqwest; extern crate serde; +extern crate serde_json; extern crate serde_yaml; extern crate time; extern crate url;