ssl_client_s_dn 是 Nginx/OpenResty 中获取客户端证书 Subject DN 的内置变量,需在 mTLS 成功验证后才有值,可用于日志记录、字段解析(map 或 Lua)及身份溯源。

在启用 TLS 双向认证(mTLS)的 Nginx 或 OpenResty 环境中,ssl_client_s_dn 是一个内置变量,用于获取客户端证书的 Subject Distinguished Name(可分辨名称),即证书中标识客户端身份的核心字段。它默认以 RFC 2253 格式呈现(如 CN=api-client,OU=Services,O=Example Corp,L=Beijing,ST=Beijing,C=CN),可直接用于日志记录,帮助审计、调试或策略匹配。
确认双向认证已正确启用
只有在成功完成客户端证书验证后,ssl_client_s_dn 才有值。需确保以下配置生效:
-
ssl_verify_client on;或optional(若设为optional,需在 Lua 或 if 中检查 $ssl_client_verify 是否为 SUCCESS) -
ssl_client_certificate指向受信任的 CA 证书文件(PEM 格式) -
ssl_trusted_certificate(可选)用于验证链,尤其当 CA 有中间证书时 - 客户端实际提供了有效、未过期、由指定 CA 签发且未被吊销的证书
在 access_log 中直接记录完整 DN
在 http、server 或 location 块中自定义日志格式,将 $ssl_client_s_dn 加入 log_format:
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'client_dn="$ssl_client_s_dn"';
access_log /var/log/nginx/access.log main;
请求成功完成 mTLS 后,日志中会出现类似:
"client_dn=\"CN=monitor-01,OU=Ops,O=Acme,L=Shanghai,ST=Shanghai,C=CN\""
提取关键字段用于结构化分析
ssl_client_s_dn 是字符串,但常用字段(如 CN、OU、O)可借助 Nginx 的 map 指令做简单解析,便于后续筛选或告警:
map $ssl_client_s_dn $client_cn {
~CN=([^,]+) $1;
default "-";
}
map $ssl_client_s_dn $client_ou {
~OU=([^,]+) $1;
default "-";
}
然后在 log_format 中使用 $client_cn 和 $client_ou:
... client_cn="$client_cn" client_ou="$client_ou"
⚠️ 注意:正则匹配依赖 DN 字段顺序,若某些证书 OU 在 CN 前(如 OU=Dev,CN=app-01),建议用更鲁棒的模式(如 ~OU=([^,]+)(?:,|$)),或改用 Lua 脚本做完整 ASN.1 解析。
配合 Lua 做深度解析(OpenResty 推荐)
若需稳定提取 subject 中任意字段(包括多值 RDN、空格/逗号转义等),推荐在 access_by_lua_block 中使用 ssl.client_hello() 或解析 ngx.var.ssl_client_raw_cert(需开启 ssl_client_certificate + ssl_verify_client):
access_by_lua_block {
local cert = ngx.var.ssl_client_raw_cert
if cert then
local parsed = require "resty.openssl.x509":new(cert)
local subj = parsed:get_subject()
ngx.var.client_cn = subj:get_object("CN") or "-"
ngx.var.client_email = subj:get_object("emailAddress") or "-"
end
}
再将 $client_cn、$client_email 写入日志。这种方式规避了 DN 字符串解析的歧义,适合生产环境对身份溯源要求高的场景。


















