- 云原生
- 网络
- 微服务
【免费下载链接】linkerd
Old repo for Linkerd 1.x. See the linkerd2 repo for Linkerd 2.x.
Linkerd 1.x 作为一款服务网格代理,其核心职责之一就是在服务之间建立安全、加密的通信通道。本指南以 linkerd/docs/client_tls.md 为骨架,结合仓库源码与示例配置,系统讲解 Linkerd 中 TLS 的两大方向——Server TLS(服务端接收加密流量)与Client TLS(客户端发送加密流量)的完整配置方法、参数语义、常见陷阱与调试技巧。读完本文,你将能够独立为 Linkerd 路由器配置单向 TLS、双向(mTLS)认证、按目标服务动态下发证书的静态客户端,并理解底层实现原理。
一、TLS 在 Linkerd 中的两种形态
在 Linkerd 的配置模型中,TLS 被清晰地划分为两个层面:
- Server TLS:定义在
routers[].servers[].tls下,决定 Linkerd作为服务端时如何接收来自下游(例如远程 Linkerd、浏览器或客户端应用)的加密流量。 - Client TLS:定义在
routers[].client.tls下,决定 Linkerd作为客户端时如何加密它发送给目标服务的流量。
两者可以独立启用,也可以同时启用。例如一台 Linkerd 可以对外提供 TLS 监听端口接收加密请求,同时以 TLS 方式向上游服务发起加密请求,从而形成全链路的加密转发。仓库中的 linkerd/examples/tls.yaml 正是这样一个"收发皆加密"的完整示例。
二、Server TLS:让 Linkerd 接收加密流量
2.1 最小配置
要在 Linkerd 的某个 server 上启用 TLS,只需在servers条目下添加tls参数并指定证书与私钥路径:
routers: - protocol: http servers: - port: 4140 # accept incoming TLS traffic from remote Linkerd tls: certPath: /certificates/certificate.pem keyPath: /certificates/key.pem dtab: | /http => /$/inet/127.1/8080;配置后,Linkerd 在 4140 端口上监听的就是 TLS 加密流量。示例 linkerd/examples/admin-tls.yaml 还展示了管理界面(admin)本身的 TLS 化方式——在顶层admin段同样支持tls配置。
2.2 Server TLS 参数总览
| Key | 默认值 | 说明 |
|---|---|---|
enabled | true | 是否在入站连接上启用 TLS。 |
certPath | 必填 | TLS 服务端证书文件路径。 |
intermediateCertsPath | 无 | 包含 CA 证书链的文件路径,用于支撑服务端证书(即服务端证书由中间 CA 签发时的完整证书链)。 |
keyPath | 必填 | TLS 私钥文件路径。 |
requireClientAuth | false | 若为true,仅接受持有有效客户端证书的请求(启用双向认证)。 |
caCertPath | 无 | 用于校验客户端证书的 CA 证书文件路径。 |
protocols | 未指定 | 要启用的 TLS 协议列表(例如TLSv1.2)。 |
关键限制:Linkerd 需要 PKCS#8 格式的
.pem私钥,不支持 PKCS1。从源码看,这一约束贯穿于测试证书生成工具 finagle/buoyant 层测试工具 中——它专门使用openssl pkcs8 -topk8 -nocrypt将私钥转换为 PKCS#8 无加密格式后再写入配置。
2.3 Server TLS 的源码级实现
Server TLS 的参数解析由TlsServerConfig完成(finagle/buoyant/src/main/scala/com/twitter/finagle/buoyant/TlsServerConfig.scala),其底层逻辑揭示了每个参数的真实影响:
certPath+keyPath构成KeyCredentials.CertAndKey;一旦设置了intermediateCertsPath,则升级为KeyCredentials.CertKeyAndChain,把中间 CA 证书链一并装入密钥凭据(TlsServerConfig.scala#L39-L46)。caCertPath被映射为TrustCredentials.CertCollection,作为服务端信任的客户端证书集合;未设置时则为TrustCredentials.Unspecified(TlsServerConfig.scala#L22-L25)。requireClientAuth: true会被转换为 Finagle 的FClientAuth.Needed,即强制要求客户端提供证书并验证;默认false对应FClientAuth.Off(TlsServerConfig.scala#L34-L37)。- 除文档列出的参数外,
TlsServerConfig还支持ciphers(显式指定 TLS 密码套件列表),这是文档之外可从源码确认的扩展能力(TlsServerConfig.scala#L26-L29)。
在 Linkerd 侧,ServerConfig将tls参数经serverParams注入到 server 的Stack.Params中(linkerd/core/src/main/scala/io/buoyant/linkerd/Server.scala#L94-L100),默认使用Netty4ServerEngineFactory作为 SSL 引擎。
2.4 双向认证(mTLS)配置
当需要校验来访客户端身份时,同时开启requireClientAuth与caCertPath:
routers: - protocol: http dtab: | /svc => /#/io.l5d.fs servers: - port: 4140 tls: certPath: /foo/cert.pem keyPath: /foo/key.pem # clients must provide a valid certificate requireClientAuth: true # the authority used to validate client certificates caCertPath: /foo/cacert.pem这是从 linkerd/examples/mutualTls.yaml 摘取的完整双向认证服务端配置。namerd 示例 linkerd/examples/namerd-tls.yaml 中同样存在requireClientAuth: true的服务端(如namerd-http-tls-clientauth/4142),并配套了携带客户端证书的 client 段,可作为 mTLS 端到端部署的参考。
三、Client TLS:让 Linkerd 发送加密流量
Client TLS 定义在 router 的client段中,描述 Linkerd 在向目标服务发送请求时如何使用 TLS。它既可以作为普通客户端参数直接写在client.tls,也可以通过io.l5d.static静态客户端按前缀(prefix)分别下发。
3.1 最小配置
routers: - protocol: http client: tls: commonName: linkerd.io trustCertsBundle: /certificates/cacert.pem clientAuth: certPath: /certificates/cert.pem keyPath: /certificates/key.pem protocols: - TLSv1.2要点:
- 在 linkerd 配置模型中,
client.tls属于 ClientConfig 提供的客户端通用参数之一,协议无关; - 若目标服务只要求单向 TLS,可省略
clientAuth段,仅保留commonName与trustCertsBundle。
3.2 Client TLS 参数总览
| Key | 默认值 | 说明 |
|---|---|---|
disableValidation | false | 跳过主机名校验(不安全)。disableValidation: true与clientAuth不兼容。 |
commonName | 除非设置了disableValidation,否则必填 | 所有 TLS 请求使用的通用名(CN)。即使disableValidation: true,若服务端要求 SNI,也必须设置此项。 |
trustCerts | 空列表 | 用于 CN 校验的 CA 证书文件路径列表(已弃用,请改用trustCertsBundle)。 |
trustCertsBundle | 空 | 用于 CN 校验的 CA 证书 bundle 文件路径。 |
clientAuth | 无 | 用于给请求签名的客户端认证对象。 |
protocols | 未指定 | 要启用的 TLS 协议列表。 |
clientAuth对象内部包含两个必填属性与一个可选属性:
| Key | 默认值 | 说明 |
|---|---|---|
certPath | 必填 | 客户端 TLS 证书文件路径。 |
intermediateCertsPath | 无 | 包含 CA 证书链的文件路径,用于支撑客户端证书。 |
keyPath | 必填 | 客户端 TLS 私钥路径,必须为 PKCS#8 格式。 |
警告:设置
disableValidation: true会强制使用 JDK SSL provider,而该 provider 不支持客户端认证。因此disableValidation: true与clientAuth互斥。这一约束不仅写在文档中,也以require断言的形式固化在配置解析代码里(linkerd/core/src/main/scala/io/buoyant/linkerd/ClientConfig.scala#L53-L56),若同时配置两者,Linkerd 会在启动时直接报错。
3.3 Client TLS 的源码级实现
TlsClientConfig在 finagle/buoyant/src/main/scala/com/twitter/finagle/buoyant/TlsClientConfig.scala 中被编译为 Finagle 的SslClientConfiguration,其模式匹配逻辑值得注意:
enabled: false:显式禁用 TLS,Transport.ClientSsl(None)(TlsClientConfig.scala#L22-L23)。这正是 linkerd/examples/disable-tls.yaml 中"仅对/$/inet/localhost关闭 TLS、其余目标启用 TLS"的实现基础。disableValidation: true:信任凭据变为TrustCredentials.Insecure,跳过一切证书校验(TlsClientConfig.scala#L24-L32)。trustCerts与trustCertsBundle同时设置:直接抛出IllegalArgumentException,提示"请仅使用 trustCertsBundle"(TlsClientConfig.scala#L34-L36)。trustCerts(弃用路径):多个 CA 文件会被流式合并写入一个临时文件,再作为TrustCredentials.CertCollection使用(TlsClientConfig.scala#L38-L64)。linkerd 层在检测到trustCerts时还会打印弃用警告日志(linkerd/core/src/main/scala/io/buoyant/linkerd/ClientConfig.scala#L58-L60)。clientAuth:无中间证书时生成KeyCredentials.CertAndKey,带intermediateCertsPath时生成KeyCredentials.CertKeyAndChain(TlsClientConfig.scala#L92-L99)。
四、按目标服务下发证书:io.l5d.static与 commonName 变量替换
Linkerd 客户端配置支持io.l5d.global(默认,配置直接写在client段)与io.l5d.static两种形态。io.l5d.static通过一组prefix -> 参数的映射,为不同的目标服务前缀应用不同的 TLS 参数(linkerd/core/src/main/scala/io/buoyant/linkerd/Client.scala#L51-L66)。
关键能力:从client前缀中捕获的任何变量都可以在commonName中使用(花括号语法{var})。例如:
routers: - protocol: http client: kind: io.l5d.static configs: - prefix: /#/io.l5d.fs/{service} tls: commonName: "{service}.linkerd.io" trustCerts: - /certificates/cacert.pem clientAuth: certPath: /certificates/cert.pem keyPath: /certificates/key.pem protocols: - TLSv1.2这里前缀/#/io.l5d.fs/{service}捕获了服务名service,随后commonName: "{service}.linkerd.io"会为每个目标服务动态生成对应的 CN(如cat.linkerd.io)。变量替换通过PathMatcher.substitute完成(linkerd/core/src/main/scala/io/buoyant/linkerd/ClientConfig.scala#L62-L71),并在 linkerd/core/src/test/scala/io/buoyant/linkerd/ClientTest.scala 中由多个测试用例验证,包括通配符捕获("*.{service}.com")与多变量捕获("{role}.{service}.com")等场景。
4.1 结合 dtab 与变量捕获的典型用法
linkerd/examples/tls.yaml 给出了"客户端按服务名动态签发 CN + 服务端接收加密流量"的组合示例:
namers: - kind: io.l5d.fs rootDir: linkerd/examples/io.l5d.fs routers: - protocol: http dtab: | /svc => /#/io.l5d.fs client: # Establish encrypted outgoing connections. kind: io.l5d.static configs: - prefix: "/#/io.l5d.fs/{service}" tls: trustCertsBundle: /foo/caCert.pem commonName: "{service}" servers: - port: 4140 tls: certPath: /foo/cert.pem keyPath: /foo/key.pem intermediateCertsPath: /foo/ca-chain.pem注意该示例使用了推荐的trustCertsBundle(单个 bundle 文件)替代已弃用的trustCerts列表,并展示了服务端intermediateCertsPath的用法。类似地,linkerd/examples/client-options.yaml 展示了通配前缀"/#/*/{service}"配合commonName: "{service}.linkerd.io"的写法,而 linkerd/examples/disable-tls.yaml 则演示了在同一 client 下按前缀混合启用/禁用 TLS 的精细化控制。
4.2 双向认证的客户端侧配置
与 2.4 的服务端 mTLS 对应,客户端侧需要携带自己的证书链:
routers: - protocol: http dtab: | /svc => /#/io.l5d.fs client: tls: commonName: foo trustCertsBundle: /foo/cacert.pem clientAuth: certPath: /foo/clientCert.pem keyPath: /foo/clientKey.pem intermediateCertsPath: /foo/intermediateCa.pem servers: - port: 4140 tls: certPath: /foo/cert.pem keyPath: /foo/key.pem requireClientAuth: true caCertPath: /foo/cacert.pem以上配置取自 linkerd/examples/mutualTls.yaml:客户端用clientAuth出示自身证书,服务端用requireClientAuth+caCertPath验证来访者,构成完整的双向 TLS 链路。
五、Client TLS 与 transformer 的配合
Linkerd 的 transformer(如io.l5d.port)会改写客户端名称:每个 transformer 都会在客户端名前缀上以/%开头的 transformer 前缀,用于标识该客户端已被变换。
在使用io.l5d.static与 transformer 组合时,必须确保 client TLS 的prefix字段至少以 dtab 中应用到客户端名称的第一个 transformer 开头,这样才能保证 TLS 在 Linkerd 客户端与任何接收目标 TLS 流量的下游服务之间正确建立。示例:
routers: - protocol: http interpreter: kind: default transformers: - kind: io.l5d.port port: 4141 dtab: | /svc => /#/io.l5d.fs; client: kind: io.l5d.static configs: - prefix: /%/io.l5d.port/4141/#/io.l5d.fs/ tls: commonName: "linkerd.io" trustCerts: - /certificates/cacert.pem clientAuth: certPath: /certificates/cert.pem keyPath: /certificates/key.pem5.1 transformer 前缀如何作用于客户端名称
假设基础客户端名称为/#/io.l5d.fs/hello,port transformer 会施加/%/io.l5d.port/4141作为 transformer 前缀,于是变换后的客户端名称变为:
/%/io.l5d.port/4141/#/io.l5d.fs/<client name>Linkerd 为服务hello生成的完整客户端名类似/%/io.l5d.port/#/io.l5d.fs/4141/hello(文档原文如此,注意前缀顺序以实际生成的完整名为准)。
5.2 快速获取完整客户端名的调试技巧
一个快捷的排查方法是查看 Linkerd 的管理界面(admin dashboard):
- 打开 admin dashboard 首页;
- 页面中的
client区域会展示当前用于连接下游服务的活跃客户端; - 点击其中任意客户端名称,即可看到该客户端的完整名称;
将显示出的完整名称直接用作io.l5d.static中 client TLS 的prefix值,即可精准匹配该客户端。管理界面自身的 TLS 化配置可参考 linkerd/examples/admin-tls.yaml(在顶层admin.tls中指定certPath、keyPath、caCertPath)。
六、证书与私钥的生成与格式要求
6.1 PKCS#8 格式要求
Linkerd 对私钥格式有严格要求:
- 服务端与客户端的
keyPath都必须是PKCS#8格式的.pem文件; - PKCS1 格式不被支持。
仓库的测试证书工具 linkerd/tls/src/main/scala/io/buoyant/linkerd/tls/TlsUtils.scala 完整演示了证书与密钥的生成流程,可作为实操参考:
- 用
openssl req -x509 ...创建测试 CA(newKeyAndCert); - 用
openssl req -new ...生成服务端/客户端证书请求(newReq); - 用
openssl ca -batch ...由 CA 签发证书(signReq); - 最后用
openssl pkcs8 -topk8 -nocrypt将私钥转换为 PKCS#8 无加密格式(toPk8,见 TlsUtils.scala#L180-L181)。
其中转换命令的核心形态为:
openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pk8.pem6.2 仓库内可直接使用的测试证书
仓库为 e2e 测试预置了一套自签 CA 与端到端证书,位于 finagle/h2/src/e2e/resources 目录:
cacert.pem:测试 CA 证书;linkerd-tls-e2e-cert.pem:端到端 TLS 服务证书;linkerd-tls-e2e-key.pem:对应的 PKCS#8 私钥。
多个示例配置(如 linkerd/examples/admin-tls.yaml 与 linkerd/examples/namerd-tls.yaml)直接引用了这些测试资源,可在本地快速搭建 TLS 验证环境。
七、常见配置陷阱与最佳实践
结合文档警告与源码实现,总结以下易错点:
disableValidation: true与clientAuth互斥:前者强制 JDK SSL provider,后者不被其支持。配置解析层会直接拒绝这种组合(ClientConfig.scala#L53-L56)。- 启用校验时
commonName必填:若未设置disableValidation又缺少commonName,TlsClientConfig会抛出"tls is configured with validation but commonName is not set"异常(TlsClientConfig.scala#L87-L89)。 - 不要混用
trustCerts与trustCertsBundle:两者同时设置会直接启动失败;trustCerts已弃用,新配置请一律使用trustCertsBundle。 - 私钥必须是 PKCS#8:PKCS1 私钥会导致 TLS 握手失败,转换命令见 6.1 节。
- SNI 场景下务必设置
commonName:即使跳过校验(disableValidation: true),只要服务端依赖 SNI 路由,也必须提供commonName。 - transformer 场景下前缀要带
/%前缀:使用io.l5d.static且 dtab 中应用了 transformer 时,prefix需以 transformer 前缀开头,否则 TLS 参数无法命中对应的客户端名称。
八、参考资料
- 本文核心依据:linkerd/docs/client_tls.md
- 完整示例配置:linkerd/examples/tls.yaml、linkerd/examples/mutualTls.yaml、linkerd/examples/disable-tls.yaml、linkerd/examples/client-options.yaml、linkerd/examples/admin-tls.yaml
- 配置解析实现:linkerd/core/src/main/scala/io/buoyant/linkerd/ClientConfig.scala、linkerd/core/src/main/scala/io/buoyant/linkerd/Client.scala、linkerd/core/src/main/scala/io/buoyant/linkerd/Server.scala
- Finagle 底层实现:finagle/buoyant/src/main/scala/com/twitter/finagle/buoyant/TlsClientConfig.scala、finagle/buoyant/src/main/scala/com/twitter/finagle/buoyant/TlsServerConfig.scala
- 测试与证书工具:linkerd/core/src/test/scala/io/buoyant/linkerd/ClientTest.scala、linkerd/tls/src/main/scala/io/buoyant/linkerd/tls/TlsUtils.scala、finagle/h2/src/e2e/resources
- 云原生
- 网络
- 微服务
【免费下载链接】linkerd
Old repo for Linkerd 1.x. See the linkerd2 repo for Linkerd 2.x.
相关推荐
Linkerd 1.x 路由配置完全指南:Router、Server 与 Client 参数详解
Linkerd 1.x 路由配置完全指南:Router、Server 与 Client 参数详解 导读 本文以 Linkerd 1.x 官方配置文档( link
云原生网络微服务Traefik TCP TLS 路由配置完全指南:TLS 终结、Passthrough 与 Postgres STARTTLS 实战
Traefik TCP TLS 路由配置完全指南:TLS 终结、Passthrough 与 Postgres STARTTLS 实战 本指南以 Traefik
后端API网关负载均衡微服务网络云原生libwebsockets 内存证书 TLS 最小 HTTP 服务器实战:minimal-http-server-tls-mem 原理与配置详解
libwebsockets 内存证书 TLS 最小 HTTP 服务器实战:minimal http server tls mem 原理与配置详解 导读: min
人工智能AI Agent多模态语音AI 应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考