Echo.Server必须手动构造以实现mTLS:需自定义tls.Config,设置ClientAuth为RequireAndVerifyClientCert、加载CA证书到ClientCAs,并确保客户端证书含完整链及EKU包含clientAuth。

echo.Server 必须手动构造,不能用 echo.StartTLS
直接调用 e.StartTLS("cert.pem", "key.pem") 会创建一个默认 tls.Config,但其中 ClientAuth 是 tls.NoClientCert——服务端根本不会向客户端索要证书,mTLS 彻底失效。你得绕过这个封装,自己构建 http.Server 实例。
关键步骤:
- 用
echo.New()创建 Echo 实例,但先不启动 - 手动初始化
tls.Config,设置ClientAuth和ClientCAs - 把
echo.Server的Handler赋给http.Server.Handler - 调用
http.Server.ListenAndServeTLS
ClientAuth 和 ClientCAs 必须同时设对
TLSConfig.ClientAuth 至少得是 tls.RequireAnyClientCert(只验存在)或更严格的 tls.RequireAndVerifyClientCert(验签名+信任链)。只设后者但漏掉 ClientCAs,服务端会拒绝所有客户端证书,报错 tls: client didn't provide a certificate 或静默关闭连接。
ClientCAs 必须是加载了根 CA 证书的 *x509.CertPool,不是放客户端证书,也不是放服务端证书。常见错误是把 client.crt 直接塞进去,结果校验永远失败。
示例片段:
caCert, _ := os.ReadFile("/path/to/ca.crt")
caPool := x509.NewCertPool()
caPool.AppendCertsFromPEM(caCert)
config := &tls.Config{
Certificates: []tls.Certificate{cert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: caPool,
}
客户端证书必须完整链,且私钥权限严格
服务端校验的是客户端证书的签名链是否可追溯到 ClientCAs 里的根证书。如果客户端只发 leaf 证书(client.crt),没带中间 CA,服务端解析 r.TLS.PeerCertificates 时可能只剩一个证书,验证失败。
Echo框架 5.1.0 版本源码包下载,适合关注 RealIP 行为变化、StartConfig.Listener、NewDefaultFS 和观测性中间件入口的开发团队。
客户端构造 http.Client 时,TLSClientConfig.Certificates 必须用 tls.LoadX509KeyPair("client.crt", "client.key") 加载——且 client.crt 文件里要按顺序包含 leaf + intermediate(如有),不能拆开。
私钥文件权限必须是 0600,否则 Go 的 crypto/tls 在加载时会静默跳过或 panic;macOS/Linux 上建议执行:chmod 600 client.key。
白名单逻辑得自己写,在 handler 里取 SubjectKeyId
Echo 不提供内置的客户端证书白名单中间件。你得在路由 handler 中手动提取证书信息,比如用 r.TLS.PeerCertificates[0].SubjectKeyId 做哈希比对,或检查 CommonName、DNSNames 等字段。
注意:r.TLS.PeerCertificates 只有在 ClientAuth != tls.NoClientCert 且验证通过后才非空;如果为空,说明 mTLS 没生效,别急着查白名单逻辑,先回退检查 TLS 配置。
容易被忽略的一点:证书的 Extended Key Usage 必须包含 clientAuth(OID 1.3.6.1.5.5.7.3.2),否则某些严格实现(如鸿蒙、Java 客户端)会拒绝发送该证书,导致握手卡在 CertificateRequest 阶段。









