mirror of
https://github.com/netbirdio/plugins.git
synced 2026-05-22 18:44:07 -07:00
www/caddy: Change template generation of wildcard+subdomain pattern to support ECH and mTLS (#4673)
* www/caddy: Change wildcard domain with subdomain pattern to align with caddy-v2.10.0 * www/caddy: Allow Client Auth (mTLS) inside subdomains as supported by new wildcard domain and subdomain pattern * www/caddy: Add encrypted client hello (ECH)
This commit is contained in:
@@ -81,4 +81,23 @@
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
</field>
|
||||
<field>
|
||||
<id>subdomain.ClientAuthTrustPool</id>
|
||||
<label>Client Auth Trust Pool</label>
|
||||
<type>select_multiple</type>
|
||||
<help><![CDATA[Choose multiple CAs or self-signed certificates from "System - Trust - Authorities". Client Auth is activated as soon as at least one certificate has been chosen. Important: Certificate revocation lists are not evaluated. If you need granular control, provide individual self-signed certificates for each device, and unset them to block access. Though keep in mind that if no certificate is left in this field, Client Auth will be deactivated.]]></help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
</field>
|
||||
<field>
|
||||
<id>subdomain.ClientAuthMode</id>
|
||||
<label>Client Auth Mode</label>
|
||||
<type>dropdown</type>
|
||||
<advanced>true</advanced>
|
||||
<help><![CDATA["request" - Ask clients for a certificate, but allow even if there isn't one; do not verify it. "require" - Require clients to present a certificate, but do not verify it. "verify_if_given" - Ask clients for a certificate; allow even if there isn't one, but verify it if there is. "require_and_verify" - Require clients to present a valid certificate that is verified.]]></help>
|
||||
<grid_view>
|
||||
<visible>false</visible>
|
||||
</grid_view>
|
||||
</field>
|
||||
</form>
|
||||
|
||||
@@ -180,6 +180,16 @@
|
||||
<hint>0</hint>
|
||||
<help><![CDATA[propagation_delay is a duration value in seconds that sets how long to wait before starting DNS TXT records propagation checks when using the DNS challenge.]]></help>
|
||||
</field>
|
||||
<field>
|
||||
<type>header</type>
|
||||
<label>ECH</label>
|
||||
</field>
|
||||
<field>
|
||||
<id>caddy.general.TlsDnsEchDomain</id>
|
||||
<label>ECH Domain</label>
|
||||
<type>text</type>
|
||||
<help><![CDATA[Enables Encrypted ClientHello (ECH) by using the specified public domain name as the plaintext server name (SNI) in TLS handshakes. More information: https://caddyserver.com/docs/caddyfile/options#ech]]></help>
|
||||
</field>
|
||||
</tab>
|
||||
<tab id="general-dynamicdns" description="Dynamic DNS">
|
||||
<field>
|
||||
|
||||
@@ -109,6 +109,9 @@
|
||||
<TlsDnsPropagationResolvers type="NetworkField">
|
||||
<NetMaskAllowed>N</NetMaskAllowed>
|
||||
</TlsDnsPropagationResolvers>
|
||||
<TlsDnsEchDomain type="HostnameField">
|
||||
<IpAllowed>N</IpAllowed>
|
||||
</TlsDnsEchDomain>
|
||||
<accesslist type="ModelRelationField">
|
||||
<Model>
|
||||
<reverseproxy>
|
||||
@@ -337,6 +340,18 @@
|
||||
<description type="DescriptionField"/>
|
||||
<DynDns type="BooleanField"/>
|
||||
<AcmePassthrough type="HostnameField"/>
|
||||
<ClientAuthMode type="OptionField">
|
||||
<BlankDesc>require_and_verify</BlankDesc>
|
||||
<OptionValues>
|
||||
<request>request</request>
|
||||
<require>require</require>
|
||||
<verify_if_given>verify_if_given</verify_if_given>
|
||||
</OptionValues>
|
||||
</ClientAuthMode>
|
||||
<ClientAuthTrustPool type="CertificateField">
|
||||
<Type>ca</Type>
|
||||
<Multiple>Y</Multiple>
|
||||
</ClientAuthTrustPool>
|
||||
</subdomain>
|
||||
<handle type="ArrayField">
|
||||
<enabled type="BooleanField">
|
||||
|
||||
@@ -100,6 +100,19 @@ foreach ((new Caddy())->reverseproxy->reverse->iterateItems() as $reverseItem) {
|
||||
}
|
||||
}
|
||||
|
||||
foreach ((new Caddy())->reverseproxy->subdomain->iterateItems() as $subdomainItem) {
|
||||
$caCertField = (string)$subdomainItem->ClientAuthTrustPool;
|
||||
|
||||
if (!empty($caCertField)) {
|
||||
$refs = array_map('trim', explode(',', $caCertField));
|
||||
foreach ($refs as $ref) {
|
||||
if (!empty($ref)) {
|
||||
$caCertRefs[] = $ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$caCertRefs = array_unique($caCertRefs);
|
||||
|
||||
foreach ((new Ca())->ca->iterateItems() as $caItem) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{#
|
||||
# Copyright (c) 2023-2024 Cedrik Pischem
|
||||
# Copyright (c) 2023-2025 Cedrik Pischem
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
@@ -220,6 +220,19 @@
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{#
|
||||
# Section: Encrypted ClientHello (ECH) Configuration
|
||||
# https://caddyserver.com/docs/caddyfile/options#ech
|
||||
#}
|
||||
{% if generalSettings.TlsDnsEchDomain|default("") and dnsProvider %}
|
||||
dns {{ dnsProvider }} {% if dnsProvider not in dnsProviderSpecialConfig %}{{ dnsApiKey }}{% else %}{
|
||||
{% set context_var = 'dnsProviderSpecialLogic' %}
|
||||
{% include "OPNsense/Caddy/includeDnsProvider" %}
|
||||
}
|
||||
{% endif +%}
|
||||
ech {{ generalSettings.TlsDnsEchDomain }}
|
||||
{% endif %}
|
||||
|
||||
{#
|
||||
# Section: ACME Email, Auto HTTPS selection and global import statement
|
||||
# Purpose: The ACME email is optional for receiving certificate notices.
|
||||
@@ -304,21 +317,21 @@ http://{{ domain }} {
|
||||
# certificates with the DNS-01 challenge. Refer to Dynamic DNS section for more details.
|
||||
#}
|
||||
{% macro tls_configuration(
|
||||
customCert,
|
||||
dnsChallenge,
|
||||
clientAuthTrustPool,
|
||||
clientAuthMode,
|
||||
dnsProvider,
|
||||
dnsApiKey,
|
||||
dnsSecretApiKey,
|
||||
tlsDnsOptionalField1,
|
||||
tlsDnsOptionalField2,
|
||||
tlsDnsOptionalField3,
|
||||
tlsDnsOptionalField4,
|
||||
tlsDnsPropagationTimeout,
|
||||
tlsDnsPropagationTimeoutPeriod,
|
||||
tlsDnsPropagationDelay,
|
||||
tlsDnsPropagationResolvers
|
||||
customCert="",
|
||||
dnsChallenge="0",
|
||||
clientAuthTrustPool="",
|
||||
clientAuthMode="",
|
||||
dnsProvider="",
|
||||
dnsApiKey="",
|
||||
dnsSecretApiKey="",
|
||||
tlsDnsOptionalField1="",
|
||||
tlsDnsOptionalField2="",
|
||||
tlsDnsOptionalField3="",
|
||||
tlsDnsOptionalField4="",
|
||||
tlsDnsPropagationTimeout="",
|
||||
tlsDnsPropagationTimeoutPeriod="",
|
||||
tlsDnsPropagationDelay="",
|
||||
tlsDnsPropagationResolvers=""
|
||||
) %}
|
||||
{% if customCert or (dnsChallenge == "1" and dnsProvider) or clientAuthTrustPool %}
|
||||
tls {% if customCert %}/var/db/caddy/data/caddy/certificates/temp/{{ customCert }}.pem /var/db/caddy/data/caddy/certificates/temp/{{ customCert }}.key{% endif %} {
|
||||
@@ -586,13 +599,10 @@ http://{{ domain }} {
|
||||
# - render_handles: Renders the handles in the correct order, including basic authentication.
|
||||
# - reverse_proxy_configuration: Sets up the handle with reverse proxy configurations.
|
||||
# - handle_response: Manages the response logic for access lists and aborts.
|
||||
# Important Details:
|
||||
# - Order of Path specific Handles: Prioritizes order of specific path handles over catch-all handles.
|
||||
# - Order of Wildcard Domains and Subdomains: Handles for wildcard domains come after all subdomains.
|
||||
#}
|
||||
|
||||
{% for reverse in helpers.toList('Pischem.caddy.reverseproxy.reverse') %}
|
||||
{% if reverse.enabled|default("0") == "1" %}
|
||||
# Reverse Proxy Domain: "{{ reverse['@uuid'] }}"
|
||||
{% if reverse.DisableTls|default("0") == "1" %}http://{% endif %}{{ reverse.FromDomain|default("") }}{% if reverse.FromPort %}:{{ reverse.FromPort }}{% endif %} {
|
||||
{% if reverse.AccessLog|default("0") == "1" %}
|
||||
{% if generalSettings.LogAccessPlain|default("0") == "0" %}
|
||||
@@ -606,44 +616,58 @@ http://{{ domain }} {
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{{ tls_configuration(
|
||||
reverse.CustomCertificate|default(""),
|
||||
reverse.DnsChallenge|default("0"),
|
||||
reverse.ClientAuthTrustPool|default(""),
|
||||
reverse.ClientAuthMode|default(""),
|
||||
generalSettings.TlsDnsProvider,
|
||||
generalSettings.TlsDnsApiKey,
|
||||
generalSettings.TlsDnsSecretApiKey,
|
||||
generalSettings.TlsDnsOptionalField1,
|
||||
generalSettings.TlsDnsOptionalField2,
|
||||
generalSettings.TlsDnsOptionalField3,
|
||||
generalSettings.TlsDnsOptionalField4,
|
||||
generalSettings.TlsDnsPropagationTimeout,
|
||||
generalSettings.TlsDnsPropagationTimeoutPeriod,
|
||||
generalSettings.TlsDnsPropagationDelay,
|
||||
generalSettings.TlsDnsPropagationResolvers
|
||||
customCert=reverse.CustomCertificate|default(""),
|
||||
dnsChallenge=reverse.DnsChallenge|default("0"),
|
||||
clientAuthTrustPool=reverse.ClientAuthTrustPool|default(""),
|
||||
clientAuthMode=reverse.ClientAuthMode|default(""),
|
||||
dnsProvider=generalSettings.TlsDnsProvider,
|
||||
dnsApiKey=generalSettings.TlsDnsApiKey,
|
||||
dnsSecretApiKey=generalSettings.TlsDnsSecretApiKey,
|
||||
tlsDnsOptionalField1=generalSettings.TlsDnsOptionalField1,
|
||||
tlsDnsOptionalField2=generalSettings.TlsDnsOptionalField2,
|
||||
tlsDnsOptionalField3=generalSettings.TlsDnsOptionalField3,
|
||||
tlsDnsOptionalField4=generalSettings.TlsDnsOptionalField4,
|
||||
tlsDnsPropagationTimeout=generalSettings.TlsDnsPropagationTimeout,
|
||||
tlsDnsPropagationTimeoutPeriod=generalSettings.TlsDnsPropagationTimeoutPeriod,
|
||||
tlsDnsPropagationDelay=generalSettings.TlsDnsPropagationDelay,
|
||||
tlsDnsPropagationResolvers=generalSettings.TlsDnsPropagationResolvers
|
||||
) }}
|
||||
|
||||
{% for subdomain in helpers.toList('Pischem.caddy.reverseproxy.subdomain') %}
|
||||
{% if subdomain.enabled|default("0") == "1" and subdomain.reverse == reverse['@uuid'] %}
|
||||
@{{ subdomain['@uuid'] }} {
|
||||
host {{ subdomain.FromDomain }}
|
||||
}
|
||||
handle @{{ subdomain['@uuid'] }} {
|
||||
{% set subdomain_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('subdomain', 'equalto', subdomain['@uuid']) | list %}
|
||||
{{ handle_accesslist(subdomain.accesslist, subdomain.FromDomain) }}
|
||||
{# All IPs not matched by accesslist will continue processing #}
|
||||
{{ render_basic_auth(subdomain.basicauth) }}
|
||||
{{ render_handles(subdomain_handles) }}
|
||||
}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% set domain_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('reverse', 'equalto', reverse['@uuid']) | selectattr('subdomain', 'undefined') | list %}
|
||||
{{ handle_accesslist(reverse.accesslist, reverse.FromDomain) }}
|
||||
{# All IPs not matched by accesslist will continue processing #}
|
||||
{{ render_basic_auth(reverse.basicauth) }}
|
||||
{{ render_handles(domain_handles) }}
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% for subdomain in helpers.toList('Pischem.caddy.reverseproxy.subdomain') %}
|
||||
{% if subdomain.enabled|default("0") == "1" %}
|
||||
{% set reverse = helpers.toList('Pischem.caddy.reverseproxy.reverse') | selectattr('@uuid', 'equalto', subdomain.reverse) | first %}
|
||||
{% if reverse and reverse.enabled|default("0") == "1" %}
|
||||
{% if reverse.DisableTls|default("0") == "1" %}http://{% endif %}{{ subdomain.FromDomain|default("") }}{% if reverse.FromPort %}:{{ reverse.FromPort }}{% endif %} {
|
||||
{% if reverse.AccessLog|default("0") == "1" %}
|
||||
{% if generalSettings.LogAccessPlain|default("0") == "0" %}
|
||||
log {{ subdomain['@uuid'] }}
|
||||
{% else %}
|
||||
log {
|
||||
output file /var/log/caddy/access/{{ subdomain['@uuid'] }}.log {
|
||||
roll_keep_for {{ generalSettings.LogAccessPlainKeep|default("10") }}d
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{{ tls_configuration(
|
||||
clientAuthTrustPool=subdomain.ClientAuthTrustPool|default(""),
|
||||
clientAuthMode=subdomain.ClientAuthMode|default("")
|
||||
) }}
|
||||
{% set subdomain_handles = helpers.toList('Pischem.caddy.reverseproxy.handle') | selectattr('subdomain', 'equalto', subdomain['@uuid']) | list %}
|
||||
{{ handle_accesslist(subdomain.accesslist, subdomain.FromDomain) }}
|
||||
{{ render_basic_auth(subdomain.basicauth) }}
|
||||
{{ render_handles(subdomain_handles) }}
|
||||
}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user