☰
Linkerd 1.x TLS 配置完全指南:Server TLS 与 Client TLS 的实战详解
2026/10/13 3:11:48 网站建设 项目流程
  • 云原生
  • 网络
  • 微服务

【免费下载链接】linkerd

Old repo for Linkerd 1.x. See the linkerd2 repo for Linkerd 2.x.

项目地址:https://gitcode.com/gh_mirrors/li/linkerd
点击查看免费下载

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默认值说明
enabledtrue是否在入站连接上启用 TLS。
certPath必填TLS 服务端证书文件路径。
intermediateCertsPath无包含 CA 证书链的文件路径,用于支撑服务端证书(即服务端证书由中间 CA 签发时的完整证书链)。
keyPath必填TLS 私钥文件路径。
requireClientAuthfalse若为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默认值说明
disableValidationfalse跳过主机名校验(不安全)。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.pem

5.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):

  1. 打开 admin dashboard 首页;
  2. 页面中的client区域会展示当前用于连接下游服务的活跃客户端;
  3. 点击其中任意客户端名称,即可看到该客户端的完整名称;

将显示出的完整名称直接用作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 完整演示了证书与密钥的生成流程,可作为实操参考:

  1. 用openssl req -x509 ...创建测试 CA(newKeyAndCert);
  2. 用openssl req -new ...生成服务端/客户端证书请求(newReq);
  3. 用openssl ca -batch ...由 CA 签发证书(signReq);
  4. 最后用openssl pkcs8 -topk8 -nocrypt将私钥转换为 PKCS#8 无加密格式(toPk8,见 TlsUtils.scala#L180-L181)。

其中转换命令的核心形态为:

openssl pkcs8 -topk8 -nocrypt -in key.pem -out key_pk8.pem

6.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 验证环境。

七、常见配置陷阱与最佳实践

结合文档警告与源码实现,总结以下易错点:

  1. disableValidation: true与clientAuth互斥:前者强制 JDK SSL provider,后者不被其支持。配置解析层会直接拒绝这种组合(ClientConfig.scala#L53-L56)。
  2. 启用校验时commonName必填:若未设置disableValidation又缺少commonName,TlsClientConfig会抛出"tls is configured with validation but commonName is not set"异常(TlsClientConfig.scala#L87-L89)。
  3. 不要混用trustCerts与trustCertsBundle:两者同时设置会直接启动失败;trustCerts已弃用,新配置请一律使用trustCertsBundle。
  4. 私钥必须是 PKCS#8:PKCS1 私钥会导致 TLS 握手失败,转换命令见 6.1 节。
  5. SNI 场景下务必设置commonName:即使跳过校验(disableValidation: true),只要服务端依赖 SNI 路由,也必须提供commonName。
  6. 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.

项目地址:https://gitcode.com/gh_mirrors/li/linkerd
点击查看免费下载
上一篇:ClawPanel是什么?一文看懂OpenClaw与Hermes Agent多引擎AI管理面板
下一篇:微调面试题实战指南:LoRA、QLoRA与RLHF怎么选、怎么答

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

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

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

立即咨询