Skip to content

Commit

Permalink
Add client::ConfigExt to extend Config for Client
Browse files Browse the repository at this point in the history
- Move TLS methods to `ConfigExt`
- Prepare to move `Auth` method to `ConfigExt`
  - `.option_layer(config.auth_layer()?)`
  • Loading branch information
kazk committed Jun 4, 2021
1 parent 54baa61 commit 1bdb02f
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 73 deletions.
2 changes: 1 addition & 1 deletion examples/custom_client.rs
Expand Up @@ -4,7 +4,7 @@ use tower::ServiceBuilder;

use kube::{
api::{Api, ListParams},
client::SetBaseUriLayer,
client::{ConfigExt, SetBaseUriLayer},
Client, Config,
};

Expand Down
2 changes: 1 addition & 1 deletion examples/custom_client_tls.rs
Expand Up @@ -6,7 +6,7 @@ use tower::ServiceBuilder;

use kube::{
api::{Api, ListParams},
client::SetBaseUriLayer,
client::{ConfigExt, SetBaseUriLayer},
Client, Config,
};

Expand Down
2 changes: 1 addition & 1 deletion examples/custom_client_trace.rs
Expand Up @@ -10,7 +10,7 @@ use tracing::Span;

use kube::{
api::{Api, ListParams},
client::SetBaseUriLayer,
client::{ConfigExt, SetBaseUriLayer},
Client, Config,
};

Expand Down
12 changes: 0 additions & 12 deletions kube/src/client/auth/mod.rs
Expand Up @@ -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},
Expand All @@ -29,17 +28,6 @@ pub(crate) enum Auth {
RefreshableToken(RefreshableToken),
}

impl Auth {
pub(crate) fn into_layer(self) -> Option<Either<AddAuthorizationLayer, RefreshingTokenLayer>> {
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:
Expand Down
86 changes: 86 additions & 0 deletions 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<tokio_native_tls::native_tls::TlsConnector>;

/// Create `hyper_tls::HttpsConnector`
#[cfg_attr(docsrs, doc(cfg(feature = "native-tls")))]
#[cfg(feature = "native-tls")]
fn native_tls_https_connector(&self) -> Result<hyper_tls::HttpsConnector<hyper::client::HttpConnector>>;

/// Create `rustls::ClientConfig`
#[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
#[cfg(feature = "rustls-tls")]
fn rustls_client_config(&self) -> Result<rustls::ClientConfig>;

/// Create `hyper_rustls::HttpsConnector`
#[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))]
#[cfg(feature = "rustls-tls")]
fn rustls_https_connector(&self) -> Result<hyper_rustls::HttpsConnector<hyper::client::HttpConnector>>;
}

impl ConfigExt for Config {
#[cfg(feature = "native-tls")]
fn native_tls_connector(&self) -> Result<tokio_native_tls::native_tls::TlsConnector> {
tls::native_tls::native_tls_connector(
self.identity_pem.as_ref(),
self.root_cert.as_ref(),
self.accept_invalid_certs,
)
}

#[cfg(feature = "native-tls")]
fn native_tls_https_connector(&self) -> Result<hyper_tls::HttpsConnector<hyper::client::HttpConnector>> {
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<rustls::ClientConfig> {
tls::rustls_tls::rustls_client_config(
self.identity_pem.as_ref(),
self.root_cert.as_ref(),
self.accept_invalid_certs,
)
}

#[cfg(feature = "rustls-tls")]
fn rustls_https_connector(&self) -> Result<hyper_rustls::HttpsConnector<hyper::client::HttpConnector>> {
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<Option<Either<AddAuthorizationLayer, RefreshingTokenLayer>>>;
}

impl ConfigAuthExt for Config {
fn auth_layer(&self) -> Result<Option<Either<AddAuthorizationLayer, RefreshingTokenLayer>>> {
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))),
})
}
}
8 changes: 7 additions & 1 deletion kube/src/client/mod.rs
Expand Up @@ -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")]
Expand Down Expand Up @@ -448,7 +454,7 @@ impl TryFrom<Config> 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
Expand Down
57 changes: 2 additions & 55 deletions kube/src/config/tls.rs → 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<tokio_native_tls::native_tls::TlsConnector> {
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<hyper_tls::HttpsConnector<hyper::client::HttpConnector>> {
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<rustls::ClientConfig> {
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<hyper_rustls::HttpsConnector<hyper::client::HttpConnector>> {
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};
Expand Down Expand Up @@ -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};
Expand Down
3 changes: 1 addition & 2 deletions kube/src/config/mod.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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<Vec<u8>>,
pub(crate) identity_pem: Option<Vec<u8>>,
/// Stores information to tell the cluster who you are.
pub(crate) auth_info: AuthInfo,
}
Expand Down

0 comments on commit 1bdb02f

Please sign in to comment.