diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 3753642f1..abf187a18 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -45,11 +45,11 @@ tar = "0.4.37" tracing = "0.1.36" tracing-subscriber = "0.3.3" warp = { version = "0.3", default-features = false, features = ["tls"] } -http = "0.2.5" +http = "1.0.0" json-patch = "1.0.0" tower = { version = "0.4.13", features = ["limit"] } -tower-http = { version = "0.4.0", features = ["trace", "decompression-gzip"] } -hyper = { version = "0.14.13", features = ["client", "http1", "stream", "tcp"] } +tower-http = { version = "0.5.1", features = ["trace", "decompression-gzip"] } +hyper = { version = "1.1.0", features = ["client", "http1"] } thiserror = "1.0.29" backoff = "0.4.0" clap = { version = "4.0", default-features = false, features = ["std", "cargo", "derive"] } diff --git a/kube-client/Cargo.toml b/kube-client/Cargo.toml index bfaa74ab9..b1f636066 100644 --- a/kube-client/Cargo.toml +++ b/kube-client/Cargo.toml @@ -23,7 +23,7 @@ ws = ["client", "tokio-tungstenite", "rand", "kube-core/ws", "tokio/macros"] oauth = ["client", "tame-oauth"] oidc = ["client", "form_urlencoded"] gzip = ["client", "tower-http/decompression-gzip"] -client = ["config", "__non_core", "hyper", "http-body", "tower", "tower-http", "hyper-timeout", "pin-project", "chrono", "jsonpath-rust", "bytes", "futures", "tokio", "tokio-util", "either"] +client = ["config", "__non_core", "hyper", "http-body", "hyper-tls", "hyper-util", "http-body-util", "tower", "tower-http", "hyper-timeout", "pin-project", "chrono", "jsonpath-rust", "bytes", "futures", "tokio", "tokio-util", "either"] jsonpatch = ["kube-core/jsonpatch"] admission = ["kube-core/admission"] config = ["__non_core", "pem", "home"] @@ -44,35 +44,45 @@ home = { version = "0.5.4", optional = true } serde = { version = "1.0.130", features = ["derive"] } serde_json = "1.0.68" serde_yaml = { version = "0.9.19", optional = true } -http = "0.2.5" -http-body = { version = "0.4.2", optional = true } +http = "1.0.0" +http-body = { version = "1.0.0", optional = true } either = { version = "1.6.1", optional = true } thiserror = "1.0.29" futures = { version = "0.3.17", optional = true } pem = { version = "3.0.1", optional = true } openssl = { version = "0.10.36", optional = true } -rustls = { version = "0.21.4", features = ["dangerous_configuration"], optional = true } -rustls-pemfile = { version = "1.0.0", optional = true } +rustls = { version = "0.22.2", optional = true } +rustls-pemfile = { version = "2.0.0", optional = true } bytes = { version = "1.1.0", optional = true } tokio = { version = "1.14.0", features = ["time", "signal", "sync"], optional = true } kube-core = { path = "../kube-core", version = "=0.88.0" } jsonpath-rust = { version = "0.4.0", optional = true } tokio-util = { version = "0.7.0", optional = true, features = ["io", "codec"] } -hyper = { version = "0.14.13", optional = true, features = ["client", "http1", "stream", "tcp"] } -hyper-rustls = { version = "0.24.0", optional = true } -hyper-socks2 = { version = "0.8.0", optional = true, default-features = false } -tokio-tungstenite = { version = "0.20.0", optional = true } +hyper = { version = "1.1.0", optional = true, features = ["client", "http1"] } +hyper-rustls = { version = "0.26.0", optional = true } +hyper-tls = { version = "0.6.0", optional = true } +hyper-util = { version = "0.1.1", optional = true, features = ["client-legacy", "tokio"] } +http-body-util = { version = "0.1.0", optional = true } +#hyper-socks2 = { version = "0.8.0", optional = true, default-features = false } # using fork below +tokio-tungstenite = { version = "0.21.0", optional = true } tower = { version = "0.4.13", optional = true, features = ["buffer", "filter", "util"] } -tower-http = { version = "0.4.0", optional = true, features = ["auth", "map-response-body", "trace"] } -hyper-timeout = {version = "0.4.1", optional = true } +tower-http = { version = "0.5.1", optional = true, features = ["auth", "map-response-body", "trace"] } +hyper-timeout = {version = "0.5.1", optional = true } tame-oauth = { version = "0.9.1", features = ["gcp"], optional = true } pin-project = { version = "1.0.4", optional = true } rand = { version = "0.8.3", optional = true } secrecy = { version = "0.8.0", features = ["alloc", "serde"] } tracing = { version = "0.1.36", features = ["log"], optional = true } -hyper-openssl = { version = "0.9.2", optional = true } +hyper-openssl = { version = "0.10.1", optional = true } form_urlencoded = { version = "1.2.0", optional = true } +[dependencies.hyper-socks2] +git = "https://github.com/aviramha/hyper-socks2.git" +#branch = "hyper1" +rev = "947387f377ed441e42cc61a3397333a20932f28f" +optional = true +default-features = false + [dependencies.k8s-openapi] version = "0.21.0" default-features = false diff --git a/kube-client/src/api/mod.rs b/kube-client/src/api/mod.rs index 554b96876..db1e7155b 100644 --- a/kube-client/src/api/mod.rs +++ b/kube-client/src/api/mod.rs @@ -1,27 +1,28 @@ //! API helpers for structured interaction with the Kubernetes API -mod core_methods; -#[cfg(feature = "ws")] mod remote_command; +// TODO: reinstate.. +//mod core_methods; +//#[cfg(feature = "ws")] mod remote_command; use std::fmt::Debug; -#[cfg(feature = "ws")] pub use remote_command::{AttachedProcess, TerminalSize}; -#[cfg(feature = "ws")] mod portforward; -#[cfg(feature = "ws")] pub use portforward::Portforwarder; +//#[cfg(feature = "ws")] pub use remote_command::{AttachedProcess, TerminalSize}; +//#[cfg(feature = "ws")] mod portforward; +//#[cfg(feature = "ws")] pub use portforward::Portforwarder; -mod subresource; -#[cfg(feature = "ws")] +//mod subresource; +/*#[cfg(feature = "ws")] #[cfg_attr(docsrs, doc(cfg(feature = "ws")))] pub use subresource::{Attach, AttachParams, Execute, Portforward}; pub use subresource::{Evict, EvictParams, Log, LogParams, ScaleSpec, ScaleStatus}; - +*/ // Ephemeral containers were stabilized in Kubernetes 1.25. -k8s_openapi::k8s_if_ge_1_25! { - pub use subresource::Ephemeral; -} +//k8s_openapi::k8s_if_ge_1_25! { +// pub use subresource::Ephemeral; +//} -mod util; +//mod util; -pub mod entry; +//pub mod entry; // Re-exports from kube-core #[cfg(feature = "admission")] diff --git a/kube-client/src/client/auth/mod.rs b/kube-client/src/client/auth/mod.rs index eaca2d8ea..0cf9bb446 100644 --- a/kube-client/src/client/auth/mod.rs +++ b/kube-client/src/client/auth/mod.rs @@ -19,10 +19,10 @@ use tower::{filter::AsyncPredicate, BoxError}; use crate::config::{AuthInfo, AuthProviderConfig, ExecAuthCluster, ExecConfig, ExecInteractiveMode}; -#[cfg(feature = "oauth")] mod oauth; -#[cfg(feature = "oauth")] pub use oauth::Error as OAuthError; -#[cfg(feature = "oidc")] mod oidc; -#[cfg(feature = "oidc")] pub use oidc::errors as oidc_errors; +//#[cfg(feature = "oauth")] mod oauth; +//#[cfg(feature = "oauth")] pub use oauth::Error as OAuthError; +//#[cfg(feature = "oidc")] mod oidc; +//#[cfg(feature = "oidc")] pub use oidc::errors as oidc_errors; #[cfg(target_os = "windows")] use std::os::windows::process::CommandExt; #[derive(Error, Debug)] diff --git a/kube-client/src/client/builder.rs b/kube-client/src/client/builder.rs index e1ae4871c..ca4e6dc38 100644 --- a/kube-client/src/client/builder.rs +++ b/kube-client/src/client/builder.rs @@ -1,10 +1,13 @@ use bytes::Bytes; use http::{header::HeaderMap, Request, Response}; +use http_body_util::{combinators::BoxBody, BodyExt, StreamBody}; use hyper::{ - self, - client::{connect::Connection, HttpConnector}, + body::{Body, Incoming}, + client::conn::http1::Connection, }; use hyper_timeout::TimeoutConnector; +use hyper_tls::HttpsConnector; +use hyper_util::client::legacy::{connect::HttpConnector, Builder as HyperBuilder}; pub use kube_core::response::Status; use std::time::Duration; use tokio::io::{AsyncRead, AsyncWrite}; @@ -17,9 +20,7 @@ use tracing::Span; use crate::{client::ConfigExt, Client, Config, Error, Result}; /// HTTP body of a dynamic backing type. -/// -/// The suggested implementation type is [`hyper::Body`]. -pub type DynBody = dyn http_body::Body + Send + Unpin; +pub type DynBody = dyn Body + Send + Unpin; /// Builder for [`Client`] instances with customized [tower](`Service`) middleware. pub struct ClientBuilder { @@ -34,7 +35,7 @@ impl ClientBuilder { /// which provides a default stack as a starting point. pub fn new(service: Svc, default_namespace: impl Into) -> Self where - Svc: Service>, + Svc: Service>, { Self { service, @@ -57,7 +58,7 @@ impl ClientBuilder { /// Build a [`Client`] instance with the current [`Service`] stack. pub fn build(self) -> Client where - Svc: Service, Response = Response> + Send + 'static, + Svc: Service, Response = Response> + Send + 'static, Svc::Future: Send + 'static, Svc::Error: Into, B: http_body::Body + Send + 'static, @@ -67,7 +68,7 @@ impl ClientBuilder { } } -pub type GenericService = BoxService, Response>, BoxError>; +pub type GenericService = BoxService, Response>, BoxError>; impl TryFrom for ClientBuilder { type Error = Error; @@ -97,14 +98,14 @@ impl TryFrom for ClientBuilder { fn make_generic_builder(connector: H, config: Config) -> Result, Error> where H: 'static + Clone + Send + Sync + Service, - H::Response: 'static + Connection + AsyncRead + AsyncWrite + Send + Unpin, + H::Response: 'static + AsyncRead + AsyncWrite + Send + Unpin, H::Future: 'static + Send, H::Error: 'static + Send + Sync + std::error::Error, { let default_ns = config.default_namespace.clone(); let auth_layer = config.auth_layer()?; - let client: hyper::Client<_, hyper::Body> = { + let client = { // Current TLS feature precedence when more than one are set: // 1. rustls-tls // 2. openssl-tls @@ -120,14 +121,16 @@ where return Err(Error::TlsRequired); } - let mut connector = TimeoutConnector::new(connector); + //TODO: fix bound + //let mut connector = TimeoutConnector::new(connector); // Set the timeouts for the client - connector.set_connect_timeout(config.connect_timeout); - connector.set_read_timeout(config.read_timeout); - connector.set_write_timeout(config.write_timeout); + // connector.set_connect_timeout(config.connect_timeout); + // connector.set_read_timeout(config.read_timeout); + // connector.set_write_timeout(config.write_timeout); - hyper::Client::builder().build(connector) + use hyper_util::rt::TokioExecutor; // seems necessary now + HyperBuilder::new(TokioExecutor::new()).build(connector) }; let stack = ServiceBuilder::new().layer(config.base_uri_layer()).into_inner(); @@ -145,7 +148,7 @@ where // Attribute names follow [Semantic Conventions]. // [Semantic Conventions]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md TraceLayer::new_for_http() - .make_span_with(|req: &Request| { + .make_span_with(|req: &Request| { tracing::debug_span!( "HTTP", http.method = %req.method(), @@ -156,10 +159,10 @@ where otel.status_code = tracing::field::Empty, ) }) - .on_request(|_req: &Request, _span: &Span| { + .on_request(|_req: &Request, _span: &Span| { tracing::debug!("requesting"); }) - .on_response(|res: &Response, _latency: Duration, span: &Span| { + .on_response(|res: &Response, _latency: Duration, span: &Span| { let status = res.status(); span.record("http.status_code", status.as_u16()); if status.is_client_error() || status.is_server_error() { diff --git a/kube-client/src/client/config_ext.rs b/kube-client/src/client/config_ext.rs index 6e7239a1d..b89b0de27 100644 --- a/kube-client/src/client/config_ext.rs +++ b/kube-client/src/client/config_ext.rs @@ -1,6 +1,7 @@ use std::sync::Arc; use http::{header::HeaderName, HeaderValue}; +use hyper_util::client::legacy::connect::HttpConnector; use secrecy::ExposeSecret; use tower::{filter::AsyncFilterLayer, util::Either}; @@ -26,7 +27,7 @@ pub trait ConfigExt: private::Sealed { /// Layer to add non-authn HTTP headers depending on the config. fn extra_headers_layer(&self) -> Result; - /// Create [`hyper_rustls::HttpsConnector`] based on config. + /// Create [`HttpsConnector`] based on config. /// /// # Example /// @@ -41,16 +42,16 @@ pub trait ConfigExt: private::Sealed { /// ``` #[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))] #[cfg(feature = "rustls-tls")] - fn rustls_https_connector(&self) -> Result>; + fn rustls_https_connector(&self) -> Result>; - /// Create [`hyper_rustls::HttpsConnector`] based on config and `connector`. + /// Create [`HttpsConnector`] based on config and `connector`. /// /// # Example /// /// ```rust /// # async fn doc() -> Result<(), Box> { /// # use kube::{client::ConfigExt, Config}; - /// # use hyper::client::HttpConnector; + /// # use hyper_util::client::legacy::connect::HttpConnector; /// let config = Config::infer().await?; /// let mut connector = HttpConnector::new(); /// connector.enforce_http(false); @@ -71,7 +72,7 @@ pub trait ConfigExt: private::Sealed { /// /// ```rust /// # async fn doc() -> Result<(), Box> { - /// # use hyper::client::HttpConnector; + /// # use hyper_util::client::legacy::connect::HttpConnector; /// # use kube::{client::ConfigExt, Config}; /// let config = Config::infer().await?; /// let https = { @@ -87,7 +88,7 @@ pub trait ConfigExt: private::Sealed { #[cfg(feature = "rustls-tls")] fn rustls_client_config(&self) -> Result; - /// Create [`hyper_openssl::HttpsConnector`] based on config. + /// Create [`HttpsConnector`] based on config. /// # Example /// /// ```rust @@ -100,14 +101,14 @@ pub trait ConfigExt: private::Sealed { /// ``` #[cfg_attr(docsrs, doc(cfg(feature = "openssl-tls")))] #[cfg(feature = "openssl-tls")] - fn openssl_https_connector(&self) -> Result>; + fn openssl_https_connector(&self) -> Result>; - /// Create [`hyper_openssl::HttpsConnector`] based on config and `connector`. + /// Create [`HttpsConnector`] based on config and `connector`. /// # Example /// /// ```rust /// # async fn doc() -> Result<(), Box> { - /// # use hyper::client::HttpConnector; + /// # use hyper_util::client::legacy::connect::HttpConnector; /// # use kube::{client::ConfigExt, Config}; /// let mut http = HttpConnector::new(); /// http.enforce_http(false); @@ -134,7 +135,7 @@ pub trait ConfigExt: private::Sealed { /// /// ```rust /// # async fn doc() -> Result<(), Box> { - /// # use hyper::client::HttpConnector; + /// # use hyper_util::client::legacy::connect::HttpConnector; /// # use kube::{client::ConfigExt, Client, Config}; /// let config = Config::infer().await?; /// let https = { @@ -214,8 +215,8 @@ impl ConfigExt for Config { } #[cfg(feature = "rustls-tls")] - fn rustls_https_connector(&self) -> Result> { - let mut connector = hyper::client::HttpConnector::new(); + fn rustls_https_connector(&self) -> Result> { + let mut connector = HttpConnector::new(); connector.enforce_http(false); self.rustls_https_connector_with_connector(connector) } @@ -244,17 +245,14 @@ impl ConfigExt for Config { } #[cfg(feature = "openssl-tls")] - fn openssl_https_connector(&self) -> Result> { - let mut connector = hyper::client::HttpConnector::new(); + fn openssl_https_connector(&self) -> Result> { + let mut connector = HttpConnector::new(); connector.enforce_http(false); self.openssl_https_connector_with_connector(connector) } #[cfg(feature = "openssl-tls")] - fn openssl_https_connector_with_connector( - &self, - connector: H, - ) -> Result> + fn openssl_https_connector_with_connector(&self, connector: H) -> Result> where H: tower::Service + Send, H::Error: Into>, diff --git a/kube-client/src/client/mod.rs b/kube-client/src/client/mod.rs index 83d87e74a..e62d2a41b 100644 --- a/kube-client/src/client/mod.rs +++ b/kube-client/src/client/mod.rs @@ -7,10 +7,18 @@ //! //! The [`Client`] can also be used with [`Discovery`](crate::Discovery) to dynamically //! retrieve the resources served by the kubernetes API. +#![allow(unused_imports)] // TODO: remove +use bytes::Bytes; use either::{Either, Left, Right}; use futures::{self, AsyncBufRead, StreamExt, TryStream, TryStreamExt}; use http::{self, Request, Response, StatusCode}; -use hyper::Body; +use http_body::Body; +use http_body_util::{ + combinators::{BoxBody, UnsyncBoxBody}, + BodyExt, Full, +}; +use hyper::body::Incoming; +//type Bytes = Vec; // we use Vec internally everywhere - maybe try to move to Bytes.. use k8s_openapi::apimachinery::pkg::apis::meta::v1 as k8s_meta_v1; pub use kube_core::response::Status; use serde::de::DeserializeOwned; @@ -42,13 +50,13 @@ pub use tls::openssl_tls::Error as OpensslTlsError; #[cfg(feature = "rustls-tls")] pub use tls::rustls_tls::Error as RustlsTlsError; #[cfg(feature = "ws")] mod upgrade; -#[cfg(feature = "oauth")] -#[cfg_attr(docsrs, doc(cfg(feature = "oauth")))] -pub use auth::OAuthError; +//#[cfg(feature = "oauth")] +//#[cfg_attr(docsrs, doc(cfg(feature = "oauth")))] +//pub use auth::OAuthError; -#[cfg(feature = "oidc")] -#[cfg_attr(docsrs, doc(cfg(feature = "oidc")))] -pub use auth::oidc_errors; +//#[cfg(feature = "oidc")] +//#[cfg_attr(docsrs, doc(cfg(feature = "oidc")))] +//pub use auth::oidc_errors; #[cfg(feature = "ws")] pub use upgrade::UpgradeConnectionError; @@ -65,7 +73,7 @@ pub use builder::{ClientBuilder, DynBody}; pub struct Client { // - `Buffer` for cheap clone // - `BoxService` for dynamic response future type - inner: Buffer, Response, BoxError>, Request>, + inner: Buffer, Response>, BoxError>, Request>, default_ns: String, } @@ -97,17 +105,17 @@ impl Client { /// # Ok(()) /// # } /// ``` - pub fn new(service: S, default_namespace: T) -> Self + pub fn new(service: S, default_namespace: T) -> Self where - S: Service, Response = Response> + Send + 'static, + S: Service, Response = Response>> + Send + 'static, S::Future: Send + 'static, S::Error: Into, - B: http_body::Body + Send + 'static, - B::Error: Into, + //B: http_body::Body + Send + 'static, + //B::Error: Into, T: Into, { // Transform response body to `hyper::Body` and use type erased error to avoid type parameters. - let service = MapResponseBodyLayer::new(|b: B| Body::wrap_stream(b.into_stream())) + let service = MapResponseBodyLayer::new(|x| x.into_stream()) .layer(service) .map_err(|e| e.into()); Self { @@ -141,7 +149,7 @@ impl Client { /// Perform a raw HTTP request against the API and return the raw response back. /// This method can be used to get raw access to the API which may be used to, for example, /// create a proxy server or application-level gateway between localhost and the API server. - pub async fn send(&self, request: Request) -> Result> { + pub async fn send(&self, request: Request) -> Result>> { let mut svc = self.inner.clone(); let res = svc .ready() @@ -161,12 +169,13 @@ impl Client { Ok(res) } + /* /// Make WebSocket connection. #[cfg(feature = "ws")] #[cfg_attr(docsrs, doc(cfg(feature = "ws")))] pub async fn connect( &self, - request: Request>, + request: Request, ) -> Result> { use http::header::HeaderValue; let (mut parts, body) = request.into_parts(); @@ -195,7 +204,7 @@ impl Client { HeaderValue::from_static(upgrade::WS_PROTOCOL), ); - let res = self.send(Request::from_parts(parts, Body::from(body))).await?; + let res = self.send(Request::from_parts(parts, body.into())).await?; upgrade::verify_response(&res, &key).map_err(Error::UpgradeConnection)?; match hyper::upgrade::on(res).await { Ok(upgraded) => { @@ -207,14 +216,15 @@ impl Client { )), } } + */ /// Perform a raw HTTP request against the API and deserialize the response /// as JSON to some known type. - pub async fn request(&self, request: Request>) -> Result + pub async fn request(&self, request: Request) -> Result where T: DeserializeOwned, { - let text = self.request_text(request).await?; + let text = self.request_text(request.into()).await?; // TODO: must be Request serde_json::from_str(&text).map_err(|e| { tracing::warn!("{}, {:?}", text, e); @@ -224,14 +234,13 @@ impl Client { /// Perform a raw HTTP request against the API and get back the response /// as a string - pub async fn request_text(&self, request: Request>) -> Result { - let res = self.send(request.map(Body::from)).await?; + pub async fn request_text(&self, request: Request) -> Result { + let res = self.send(request.into()).await?; let status = res.status(); // trace!("Status = {:?} for {}", status, res.url()); - let body_bytes = hyper::body::to_bytes(res.into_body()) - .await - .map_err(Error::HyperError)?; - let text = String::from_utf8(body_bytes.to_vec()).map_err(Error::FromUtf8)?; + let body_bytes = res.into_body().collect().await.unwrap(); // Infallible + let bytes = body_bytes.to_bytes(); + let text = String::from_utf8(bytes.to_vec()).map_err(Error::FromUtf8)?; handle_api_errors(&text, status)?; Ok(text) @@ -241,8 +250,8 @@ impl Client { /// /// The response can be processed using [`AsyncReadExt`](futures::AsyncReadExt) /// and [`AsyncBufReadExt`](futures::AsyncBufReadExt). - pub async fn request_stream(&self, request: Request>) -> Result { - let res = self.send(request.map(Body::from)).await?; + pub async fn request_stream(&self, request: Request) -> Result { + let res = self.send(request).await?; // Map the error, since we want to convert this into an `AsyncBufReader` using // `into_async_read` which specifies `std::io::Error` as the stream's error type. let body = res @@ -253,7 +262,7 @@ impl Client { /// Perform a raw HTTP request against the API and get back either an object /// deserialized as JSON or a [`Status`] Object. - pub async fn request_status(&self, request: Request>) -> Result> + pub async fn request_status(&self, request: Request) -> Result> where T: DeserializeOwned, { @@ -277,12 +286,12 @@ impl Client { /// Perform a raw request and get back a stream of [`WatchEvent`] objects pub async fn request_events( &self, - request: Request>, + request: Request, ) -> Result>>> where T: Clone + DeserializeOwned, { - let res = self.send(request.map(Body::from)).await?; + let res = self.send(request).await?; // trace!("Streaming from {} -> {}", res.url(), res.status().as_str()); tracing::trace!("headers: {:?}", res.headers()); @@ -357,7 +366,7 @@ impl Client { self.request( Request::builder() .uri("/version") - .body(vec![]) + .body(Bytes::new()) .map_err(Error::HttpError)?, ) .await @@ -368,7 +377,7 @@ impl Client { self.request( Request::builder() .uri("/apis") - .body(vec![]) + .body(Bytes::new()) .map_err(Error::HttpError)?, ) .await @@ -397,7 +406,7 @@ impl Client { self.request( Request::builder() .uri(url) - .body(vec![]) + .body(Bytes::new()) .map_err(Error::HttpError)?, ) .await @@ -408,7 +417,7 @@ impl Client { self.request( Request::builder() .uri("/api") - .body(vec![]) + .body(Bytes::new()) .map_err(Error::HttpError)?, ) .await @@ -420,7 +429,7 @@ impl Client { self.request( Request::builder() .uri(url) - .body(vec![]) + .body(Bytes::new()) .map_err(Error::HttpError)?, ) .await diff --git a/kube-client/src/client/tls.rs b/kube-client/src/client/tls.rs index 45785a8c9..ddf42f0e0 100644 --- a/kube-client/src/client/tls.rs +++ b/kube-client/src/client/tls.rs @@ -3,8 +3,9 @@ pub mod rustls_tls { use hyper_rustls::ConfigBuilderExt; use rustls::{ self, - client::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}, - Certificate, ClientConfig, DigitallySignedStruct, PrivateKey, + client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}, + pki_types::{CertificateDer, PrivateKeyDer, ServerName, UnixTime}, + ClientConfig, DigitallySignedStruct, SignatureScheme, }; use thiserror::Error; @@ -27,6 +28,10 @@ pub mod rustls_tls { #[error("invalid private key: {0}")] InvalidPrivateKey(#[source] rustls::Error), + /// Invalid native roots + #[error("invalid native roots: {0}")] + InvalidNativeRoots(#[source] std::io::Error), + /// Unknown private key format #[error("unknown private key format")] UnknownPrivateKeyFormat, @@ -44,11 +49,11 @@ pub mod rustls_tls { accept_invalid: bool, ) -> Result { let config_builder = if let Some(certs) = root_certs { - ClientConfig::builder() - .with_safe_defaults() - .with_root_certificates(root_store(certs)?) + ClientConfig::builder().with_root_certificates(root_store(certs)?) } else { - ClientConfig::builder().with_safe_defaults().with_native_roots() + ClientConfig::builder() + .with_native_roots() + .map_err(Error::InvalidNativeRoots)? }; let mut client_config = if let Some((chain, pkey)) = identity_pem.map(client_auth).transpose()? { @@ -71,13 +76,13 @@ pub mod rustls_tls { let mut root_store = rustls::RootCertStore::empty(); for der in root_certs { root_store - .add(&Certificate(der.clone())) + .add(CertificateDer::from(der.clone())) .map_err(|e| Error::AddRootCertificate(Box::new(e)))?; } Ok(root_store) } - fn client_auth(data: &[u8]) -> Result<(Vec, PrivateKey), Error> { + fn client_auth(data: &[u8]) -> Result<(Vec, PrivateKeyDer), Error> { use rustls_pemfile::Item; let mut cert_chain = Vec::new(); @@ -85,12 +90,13 @@ pub mod rustls_tls { let mut rsa_key = None; let mut ec_key = None; let mut reader = std::io::Cursor::new(data); - for item in rustls_pemfile::read_all(&mut reader).map_err(Error::InvalidIdentityPem)? { + for res in rustls_pemfile::read_all(&mut reader) { + let item = res.map_err(Error::InvalidIdentityPem)?; match item { - Item::X509Certificate(cert) => cert_chain.push(Certificate(cert)), - Item::PKCS8Key(key) => pkcs8_key = Some(PrivateKey(key)), - Item::RSAKey(key) => rsa_key = Some(PrivateKey(key)), - Item::ECKey(key) => ec_key = Some(PrivateKey(key)), + Item::X509Certificate(cert) => cert_chain.push(CertificateDer::from(cert)), + Item::Pkcs8Key(key) => pkcs8_key = Some(PrivateKeyDer::Pkcs8(key)), + Item::Pkcs1Key(key) => rsa_key = Some(PrivateKeyDer::Pkcs1(key)), + Item::Sec1Key(key) => ec_key = Some(PrivateKeyDer::Sec1(key)), _ => return Err(Error::UnknownPrivateKeyFormat), } } @@ -102,17 +108,17 @@ pub mod rustls_tls { Ok((cert_chain, private_key)) } + #[derive(Debug)] struct NoCertificateVerification {} impl ServerCertVerifier for NoCertificateVerification { fn verify_server_cert( &self, - _end_entity: &Certificate, - _intermediates: &[Certificate], - _server_name: &rustls::client::ServerName, - _scts: &mut dyn Iterator, + _end_entity: &CertificateDer<'_>, + _intermediates: &[CertificateDer<'_>], + _server_name: &ServerName, _ocsp_response: &[u8], - _now: std::time::SystemTime, + _now: UnixTime, ) -> Result { tracing::warn!("Server cert bypassed"); Ok(ServerCertVerified::assertion()) @@ -121,7 +127,7 @@ pub mod rustls_tls { fn verify_tls13_signature( &self, _message: &[u8], - _cert: &Certificate, + _cert: &CertificateDer, _dss: &DigitallySignedStruct, ) -> Result { Ok(HandshakeSignatureValid::assertion()) @@ -130,11 +136,15 @@ pub mod rustls_tls { fn verify_tls12_signature( &self, _message: &[u8], - _cert: &Certificate, + _cert: &CertificateDer, _dss: &DigitallySignedStruct, ) -> Result { Ok(HandshakeSignatureValid::assertion()) } + + fn supported_verify_schemes(&self) -> Vec { + vec![] + } } } diff --git a/kube-client/src/client/upgrade.rs b/kube-client/src/client/upgrade.rs index e8fe67c5c..4ae62ef28 100644 --- a/kube-client/src/client/upgrade.rs +++ b/kube-client/src/client/upgrade.rs @@ -1,5 +1,7 @@ +#![allow(unused_imports)] // TODO: remove use http::{self, Response, StatusCode}; -use hyper::Body; +use http_body_util::{combinators::BoxBody, BodyStream}; +type VerifyBody = BoxBody, tower::BoxError>; use thiserror::Error; use tokio_tungstenite::tungstenite as ws; @@ -41,7 +43,7 @@ pub enum UpgradeConnectionError { // Verify upgrade response according to RFC6455. // Based on `tungstenite` and added subprotocol verification. -pub fn verify_response(res: &Response, key: &str) -> Result<(), UpgradeConnectionError> { +pub fn verify_response(res: &Response, key: &str) -> Result<(), UpgradeConnectionError> { if res.status() != StatusCode::SWITCHING_PROTOCOLS { return Err(UpgradeConnectionError::ProtocolSwitch(res.status())); } diff --git a/kube-core/Cargo.toml b/kube-core/Cargo.toml index 9fe9d12e2..2fc4d5136 100644 --- a/kube-core/Cargo.toml +++ b/kube-core/Cargo.toml @@ -29,7 +29,7 @@ serde = { version = "1.0.130", features = ["derive"] } serde_json = "1.0.68" thiserror = "1.0.29" form_urlencoded = "1.0.1" -http = "0.2.5" +http = "1.0.0" json-patch = { version = "1.0.0", optional = true } once_cell = "1.8.0" chrono = { version = "0.4.19", default-features = false, features = ["clock"] } diff --git a/kube/Cargo.toml b/kube/Cargo.toml index 484fa2389..b094795a6 100644 --- a/kube/Cargo.toml +++ b/kube/Cargo.toml @@ -61,8 +61,8 @@ futures = "0.3.17" serde_json = "1.0.68" serde = { version = "1.0.130", features = ["derive"] } schemars = "0.8.6" -hyper = "0.14.27" -http = "0.2.9" +hyper = "1.1.0" +http = "1.0.0" tower-test = "0.4.0" anyhow = "1.0.71"