Skip to content

Commit

Permalink
Change default TLS stack to rustls-tls (#1261)
Browse files Browse the repository at this point in the history
* Make rustls-tls the default tls stack feature

Signed-off-by: clux <sszynrae@gmail.com>

* try unhacking windows ci for rustls

Signed-off-by: clux <sszynrae@gmail.com>

* invert the readme on tls

Signed-off-by: clux <sszynrae@gmail.com>

* disallow Client construction that requires auth when no tls stacks present

fixes #1275

Signed-off-by: clux <sszynrae@gmail.com>

* fix defaults in examples also

Signed-off-by: clux <sszynrae@gmail.com>

* properly fix example defaults

Signed-off-by: clux <sszynrae@gmail.com>

* also force TlsRequired when cluster_url is https scheme

Signed-off-by: clux <sszynrae@gmail.com>

---------

Signed-off-by: clux <sszynrae@gmail.com>
Signed-off-by: Eirik A <sszynrae@gmail.com>
  • Loading branch information
clux authored Sep 8, 2023
1 parent 259ed96 commit 3d68ec1
Show file tree
Hide file tree
Showing 12 changed files with 55 additions and 49 deletions.
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

0 comments on commit 3d68ec1

Please sign in to comment.