Implement glob pattern hostnames

no wildcard certificates: one certificate per matching hostname that
actually recieves requests
This commit is contained in:
Alex 2021-12-08 11:11:22 +01:00
parent 11c6f0b1c2
commit 098a6cf2cd
No known key found for this signature in database
GPG Key ID: EDABF9711E244EB1
5 changed files with 48 additions and 7 deletions

7
Cargo.lock generated
View File

@ -472,6 +472,12 @@ dependencies = [
"wasi",
]
[[package]]
name = "glob"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "h2"
version = "0.1.26"
@ -1880,6 +1886,7 @@ dependencies = [
"envy",
"futures 0.3.18",
"futures-util",
"glob",
"http 0.2.5",
"hyper 0.14.15",
"hyper-reverse-proxy",

View File

@ -31,3 +31,4 @@ hyper-reverse-proxy = "0.4"
unicase = "2"
lazy_static = "1.4"
structopt = "0.3"
glob = "0.3"

View File

@ -14,7 +14,7 @@ use rustls::sign::CertifiedKey;
use crate::cert::{Cert, CertSer};
use crate::consul::*;
use crate::proxy_config::ProxyConfig;
use crate::proxy_config::*;
pub struct CertStore {
consul: Consul,
@ -39,11 +39,13 @@ impl CertStore {
let proxy_config: Arc<ProxyConfig> = rx_proxy_config.borrow().clone();
for ent in proxy_config.entries.iter() {
domains.insert(ent.host.clone());
if let HostDescription::Hostname(domain) = &ent.host {
domains.insert(domain.clone());
}
}
info!("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);
}
@ -58,7 +60,7 @@ impl CertStore {
.borrow()
.entries
.iter()
.any(|ent| ent.host == domain)
.any(|ent| ent.host.matches(domain))
{
bail!("Domain {} should not have a TLS certificate.", domain);
}

View File

@ -93,7 +93,7 @@ async fn handle(
.entries
.iter()
.filter(|ent| {
ent.host == host
ent.host.matches(host)
&& ent
.path_prefix
.as_ref()

View File

@ -15,11 +15,34 @@ use crate::consul::*;
// ---- Extract proxy config from Consul catalog ----
#[derive(Debug)]
pub enum HostDescription {
Hostname(String),
Pattern(glob::Pattern),
}
impl HostDescription {
fn new(desc: &str) -> Result<Self> {
if desc.chars().any(|x| matches!(x, '*' | '?' | '[' | ']')) {
Ok(Self::Pattern(glob::Pattern::new(desc)?))
} else {
Ok(Self::Hostname(desc.to_string()))
}
}
pub fn matches(&self, v: &str) -> bool {
match self {
Self::Pattern(p) => p.matches(v),
Self::Hostname(s) => s == v,
}
}
}
#[derive(Debug)]
pub struct ProxyEntry {
pub target_addr: SocketAddr,
pub host: String,
pub host: HostDescription,
pub path_prefix: Option<String>,
pub priority: u32,
pub add_headers: Vec<(String, String)>,
@ -65,9 +88,17 @@ fn parse_tricot_tag(
_ => 100,
};
let host = match HostDescription::new(host) {
Ok(h) => h,
Err(e) => {
warn!("Invalid hostname pattern {}: {}", host, e);
return None;
}
};
Some(ProxyEntry {
target_addr,
host: host.to_string(),
host,
path_prefix,
priority,
add_headers: add_headers.to_vec(),