Implement glob pattern hostnames
no wildcard certificates: one certificate per matching hostname that actually recieves requests
This commit is contained in:
parent
11c6f0b1c2
commit
098a6cf2cd
5 changed files with 48 additions and 7 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -472,6 +472,12 @@ dependencies = [
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.1.26"
|
version = "0.1.26"
|
||||||
|
@ -1880,6 +1886,7 @@ dependencies = [
|
||||||
"envy",
|
"envy",
|
||||||
"futures 0.3.18",
|
"futures 0.3.18",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"glob",
|
||||||
"http 0.2.5",
|
"http 0.2.5",
|
||||||
"hyper 0.14.15",
|
"hyper 0.14.15",
|
||||||
"hyper-reverse-proxy",
|
"hyper-reverse-proxy",
|
||||||
|
|
|
@ -31,3 +31,4 @@ hyper-reverse-proxy = "0.4"
|
||||||
unicase = "2"
|
unicase = "2"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
structopt = "0.3"
|
structopt = "0.3"
|
||||||
|
glob = "0.3"
|
||||||
|
|
|
@ -14,7 +14,7 @@ use rustls::sign::CertifiedKey;
|
||||||
|
|
||||||
use crate::cert::{Cert, CertSer};
|
use crate::cert::{Cert, CertSer};
|
||||||
use crate::consul::*;
|
use crate::consul::*;
|
||||||
use crate::proxy_config::ProxyConfig;
|
use crate::proxy_config::*;
|
||||||
|
|
||||||
pub struct CertStore {
|
pub struct CertStore {
|
||||||
consul: Consul,
|
consul: Consul,
|
||||||
|
@ -39,11 +39,13 @@ impl CertStore {
|
||||||
|
|
||||||
let proxy_config: Arc<ProxyConfig> = rx_proxy_config.borrow().clone();
|
let proxy_config: Arc<ProxyConfig> = rx_proxy_config.borrow().clone();
|
||||||
for ent in proxy_config.entries.iter() {
|
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() {
|
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);
|
||||||
}
|
}
|
||||||
|
@ -58,7 +60,7 @@ impl CertStore {
|
||||||
.borrow()
|
.borrow()
|
||||||
.entries
|
.entries
|
||||||
.iter()
|
.iter()
|
||||||
.any(|ent| ent.host == domain)
|
.any(|ent| ent.host.matches(domain))
|
||||||
{
|
{
|
||||||
bail!("Domain {} should not have a TLS certificate.", domain);
|
bail!("Domain {} should not have a TLS certificate.", domain);
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ async fn handle(
|
||||||
.entries
|
.entries
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|ent| {
|
.filter(|ent| {
|
||||||
ent.host == host
|
ent.host.matches(host)
|
||||||
&& ent
|
&& ent
|
||||||
.path_prefix
|
.path_prefix
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
|
@ -15,11 +15,34 @@ use crate::consul::*;
|
||||||
|
|
||||||
// ---- Extract proxy config from Consul catalog ----
|
// ---- 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)]
|
#[derive(Debug)]
|
||||||
pub struct ProxyEntry {
|
pub struct ProxyEntry {
|
||||||
pub target_addr: SocketAddr,
|
pub target_addr: SocketAddr,
|
||||||
|
|
||||||
pub host: String,
|
pub host: HostDescription,
|
||||||
pub path_prefix: Option<String>,
|
pub path_prefix: Option<String>,
|
||||||
pub priority: u32,
|
pub priority: u32,
|
||||||
pub add_headers: Vec<(String, String)>,
|
pub add_headers: Vec<(String, String)>,
|
||||||
|
@ -65,9 +88,17 @@ fn parse_tricot_tag(
|
||||||
_ => 100,
|
_ => 100,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let host = match HostDescription::new(host) {
|
||||||
|
Ok(h) => h,
|
||||||
|
Err(e) => {
|
||||||
|
warn!("Invalid hostname pattern {}: {}", host, e);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Some(ProxyEntry {
|
Some(ProxyEntry {
|
||||||
target_addr,
|
target_addr,
|
||||||
host: host.to_string(),
|
host,
|
||||||
path_prefix,
|
path_prefix,
|
||||||
priority,
|
priority,
|
||||||
add_headers: add_headers.to_vec(),
|
add_headers: add_headers.to_vec(),
|
||||||
|
|
Loading…
Reference in a new issue