forked from Deuxfleurs/tricot
Support totally ignoring backend HTTPS certificate stuff
This commit is contained in:
parent
ca8c5aad23
commit
207f467b87
6 changed files with 117 additions and 12 deletions
|
@ -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"] }
|
tokio = { version = "1.0", default-features = false, features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros", "sync", "signal", "fs"] }
|
||||||
bytes = "1"
|
bytes = "1"
|
||||||
acme-micro = "0.12"
|
acme-micro = "0.12"
|
||||||
rustls = "0.20"
|
rustls = { version = "0.20", features = [ "dangerous_configuration" ] }
|
||||||
rustls-pemfile = "0.2"
|
rustls-pemfile = "0.2"
|
||||||
chrono = { version = "0.4", features = [ "serde" ] }
|
chrono = { version = "0.4", features = [ "serde" ] }
|
||||||
hyper = { version = "0.14", features = [ "full" ] }
|
hyper = { version = "0.14", features = [ "full" ] }
|
||||||
|
|
|
@ -18,6 +18,6 @@ COPY ./src ./src
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
|
|
||||||
FROM debian:bullseye-slim
|
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
|
COPY --from=builder /srv/target/release/tricot /usr/local/sbin/tricot
|
||||||
CMD ["/usr/local/sbin/tricot"]
|
CMD ["/usr/local/sbin/tricot"]
|
||||||
|
|
|
@ -56,8 +56,8 @@ impl CertStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug!("Ensuring we have certs for domains: {:#?}", domains);
|
||||||
for dom in domains.iter() {
|
for dom in domains.iter() {
|
||||||
info!("Ensuring we have certs for domains: {:?}", domains);
|
|
||||||
if let Err(e) = self.get_cert(dom).await {
|
if let Err(e) = self.get_cert(dom).await {
|
||||||
warn!("Error get_cert {}: {}", dom, e);
|
warn!("Error get_cert {}: {}", dom, e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ use futures::TryFutureExt;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
mod tls_util;
|
||||||
mod cert;
|
mod cert;
|
||||||
mod cert_store;
|
mod cert_store;
|
||||||
mod consul;
|
mod consul;
|
||||||
|
|
|
@ -1,16 +1,23 @@
|
||||||
//! Copied from https://github.com/felipenoris/hyper-reverse-proxy
|
//! Copied from https://github.com/felipenoris/hyper-reverse-proxy
|
||||||
//! See there for original Copyright notice
|
//! 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 anyhow::Result;
|
||||||
use log::*;
|
use log::*;
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
use http::header::HeaderName;
|
use http::header::HeaderName;
|
||||||
use hyper::header::{HeaderMap, HeaderValue};
|
use hyper::header::{HeaderMap, HeaderValue};
|
||||||
use hyper::{Body, Client, Request, Response, Uri};
|
use hyper::{Body, Client, Request, Response, Uri};
|
||||||
|
use rustls::{Certificate, ServerName};
|
||||||
|
use rustls::client::{ServerCertVerifier, ServerCertVerified};
|
||||||
use lazy_static::lazy_static;
|
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 {
|
fn is_hop_header(name: &str) -> bool {
|
||||||
use unicase::Ascii;
|
use unicase::Ascii;
|
||||||
|
@ -149,12 +156,12 @@ pub async fn call_https(
|
||||||
|
|
||||||
trace!("Proxied request (HTTPS): {:?}", proxied_request);
|
trace!("Proxied request (HTTPS): {:?}", proxied_request);
|
||||||
|
|
||||||
let https = hyper_rustls::HttpsConnectorBuilder::new()
|
let tls_config = rustls::client::ClientConfig::builder()
|
||||||
.with_native_roots()
|
.with_safe_defaults()
|
||||||
.https_only()
|
.with_custom_certificate_verifier(Arc::new(DontVerifyServerCert))
|
||||||
.enable_http1()
|
.with_no_client_auth();
|
||||||
.build();
|
let connector = HttpsConnectorFixedDnsname::new(tls_config, "dummy");
|
||||||
let client: Client<_, hyper::Body> = Client::builder().build(https);
|
let client: Client<_, hyper::Body> = Client::builder().build(connector);
|
||||||
let response = client.request(proxied_request).await?;
|
let response = client.request(proxied_request).await?;
|
||||||
|
|
||||||
trace!("Inner response (HTTPS): {:?}", response);
|
trace!("Inner response (HTTPS): {:?}", response);
|
||||||
|
@ -162,3 +169,21 @@ pub async fn call_https(
|
||||||
let proxied_response = create_proxied_response(response);
|
let proxied_response = create_proxied_response(response);
|
||||||
Ok(proxied_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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
79
src/tls_util.rs
Normal file
79
src/tls_util.rs
Normal file
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue