[pbs-devel] [PATCH proxmox-backup v2] config: check if acme domain with wildcard uses dns challenge

Gabriel Goller g.goller at proxmox.com
Wed Sep 18 14:06:40 CEST 2024


As already mentioned in our docs [0], wildcard domains are only
supported when the dns-challenge is used. If the dns-challenge is not
used, throw an error.

[0]: https://pbs.proxmox.com/docs/sysadmin.html#wildcard-certificates

Signed-off-by: Gabriel Goller <g.goller at proxmox.com>
---

v2, thanks @Christian:
 - fixed configuration matching with wildcard
 - adjusted error message

 src/api2/node/certificates.rs | 18 +++++++++++++++---
 src/config/node.rs            | 10 ++++++++++
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/src/api2/node/certificates.rs b/src/api2/node/certificates.rs
index 61ef910e47a7..4b2952feb8bd 100644
--- a/src/api2/node/certificates.rs
+++ b/src/api2/node/certificates.rs
@@ -294,10 +294,22 @@ async fn order_certificate(
         },
     )?;
 
-    let get_domain_config = |domain: &str| {
+    let get_domain_config = |domain: &str, wildcard: bool| {
         domains
             .iter()
-            .find(|d| d.domain == domain)
+            .find(|d| {
+                if !wildcard {
+                    // fast-path, no matching required
+                    d.domain == domain
+                } else {
+                    // https://community.letsencrypt.org/t/acme-v2-production-environment-wildcards/55578
+                    // DNS names in certificates may only have a single wildcard character, and it must
+                    // be the entire leftmost DNS label, f.e. *.example.com
+                    d.domain
+                        .strip_prefix("*.")
+                        .map_or(false, |stripped| domain == stripped)
+                }
+            })
             .ok_or_else(|| format_err!("no config for domain '{}'", domain))
     };
 
@@ -339,7 +351,7 @@ async fn order_certificate(
         }
 
         info!("The validation for {domain} is pending");
-        let domain_config: &AcmeDomain = get_domain_config(&domain)?;
+        let domain_config: &AcmeDomain = get_domain_config(&domain, auth.wildcard)?;
         let plugin_id = domain_config.plugin.as_deref().unwrap_or("standalone");
         let mut plugin_cfg = crate::acme::get_acme_plugin(&plugins, plugin_id)?
             .ok_or_else(|| format_err!("plugin '{plugin_id}' for domain '{domain}' not found!"))?;
diff --git a/src/config/node.rs b/src/config/node.rs
index 937beb3a125c..59faf3576b8a 100644
--- a/src/config/node.rs
+++ b/src/config/node.rs
@@ -272,6 +272,16 @@ impl NodeConfig {
             if !domains.insert(domain.domain.to_lowercase()) {
                 bail!("duplicate domain '{}' in ACME config", domain.domain);
             }
+            if domain.domain.contains('*')
+                && domain.plugin.map_or(true, |value| {
+                    value.as_str() == "" || value.as_str() == "standalone"
+                })
+            {
+                bail!(
+                    "wildcard domains like '{}' are not usable with the HTTP challenge type",
+                    domain.domain
+                );
+            }
         }
         let mut dummy_acceptor = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).unwrap();
         if let Some(ciphers) = self.ciphers_tls_1_3.as_deref() {
-- 
2.39.5





More information about the pbs-devel mailing list