Skip to content

Suggestion: sni-certs folder auto-scan + optional hostnames #115

@DisasteR

Description

@DisasteR

Problem Statement

Current sni-cert blocks require mandatory hostnames + individual file paths, making it cumbersome to manage folders containing many dynamically generated domain.crt/domain.key pairs from PKI agents or automation workflows.

HAProxy's ssl crt /path/ has long supported automatic folder scanning, CN/SAN extraction, and most-specific SNI selection - a production-proven approach for DevOps scalability.

Proposed Solution

1. New sni-certs block for folder auto-scan (within additional-certs)

sni-certs {
    cert-folder "/etc/zentinel/certs/dynamic/"     // Scans *.crt + matching *.key pairs (fullchain .crt)
    reload-mode "interval"                        // "off" | "interval" | "inotify" 
    reload-interval "30s"                         // Only if reload-mode="interval"
}

2. Make hostnames optional in existing sni-cert (auto CN/SAN fallback)

sni-cert {
    cert-file "/premium.crt"                      // CN=*.premium.com SAN=api.example.com  
    key-file "/premium.key"
    // hostnames auto-extracted from CN/SAN if not specified
}

Complete TLS Configuration Example

listener "https" {
    address "0.0.0.0:443"
    protocol "https"
    tls {
        // 1. MANUAL DEFAULT (highest priority if present, blocks ACME)
        cert-file "/etc/zentinel/certs/manual-default.crt"
        key-file "/etc/zentinel/certs/manual-default.key"

        // ACME automatic (fallback/domains-specific, used only if no manual)
        acme {
            email "admin@example.com"
            domains "auto.example.com" "newshop.com"
        }

        additional-certs {
            // PRIORITY 3: SNI-CERT WITH explicit hostnames
            sni-cert {
                hostnames "api.example.com" "direct.api.example.com"
                cert-file "/etc/zentinel/certs/api-explicit.crt"
                key-file "/etc/zentinel/certs/api-explicit.key"
            }

            // PRIORITY 4: SNI-CERT WITHOUT hostnames (auto CN/SAN)
            sni-cert {
                cert-file "/etc/zentinel/certs/premium-auto.crt"    // CN=*.premium.com SAN=www.example.com
                key-file "/etc/zentinel/certs/premium-auto.key"
            }

            // PRIORITY 5: SNI-CERTS FOLDER AUTO-SCAN (NEW)
            sni-certs {
                cert-folder "/etc/zentinel/certs/dynamic/"
                reload-mode "interval"
                reload-interval "30s"
            }
        }
    }
}

/etc/zentinel/certs/dynamic/ folder contents:

api-dynamic.crt      (CN=api.example.com)
premium-dynamic.crt  (CN=*.premium.com, SAN=beta.example.com)
wildcard-dynamic.crt (CN=*.example.com)

SNI Selection Results

Requested SNI Selected Certificate Priority Reason
api.example.com api-explicit.crt #3 Exact hostnames match
direct.api.example.com api-explicit.crt #3 hostnames pattern match
www.example.com premium-auto.crt #4 SNI in SAN of auto sni-cert
app.premium.com premium-auto.crt #4 SNI in CN of auto sni-cert
beta.example.com premium-dynamic.crt #5 SNI in SAN of folder scan
static.example.com wildcard-dynamic.crt #5 *.example.com longest-prefix
shop.auto.example.com ACME cert #6 ACME domains match
newshop.com ACME cert #6 ACME domains match (no higher)
unknown.com manual-default.crt #1 Default manual cert

Processing Priority Order

1. manual cert-file/key-file (blocks everything else including ACME)
2. sni-cert { hostnames SNI in patterns } → explicit priority
3. sni-cert {} SNI in CN/SAN → auto cert CN/SAN  
4. sni-certs folder SNI in CN/SAN → folder auto-scan
5. ACME (SNI in acme.domains only if no higher match)
6. FALLBACK Default manual cert (possible TLS handshake fails on validation)

Detailed Auto CN/SAN Behavior

  • sni-certs { cert-folder }: Scans folder for <name>.crt + <name>.key pairs, parses each .crt CN/SAN → builds hostname→cert index
  • sni-cert without hostnames: Parses single cert CN/SAN → indexes that cert for those hostnames
  • sni-cert WITH hostnames: 1) SNI matches pattern → use cert (priority), 2) OR SNI in CN/SAN → use cert anyway

Benefits: Zero-config PKI folders, full ACME compatibility, HAProxy-like simplicity, production-ready reload modes (kill -HUP + inotify/interval).

Alternatives Considered

No response

Where does this belong?

Configuration option

Manifesto Alignment

  • This feature can be bounded (has clear limits)
  • This feature can be observed (metrics, logs)
  • This feature can fail safely (explicit failure modes)
  • This feature does not add implicit behavior

Checklist

  • I have searched existing issues for duplicates
  • I have read the Manifesto

Metadata

Metadata

Labels

area:configConfiguration (sentinel-config)effort:large3+ days, architectural impactscope:kdlKDL configuration syntaxtype:featureNew functionality request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions