aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2021-12-08 23:45:24 +0100
committerAlex Auvolat <alex@adnab.me>2021-12-08 23:45:24 +0100
commit207f467b879194c993c70a092c232daca8ad1057 (patch)
tree118c8940e2d9d37400219335263f1ec9c1c94d2d
parentca8c5aad2378dd9f8ec525b3b0779f5c53cfe9eb (diff)
downloadtricot-207f467b879194c993c70a092c232daca8ad1057.tar.gz
tricot-207f467b879194c993c70a092c232daca8ad1057.zip
Support totally ignoring backend HTTPS certificate stuff
-rw-r--r--Cargo.toml2
-rw-r--r--Dockerfile2
-rw-r--r--src/cert_store.rs2
-rw-r--r--src/main.rs1
-rw-r--r--src/reverse_proxy.rs43
-rw-r--r--src/tls_util.rs79
6 files changed, 117 insertions, 12 deletions
diff --git a/Cargo.toml b/Cargo.toml
index aa1b4fb..2130197 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,7 +19,7 @@ serde_json = "1.0.53"
tokio = { version = "1.0", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros", "sync", "signal", "fs"] }
bytes = "1"
acme-micro = "0.12"
-rustls = "0.20"
+rustls = { version = "0.20", features = [ "dangerous_configuration" ] }
rustls-pemfile = "0.2"
chrono = { version = "0.4", features = [ "serde" ] }
hyper = { version = "0.14", features = [ "full" ] }
diff --git a/Dockerfile b/Dockerfile
index ebda1fc..41df609 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -18,6 +18,6 @@ COPY ./src ./src
RUN cargo build --release
FROM debian:bullseye-slim
-RUN apt-get update && apt-get install -y libssl1.1 iptables
+RUN apt-get update && apt-get install -y libssl1.1 iptables ca-certificates
COPY --from=builder /srv/target/release/tricot /usr/local/sbin/tricot
CMD ["/usr/local/sbin/tricot"]
diff --git a/src/cert_store.rs b/src/cert_store.rs
index ced9966..fe2f8b0 100644
--- a/src/cert_store.rs
+++ b/src/cert_store.rs
@@ -56,8 +56,8 @@ impl CertStore {
}
}
+ debug!("Ensuring we have certs for domains: {:#?}", domains);
for dom in domains.iter() {
- info!("Ensuring we have certs for domains: {:?}", domains);
if let Err(e) = self.get_cert(dom).await {
warn!("Error get_cert {}: {}", dom, e);
}
diff --git a/src/main.rs b/src/main.rs
index 987c3ec..1fffcbc 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,6 +5,7 @@ use futures::TryFutureExt;
use std::net::SocketAddr;
use structopt::StructOpt;
+mod tls_util;
mod cert;
mod cert_store;
mod consul;
diff --git a/src/reverse_proxy.rs b/src/reverse_proxy.rs
index 9d7780c..82e7c7a 100644
--- a/src/reverse_proxy.rs
+++ b/src/reverse_proxy.rs
@@ -1,16 +1,23 @@
//! Copied from https://github.com/felipenoris/hyper-reverse-proxy
//! See there for original Copyright notice
+use std::sync::Arc;
+use std::convert::TryInto;
+use std::time::SystemTime;
+use std::net::IpAddr;
+use std::str::FromStr;
+
use anyhow::Result;
use log::*;
-use std::convert::TryInto;
use http::header::HeaderName;
use hyper::header::{HeaderMap, HeaderValue};
use hyper::{Body, Client, Request, Response, Uri};
+use rustls::{Certificate, ServerName};
+use rustls::client::{ServerCertVerifier, ServerCertVerified};
use lazy_static::lazy_static;
-use std::net::IpAddr;
-use std::str::FromStr;
+
+use crate::tls_util::HttpsConnectorFixedDnsname;
fn is_hop_header(name: &str) -> bool {
use unicase::Ascii;
@@ -149,12 +156,12 @@ pub async fn call_https(
trace!("Proxied request (HTTPS): {:?}", proxied_request);
- let https = hyper_rustls::HttpsConnectorBuilder::new()
- .with_native_roots()
- .https_only()
- .enable_http1()
- .build();
- let client: Client<_, hyper::Body> = Client::builder().build(https);
+ let tls_config = rustls::client::ClientConfig::builder()
+ .with_safe_defaults()
+ .with_custom_certificate_verifier(Arc::new(DontVerifyServerCert))
+ .with_no_client_auth();
+ let connector = HttpsConnectorFixedDnsname::new(tls_config, "dummy");
+ let client: Client<_, hyper::Body> = Client::builder().build(connector);
let response = client.request(proxied_request).await?;
trace!("Inner response (HTTPS): {:?}", response);
@@ -162,3 +169,21 @@ pub async fn call_https(
let proxied_response = create_proxied_response(response);
Ok(proxied_response)
}
+
+struct DontVerifyServerCert;
+
+impl ServerCertVerifier for DontVerifyServerCert {
+ fn verify_server_cert(
+ &self,
+ _end_entity: &Certificate,
+ _intermediates: &[Certificate],
+ _server_name: &ServerName,
+ _scts: &mut dyn Iterator<Item = &[u8]>,
+ _ocsp_response: &[u8],
+ _now: SystemTime
+ ) -> Result<ServerCertVerified, rustls::Error> {
+ Ok(ServerCertVerified::assertion())
+ }
+}
+
+
diff --git a/src/tls_util.rs b/src/tls_util.rs
new file mode 100644
index 0000000..054c35a
--- /dev/null
+++ b/src/tls_util.rs
@@ -0,0 +1,79 @@
+use core::future::Future;
+use core::task::{Context, Poll};
+use std::convert::TryFrom;
+use std::pin::Pin;
+use std::sync::Arc;
+use std::io;
+
+use futures_util::future::*;
+use rustls::ServerName;
+use hyper::client::connect::Connection;
+use hyper::client::HttpConnector;
+use hyper::service::Service;
+use hyper::Uri;
+use hyper_rustls::MaybeHttpsStream;
+use tokio::io::{AsyncRead, AsyncWrite};
+use tokio_rustls::TlsConnector;
+
+
+#[derive(Clone)]
+pub struct HttpsConnectorFixedDnsname<T> {
+ http: T,
+ tls_config: Arc<rustls::ClientConfig>,
+ fixed_dnsname: &'static str,
+}
+type BoxError = Box<dyn std::error::Error + Send + Sync>;
+impl HttpsConnectorFixedDnsname<HttpConnector> {
+ pub fn new(mut tls_config: rustls::ClientConfig, fixed_dnsname: &'static str) -> Self {
+ let mut http = HttpConnector::new();
+ http.enforce_http(false);
+ tls_config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
+ Self {
+ http,
+ tls_config: Arc::new(tls_config),
+ fixed_dnsname,
+ }
+ }
+}
+impl<T> Service<Uri> for HttpsConnectorFixedDnsname<T>
+where
+ T: Service<Uri>,
+ T::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static,
+ T::Future: Send + 'static,
+ T::Error: Into<BoxError>,
+{
+ type Response = MaybeHttpsStream<T::Response>;
+ type Error = BoxError;
+ #[allow(clippy::type_complexity)]
+ type Future =
+ Pin<Box<dyn Future<Output = Result<MaybeHttpsStream<T::Response>, BoxError>> + Send>>;
+
+ fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
+ match self.http.poll_ready(cx) {
+ Poll::Ready(Ok(())) => Poll::Ready(Ok(())),
+ Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())),
+ Poll::Pending => Poll::Pending,
+ }
+ }
+
+ fn call(&mut self, dst: Uri) -> Self::Future {
+ let is_https = dst.scheme_str() == Some("https");
+ assert!(is_https);
+
+ let cfg = self.tls_config.clone();
+ let connecting_future = self.http.call(dst);
+ let dnsname =
+ ServerName::try_from(self.fixed_dnsname).expect("Invalid fixed dnsname");
+ let f = async move {
+ let tcp = connecting_future.await.map_err(Into::into)?;
+ let connector = TlsConnector::from(cfg);
+ let tls = connector
+ .connect(dnsname, tcp)
+ .await
+ .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
+ Ok(MaybeHttpsStream::Https(tls))
+ };
+ f.boxed()
+ }
+}
+