From 55365679855ac73821532d38d5953b4437b4b7b9 Mon Sep 17 00:00:00 2001 From: kazk Date: Fri, 4 Jun 2021 13:32:27 -0700 Subject: [PATCH] Add `client::ConfigExt` to extend `Config` for `Client` - Move TLS methods to `ConfigExt` - Prepare to move `Auth` method to `ConfigExt` - `.option_layer(config.auth_layer()?)` --- examples/custom_client.rs | 2 +- examples/custom_client_tls.rs | 2 +- examples/custom_client_trace.rs | 2 +- kube/src/client/auth/mod.rs | 12 ----- kube/src/client/config_ext.rs | 86 ++++++++++++++++++++++++++++++ kube/src/client/mod.rs | 8 ++- kube/src/{config => client}/tls.rs | 57 +------------------- kube/src/config/mod.rs | 3 +- 8 files changed, 99 insertions(+), 73 deletions(-) create mode 100644 kube/src/client/config_ext.rs rename kube/src/{config => client}/tls.rs (74%) diff --git a/examples/custom_client.rs b/examples/custom_client.rs index 098add9a5..8f3c65cc5 100644 --- a/examples/custom_client.rs +++ b/examples/custom_client.rs @@ -4,7 +4,7 @@ use tower::ServiceBuilder; use kube::{ api::{Api, ListParams}, - client::SetBaseUriLayer, + client::{ConfigExt, SetBaseUriLayer}, Client, Config, }; diff --git a/examples/custom_client_tls.rs b/examples/custom_client_tls.rs index a4c7c8166..d3d793c19 100644 --- a/examples/custom_client_tls.rs +++ b/examples/custom_client_tls.rs @@ -6,7 +6,7 @@ use tower::ServiceBuilder; use kube::{ api::{Api, ListParams}, - client::SetBaseUriLayer, + client::{ConfigExt, SetBaseUriLayer}, Client, Config, }; diff --git a/examples/custom_client_trace.rs b/examples/custom_client_trace.rs index 7c1f480e6..5abb0eeb3 100644 --- a/examples/custom_client_trace.rs +++ b/examples/custom_client_trace.rs @@ -10,7 +10,7 @@ use tracing::Span; use kube::{ api::{Api, ListParams}, - client::SetBaseUriLayer, + client::{ConfigExt, SetBaseUriLayer}, Client, Config, }; diff --git a/kube/src/client/auth/mod.rs b/kube/src/client/auth/mod.rs index 53be07567..a7a7512b9 100644 --- a/kube/src/client/auth/mod.rs +++ b/kube/src/client/auth/mod.rs @@ -5,7 +5,6 @@ use http::HeaderValue; use jsonpath_lib::select as jsonpath_select; use serde::{Deserialize, Serialize}; use tokio::sync::Mutex; -use tower::util::Either; use crate::{ config::{read_file_to_string, AuthInfo, AuthProviderConfig, ExecConfig}, @@ -29,17 +28,6 @@ pub(crate) enum Auth { RefreshableToken(RefreshableToken), } -impl Auth { - pub(crate) fn into_layer(self) -> Option> { - match self { - Self::None => None, - Self::Basic(user, pass) => Some(Either::A(AddAuthorizationLayer::basic(&user, &pass))), - Self::Bearer(token) => Some(Either::A(AddAuthorizationLayer::bearer(&token))), - Self::RefreshableToken(r) => Some(Either::B(RefreshingTokenLayer::new(r))), - } - } -} - // See https://github.com/kubernetes/kubernetes/tree/master/staging/src/k8s.io/client-go/plugin/pkg/client/auth // for the list of auth-plugins supported by client-go. // We currently support the following: diff --git a/kube/src/client/config_ext.rs b/kube/src/client/config_ext.rs new file mode 100644 index 000000000..be8a2c096 --- /dev/null +++ b/kube/src/client/config_ext.rs @@ -0,0 +1,86 @@ +use std::convert::TryFrom; + +use tower::util::Either; + +#[cfg(any(feature = "native-tls", feature = "rustls-tls"))] use super::tls; +use super::{ + auth::{AddAuthorizationLayer, RefreshingTokenLayer}, + Auth, +}; +use crate::{Config, Result}; + +/// Extensions to `Config` for `Client`. +pub trait ConfigExt { + /// Create `native_tls::TlsConnector` + #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))] + #[cfg(feature = "native-tls")] + fn native_tls_connector(&self) -> Result; + + /// Create `hyper_tls::HttpsConnector` + #[cfg_attr(docsrs, doc(cfg(all(feature = "client", feature = "native-tls"))))] + #[cfg(all(feature = "client", feature = "native-tls"))] + fn native_tls_https_connector(&self) -> Result>; + + /// Create `rustls::ClientConfig` + #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))] + #[cfg(feature = "rustls-tls")] + fn rustls_client_config(&self) -> Result; + + /// Create `hyper_rustls::HttpsConnector` + #[cfg_attr(docsrs, doc(cfg(all(feature = "client", feature = "rustls-tls"))))] + #[cfg(all(feature = "client", feature = "rustls-tls"))] + fn rustls_https_connector(&self) -> Result>; +} + +impl ConfigExt for Config { + #[cfg(feature = "native-tls")] + fn native_tls_connector(&self) -> Result { + tls::native_tls::native_tls_connector( + self.identity_pem.as_ref(), + self.root_cert.as_ref(), + self.accept_invalid_certs, + ) + } + + #[cfg(all(feature = "client", feature = "native-tls"))] + fn native_tls_https_connector(&self) -> Result> { + let tls = tokio_native_tls::TlsConnector::from(self.native_tls_connector()?); + let mut http = hyper::client::HttpConnector::new(); + http.enforce_http(false); + Ok(hyper_tls::HttpsConnector::from((http, tls))) + } + + #[cfg(feature = "rustls-tls")] + fn rustls_client_config(&self) -> Result { + tls::rustls_tls::rustls_client_config( + self.identity_pem.as_ref(), + self.root_cert.as_ref(), + self.accept_invalid_certs, + ) + } + + #[cfg(all(feature = "client", feature = "rustls-tls"))] + fn rustls_https_connector(&self) -> Result> { + let rustls_config = std::sync::Arc::new(self.rustls_client_config()?); + let mut http = hyper::client::HttpConnector::new(); + http.enforce_http(false); + Ok(hyper_rustls::HttpsConnector::from((http, rustls_config))) + } +} + +// A separate extension since it's not ready for public +pub(crate) trait ConfigAuthExt { + // TODO Try reducing exported types to minimize API surface before making this public. + fn auth_layer(&self) -> Result>>; +} + +impl ConfigAuthExt for Config { + fn auth_layer(&self) -> Result>> { + Ok(match Auth::try_from(&self.auth_info)? { + Auth::None => None, + Auth::Basic(user, pass) => Some(Either::A(AddAuthorizationLayer::basic(&user, &pass))), + Auth::Bearer(token) => Some(Either::A(AddAuthorizationLayer::bearer(&token))), + Auth::RefreshableToken(r) => Some(Either::B(RefreshingTokenLayer::new(r))), + }) + } +} diff --git a/kube/src/client/mod.rs b/kube/src/client/mod.rs index a462d435e..20eaf0e99 100644 --- a/kube/src/client/mod.rs +++ b/kube/src/client/mod.rs @@ -40,8 +40,14 @@ pub use base_uri::{SetBaseUri, SetBaseUriLayer}; mod body; // Add `into_stream()` to `http::Body` use body::BodyStreamExt; +mod config_ext; +use config_ext::ConfigAuthExt; +#[cfg(any(feature = "native-tls", feature = "rustls-tls"))] +#[cfg_attr(docsrs, doc(cfg(any(feature = "native-tls", feature = "rustls-tls"))))] +pub use config_ext::ConfigExt; mod headers; use headers::SetHeadersLayer; +#[cfg(any(feature = "native-tls", feature = "rustls-tls"))] mod tls; // Binary subprotocol v4. See `Client::connect`. #[cfg(feature = "ws")] @@ -448,7 +454,7 @@ impl TryFrom for Client { let service = ServiceBuilder::new() .layer(stack) - .option_layer(Auth::try_from(&config.auth_info)?.into_layer()) + .option_layer(config.auth_layer()?) .layer( // Attribute names follow [Semantic Conventions]. // [Semantic Conventions]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md diff --git a/kube/src/config/tls.rs b/kube/src/client/tls.rs similarity index 74% rename from kube/src/config/tls.rs rename to kube/src/client/tls.rs index a5c4bf074..3d749b8d8 100644 --- a/kube/src/config/tls.rs +++ b/kube/src/client/tls.rs @@ -1,58 +1,5 @@ -use crate::Result; - -use super::Config; - -impl Config { - /// Create `native_tls::TlsConnector` - #[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))] - #[cfg(feature = "native-tls")] - pub fn native_tls_connector(&self) -> Result { - self::native_tls::native_tls_connector( - self.identity_pem.as_ref(), - self.root_cert.as_ref(), - self.accept_invalid_certs, - ) - } - - /// Create `hyper_tls::HttpsConnector` - #[cfg_attr(docsrs, doc(cfg(all(feature = "client", feature = "native-tls"))))] - #[cfg(all(feature = "client", feature = "native-tls"))] - pub fn native_tls_https_connector( - &self, - ) -> Result> { - let tls = tokio_native_tls::TlsConnector::from(self.native_tls_connector()?); - let mut http = hyper::client::HttpConnector::new(); - http.enforce_http(false); - Ok(hyper_tls::HttpsConnector::from((http, tls))) - } - - /// Create `rustls::ClientConfig` - #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))] - #[cfg(feature = "rustls-tls")] - pub fn rustls_client_config(&self) -> Result { - self::rustls_tls::rustls_client_config( - self.identity_pem.as_ref(), - self.root_cert.as_ref(), - self.accept_invalid_certs, - ) - } - - /// Create `hyper_rustls::HttpsConnector` - #[cfg_attr(docsrs, doc(cfg(all(feature = "client", feature = "rustls-tls"))))] - #[cfg(all(feature = "client", feature = "rustls-tls"))] - pub fn rustls_https_connector( - &self, - ) -> Result> { - let rustls_config = std::sync::Arc::new(self.rustls_client_config()?); - let mut http = hyper::client::HttpConnector::new(); - http.enforce_http(false); - Ok(hyper_rustls::HttpsConnector::from((http, rustls_config))) - } -} - - #[cfg(feature = "native-tls")] -mod native_tls { +pub mod native_tls { use tokio_native_tls::native_tls::{Certificate, Identity, TlsConnector}; use crate::{Error, Result}; @@ -102,7 +49,7 @@ mod native_tls { } #[cfg(feature = "rustls-tls")] -mod rustls_tls { +pub mod rustls_tls { use std::sync::Arc; use rustls::{self, Certificate, ClientConfig, ServerCertVerified, ServerCertVerifier}; diff --git a/kube/src/config/mod.rs b/kube/src/config/mod.rs index 0c1b6524a..d59b5f25a 100644 --- a/kube/src/config/mod.rs +++ b/kube/src/config/mod.rs @@ -7,7 +7,6 @@ mod file_config; mod file_loader; mod incluster_config; -#[cfg(any(feature = "native-tls", feature = "rustls-tls"))] mod tls; mod utils; use crate::{error::ConfigError, Result}; @@ -38,7 +37,7 @@ pub struct Config { pub accept_invalid_certs: bool, // TODO should keep client key and certificate separate. It's split later anyway. /// Client certificate and private key in PEM. - identity_pem: Option>, + pub(crate) identity_pem: Option>, /// Stores information to tell the cluster who you are. pub(crate) auth_info: AuthInfo, }