Caddy mTLS 实战:条件化双向认证与客户端证书校验
2026/8/29 12:09:20 网站建设 项目流程

Caddy mTLS 实战:条件化双向认证与客户端证书校验

【免费下载链接】caddyFast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS项目地址: https://gitcode.com/GitHub_Trending/ca/caddy

一个常见的现实诉求:同一个 HTTPS 入口既服务公网,也服务内网服务——只有内网来源的请求需要出示客户端证书,公网保持普通访问。Caddy 的条件化 mTLS 正好覆盖这个场景:通过connection_policy在 TLS 握手阶段做条件匹配,对命中条件的连接启用客户端证书校验,其余连接照常放行。

一、为什么要"按条件开"双向认证

mTLS(Mutual TLS,双向 TLS)即客户端和服务器互验身份:客户端验证服务器的证书,服务器也要验证客户端的证书——可以理解为服务端也要求客户端出示"身份证"。

全量强制 mTLS 和条件化 mTLS 各有代价:

维度全量强制 mTLS条件化 mTLS
适用场景内网服务网格、API 间互调同一入口混合公网访问与内部服务
客户端体验所有客户端都要装证书,浏览器/脚本接入成本高仅命中条件的连接需要证书
安全边界一刀切,简单清晰按来源收紧,敏感链路强校验
主要代价可用性受损,排障时也要先解决证书问题匹配条件本身成为安全边界,需认真设计

选择性双向认证的价值在于把校验强度交给条件,而不是交给"全部"。

二、一次握手里发生了什么

Caddy 在 TLS 握手阶段对每个连接按顺序评估 TLS 连接策略(connection policy,源码见modules/caddytls/connpolicy.go),命中的第一条策略决定该连接是否要求客户端证书:

client_authmode有两个常用取值:

  • request:向客户端请求证书,但不强制、不校验,拿不到也能连上;
  • require_and_verify:必须提供有效证书且能通过校验,否则握手失败(提供 trust_pool 时这也是默认值)。

三、一份能直接用的 Caddyfile 与 connection_policy 条件匹配写法

先把 CA 根证书放到 Caddy 配置目录(如/etc/caddy/caddy.ca.cer),再使用下面这份完整配置:

{ # 全局可选:日志等 } https://api.example.com { tls { client_auth { mode request trust_pool file { pem_file /etc/caddy/caddy.ca.cer } } } connection_policy { match { remote_ip 192.168.1.0/24 } client_auth { mode require_and_verify trust_pool file { pem_file /etc/caddy/caddy.ca.cer } } } respond "ok" }

语义是:全站默认request(不挡任何人);来源落在192.168.1.0/24的连接命中connection_policy,升级为require_and_verify

匹配维度速查(匹配器定义见modules/caddytls/matchers.go):

匹配项匹配对象典型用途
sni域名,支持左标签通配符仅对某个域名启用 mTLS
sni_regexp域名的正则表达式一批子域统一命中
remote_ip客户端 IP / CIDR,!前缀表示排除mTLS 按 IP 认证,如仅内网段强制
local_ip服务器本地接口 IP区分多网卡、多监听端点

注意:连接策略按定义顺序匹配,靠前者优先。

四、验证矩阵:curl 按"证书 × 来源"四象限验证

场景来源是否带客户端证书预期
1内网(条件内)不带握手失败(要求证书而未提供)
2内网(条件内)带有效证书成功,返回 ok
3外部(条件外)不带成功(仅 request 模式)
4外部(条件外)成功(证书收到但不强制)

场景 1、2 在内网机器上执行(服务器证书若也是自签 CA 签发,--cacert需同时能验证服务器证书):

# 场景1:不带证书,应失败 curl -v https://api.example.com # 场景2:带客户端证书,应成功 curl --cert /etc/caddy/client.crt --key /etc/caddy/client.key \ --cacert /etc/caddy/caddy.ca.cer https://api.example.com # 场景3:从外部主机执行,不带证书应成功 curl --cacert /etc/caddy/caddy.ca.cer https://api.example.com

改动配置后,先用 adapt 校验语法再生效:

caddy adapt --config /etc/caddy/Caddyfile --pretty

输出 JSON 中的tls_connection_policies顺序应与 Caddyfile 中connection_policy的书写顺序一致,可借此核对"谁先匹配"。

五、踩坑清单

  • CA 路径写错:pem_file相对路径是相对 Caddyfile 所在目录解析的,不确定就用绝对路径/etc/caddy/...
  • 证书时效与系统时间:客户端证书过期、未生效或服务器时钟偏移,都会导致require_and_verify失败;先核对时间。
  • 策略顺序:多条connection_policy按定义顺序匹配,先写的具体条件会被后写的宽泛条件"吃掉"时,调整顺序。
  • 先 adapt 后 reload:caddy adapt能提前暴露拼写与结构错误,比 reload 后看日志更快。
  • IP 可伪造:remote_ip匹配的是 TCP 层来源 IP,经过代理/隧道时可被伪装,不要把它当作唯一鉴权手段,mTLS 按 IP 认证只应作为纵深防御的一环。

六、进阶方向

  • PKI 自动管理证书:用 Caddy 内置 PKI 模块签发并管理客户端证书与内部 CA,省去手工换证,让证书生命周期随配置走。
  • 握手日志与失败率监控:开启 TLS 握手日志,结合访问日志统计认证失败率,异常飙升往往意味着证书过期或有人试探。
  • 性能与会话复用:内部高频互调的服务启用会话复用,减少重复握手与证书校验的开销。

条件化 mTLS 把"是否出示身份证"的决定权交给了匹配条件,接下来更值得琢磨的,是你打算用哪几个维度组合这个条件——sni_regexpremote_ip的组合,能覆盖哪些单维度覆盖不了的场景?

【免费下载链接】caddyFast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS项目地址: https://gitcode.com/GitHub_Trending/ca/caddy

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询