Skip to content
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

Change default TLS stack to rustls-tls #1261

Merged
merged 10 commits into from
Sep 8, 2023
12 changes: 1 addition & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,9 @@ jobs:
# echo "OPENSSL_LIB_DIR=C:/Program Files/OpenSSL-Win64/lib" >> $env:GITHUB_ENV
# echo "OPENSSL_DIR=C:/Program Files/OpenSSL-Win64/" >> $env:GITHUB_ENV
# echo "OPENSSL_INCLUDE_DIR=C:/Program Files/OpenSSL-Win64/include" >> $env:GITHUB_ENV
# Only test Rustls on Windows instead due to #1191
- name: "Interim Hacky Windows Test for #1191"
if: matrix.os == 'windows-latest'
run: |
sed -i '0,/openssl/s//rustls/' kube/Cargo.toml
cat kube/Cargo.toml
cargo build
cargo test --workspace --lib --exclude kube-examples --exclude e2e -j6


# Real CI work starts here
- name: Build workspace
if: matrix.os != 'windows-latest'
run: cargo build

# Workspace unit tests with various feature sets
Expand All @@ -58,7 +48,7 @@ jobs:
if: matrix.os == 'ubuntu-latest' # only linux tests all feature combinations
- name: Run workspace unit tests (default features)
run: cargo test --workspace --lib --exclude kube-examples --exclude e2e -j6
if: matrix.os == 'ubuntu-latest'
if: matrix.os != 'macos-latest'
- name: Run workspace unit tests (all features)
if: matrix.os != 'windows-latest'
run: cargo test --workspace --lib --all-features --exclude kube-examples --exclude e2e -j6
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,17 @@ Controller::new(root_kind_api, Config::default())

Here `reconcile` and `error_policy` refer to functions you define. The first will be called when the root or child elements change, and the second when the `reconciler` returns an `Err`.

## Rustls
## TLS

By default `openssl` is used for TLS, but [rustls](https://github.com/ctz/rustls) is supported. To switch, turn off `default-features`, and enable the `rustls-tls` feature:
By default [rustls](https://github.com/ctz/rustls) is used for TLS, but `openssl` is supported. To switch, turn off `default-features`, and enable the `openssl-tls` feature:

```toml
[dependencies]
kube = { version = "0.85.0", default-features = false, features = ["client", "rustls-tls"] }
kube = { version = "0.85.0", default-features = false, features = ["client", "openssl-tls"] }
k8s-openapi = { version = "0.19.0", features = ["v1_27"] }
```

This will pull in `rustls` and `hyper-rustls`. If `default-features` is left enabled, you will pull in two TLS stacks, and the default will remain as `openssl`.
This will pull in `openssl` and `hyper-openssl`. If `default-features` is left enabled, you will pull in two TLS stacks, and the default will remain as `rustls`.

## musl-libc

Expand Down
2 changes: 1 addition & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ license = "Apache-2.0"
release = false

[features]
default = ["openssl-tls", "kubederive", "ws", "latest", "runtime", "refresh"]
default = ["rustls-tls", "kubederive", "ws", "latest", "runtime", "refresh"]
kubederive = ["kube/derive"]
openssl-tls = ["kube/client", "kube/openssl-tls"]
rustls-tls = ["kube/client", "kube/rustls-tls"]
Expand Down
6 changes: 3 additions & 3 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ cargo run --example crd_reflector

The `crd_reflector` will just await changes. You can run `kubectl apply -f crd-baz.yaml`, or `kubectl delete -f crd-baz.yaml -n default`, or `kubectl edit foos baz -n default` to verify that the events are being picked up.

## rustls
Disable default features and enable `rustls-tls`:
## openssl
Disable default features and enable `openssl-tls`:

```sh
cargo run --example pod_watcher --no-default-features --features=rustls-tls,latest,runtime
cargo run --example pod_watcher --no-default-features --features=openssl-tls,latest,runtime
```
3 changes: 2 additions & 1 deletion examples/custom_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt::init();

let config = Config::infer().await?;
let https = config.openssl_https_connector()?;

let https = config.rustls_https_connector()?;
let service = tower::ServiceBuilder::new()
.layer(config.base_uri_layer())
.option_layer(config.auth_layer()?)
Expand Down
8 changes: 4 additions & 4 deletions examples/custom_client_tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ async fn main() -> anyhow::Result<()> {
let config = Config::infer().await?;

// Pick TLS at runtime
let use_rustls = std::env::var("USE_RUSTLS").map(|s| s == "1").unwrap_or(false);
let client = if use_rustls {
let https = config.rustls_https_connector()?;
let use_openssl = std::env::var("USE_OPENSSL").map(|s| s == "1").unwrap_or(false);
let client = if use_openssl {
let https = config.openssl_https_connector()?;
let service = ServiceBuilder::new()
.layer(config.base_uri_layer())
.service(hyper::Client::builder().build(https));
Client::new(service, config.default_namespace)
} else {
let https = config.openssl_https_connector()?;
let https = config.rustls_https_connector()?;
let service = ServiceBuilder::new()
.layer(config.base_uri_layer())
.service(hyper::Client::builder().build(https));
Expand Down
2 changes: 1 addition & 1 deletion examples/custom_client_trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt::init();

let config = Config::infer().await?;
let https = config.openssl_https_connector()?;
let https = config.rustls_https_connector()?;
let service = ServiceBuilder::new()
.layer(config.base_uri_layer())
// showcase rate limiting; max 10rps, and 4 concurrent
Expand Down
12 changes: 6 additions & 6 deletions kube-client/src/client/auth/oauth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,17 +108,17 @@ impl Gcp {
"At least one of rustls-tls or openssl-tls feature must be enabled to use oauth feature"
);
// Current TLS feature precedence when more than one are set:
// 1. openssl-tls
// 2. rustls-tls
#[cfg(feature = "openssl-tls")]
let https =
hyper_openssl::HttpsConnector::new().map_err(Error::CreateOpensslHttpsConnector)?;
#[cfg(all(not(feature = "openssl-tls"), feature = "rustls-tls"))]
// 1. rustls-tls
// 2. openssl-tls
#[cfg(feature = "rustls-tls")]
let https = hyper_rustls::HttpsConnectorBuilder::new()
.with_native_roots()
.https_only()
.enable_http1()
.build();
#[cfg(all(not(feature = "rustls-tls"), feature = "openssl-tls"))]
let https =
hyper_openssl::HttpsConnector::new().map_err(Error::CreateOpensslHttpsConnector)?;

let client = hyper::Client::builder().build::<_, hyper::Body>(https);

Expand Down
17 changes: 8 additions & 9 deletions kube-client/src/client/auth/oidc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,12 @@ compile_error!(
"At least one of rustls-tls or openssl-tls feature must be enabled to use refresh-oidc feature"
);
// Current TLS feature precedence when more than one are set:
// 1. openssl-tls
// 2. rustls-tls
#[cfg(feature = "openssl-tls")]
type HttpsConnector = hyper_openssl::HttpsConnector<HttpConnector>;
#[cfg(all(not(feature = "openssl-tls"), feature = "rustls-tls"))]
// 1. rustls-tls
// 2. openssl-tls
#[cfg(feature = "rustls-tls")]
type HttpsConnector = hyper_rustls::HttpsConnector<HttpConnector>;
#[cfg(all(not(feature = "rustls-tls"), feature = "openssl-tls"))]
type HttpsConnector = hyper_openssl::HttpsConnector<HttpConnector>;

/// Struct for refreshing the ID token with the refresh token.
#[derive(Debug)]
Expand Down Expand Up @@ -300,15 +300,14 @@ impl Refresher {
let client_id = get_field(Self::CONFIG_CLIENT_ID)?.into();
let client_secret = get_field(Self::CONFIG_CLIENT_SECRET)?.into();


#[cfg(feature = "openssl-tls")]
let https = hyper_openssl::HttpsConnector::new()?;
#[cfg(all(not(feature = "openssl-tls"), feature = "rustls-tls"))]
#[cfg(feature = "rustls-tls")]
let https = hyper_rustls::HttpsConnectorBuilder::new()
.with_native_roots()
.https_only()
.enable_http1()
.build();
#[cfg(all(not(feature = "rustls-tls"), feature = "openssl-tls"))]
let https = hyper_openssl::HttpsConnector::new()?;

let https_client = hyper::Client::builder().build(https);

Expand Down
18 changes: 12 additions & 6 deletions kube-client/src/client/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,26 @@ impl TryFrom<Config> for ClientBuilder<BoxService<Request<hyper::Body>, Response
use tracing::Span;

let default_ns = config.default_namespace.clone();
let auth_layer = config.auth_layer()?;

let client: hyper::Client<_, hyper::Body> = {
let mut connector = HttpConnector::new();
connector.enforce_http(false);

// Current TLS feature precedence when more than one are set:
// 1. openssl-tls
// 2. rustls-tls
// 1. rustls-tls
// 2. openssl-tls
// Create a custom client to use something else.
// If TLS features are not enabled, http connector will be used.
#[cfg(feature = "openssl-tls")]
let connector = config.openssl_https_connector_with_connector(connector)?;
#[cfg(all(not(feature = "openssl-tls"), feature = "rustls-tls"))]
#[cfg(feature = "rustls-tls")]
let connector = config.rustls_https_connector_with_connector(connector)?;
#[cfg(all(not(feature = "rustls-tls"), feature = "openssl-tls"))]
let connector = config.openssl_https_connector_with_connector(connector)?;
#[cfg(all(not(feature = "rustls-tls"), not(feature = "openssl-tls")))]
if auth_layer.is_none() || config.cluster_url.scheme() == Some(&http::uri::Scheme::HTTPS) {
// no tls stack situation only works on anonymous auth with http scheme
return Err(Error::TlsRequired);
}

let mut connector = TimeoutConnector::new(connector);

Expand All @@ -106,7 +112,7 @@ impl TryFrom<Config> for ClientBuilder<BoxService<Request<hyper::Body>, Response

let service = ServiceBuilder::new()
.layer(stack)
.option_layer(config.auth_layer()?)
.option_layer(auth_layer)
.layer(config.extra_headers_layer()?)
.layer(
// Attribute names follow [Semantic Conventions].
Expand Down
4 changes: 4 additions & 0 deletions kube-client/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ pub enum Error {
#[error("rustls tls error: {0}")]
RustlsTls(#[source] crate::client::RustlsTlsError),

/// Missing TLS stacks when TLS is required
#[error("TLS required but no TLS stack selected")]
TlsRequired,

/// Failed to upgrade to a WebSocket connection
#[cfg(feature = "ws")]
#[cfg_attr(docsrs, doc(cfg(feature = "ws")))]
Expand Down
12 changes: 9 additions & 3 deletions kube/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,24 @@ rust-version = "1.64.0"
edition = "2021"

[features]
default = ["client", "openssl-tls"]
default = ["client", "rustls-tls"]

# default features
client = ["kube-client/client", "config"]
config = ["kube-client/config"]
rustls-tls = ["kube-client/rustls-tls"]

# alternative features
openssl-tls = ["kube-client/openssl-tls"]

# auxiliary features
ws = ["kube-client/ws", "kube-core/ws"]
oauth = ["kube-client/oauth"]
oidc = ["kube-client/oidc"]
gzip = ["kube-client/gzip"]
client = ["kube-client/client", "config"]
jsonpatch = ["kube-core/jsonpatch"]
admission = ["kube-core/admission"]
derive = ["kube-derive", "kube-core/schema"]
config = ["kube-client/config"]
runtime = ["kube-runtime"]
unstable-runtime = ["kube-runtime/unstable-runtime"]

Expand Down
Loading