在 Kubernetes 环境中实现证书管理的自动化
原文作者:Jason Schmidt - F5 NGINX 解决方案架构师
原文链接:在 Kubernetes 环境中实现证书管理的自动化
转载来源:NGINX 中文官网
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn
有效的 SSL/TLS 证书是现代应用环境的核心要求。但遗憾的是,在部署应用时,证书的更新管理很容易被忽略。证书的有效期有限且时长不等,DigiCert 证书的有效期在 13 个月左右,Let’s Encrypt 证书的有效期为 90 天。为了确保安全访问,这些证书需要在到期前更新/重新颁发。由于大多数运维团队的工作任务繁重,证书更新有时会被搁置,因此在证书临近(或更糟糕)超过到期日时,手忙脚乱地管理证书的现象时常发生。
其实,情况大可不必如此。只需做好一些规划和准备,就可以简化并实现证书管理的自动化。在这里,我们将介绍一款解决方案,面向使用以下三种技术的 Kubernetes 环境:
通过本文,您将了解如何通过向端点提供自动更新的证书来简化证书管理。
Kubernetes 环境中的证书
在讨论技术细节之前,我们需要先定义一些术语。“TLS 证书”是指在我们的 Ingress controller(Ingress 控制器)上启用 HTTPS 连接所需的两个组件:
证书
私钥
证书和私钥都由 Let’s Encrypt 颁发。关于 TLS 证书如何工作的详细说明,请参阅 DigiCert 文章《TLS/SSL 证书如何工作》。
在 Kubernetes 中,这两个组件被存储为 Secrets。Kubernetes 工作负载,例如 NGINX Ingress Controller 和 cert-manager 可以写入和读取这些 Secret,也可以由有权访问 Kubernetes 安装的用户进行管理。
cert-manager 简介
cert-manager 项目是一个可以与 Kubernetes 和 OpenShift 协同工作的证书控制器。当部署在 Kubernetes 中时,cert-manager 将自动颁发 Ingress controller 所需的证书,并确保它们是有效和最新的。此外,它将跟踪证书的到期日,并按照配置的时间间隔尝试更新。虽然它与大量公共和私有证书颁发机构合作,但在这里我们将只介绍它与 Let’s Encrypt 的集成。
两种 challenge 类型
当使用 Let’s Encrypt 时,所有证书管理都可以自动进行。虽然这提供了极大的便利,但也带来了一个问题:这项服务如何确保您拥有完全限定域名 (FQDN)?
这个问题可使用 challenge 来解决,challenge 会要求您回答一个仅有权访问特定域名的 DNS 记录的人员才能发起的验证请求。challenge 采取以下两种形式中的一种:
HTTP-01:可通过为要将证书颁发给的 FQDN 创建 DNS 记录来解决该 challenge。例如,如果您的服务器位于 IP www.xxx.yyy.zzz,并且您的 FQDN 是 cert.example.com,那么该 challenge 机制将在位于 www.xxx.yyy.zzz 的服务器上暴露一个令牌,Let’s Encrypt 服务器将试图通过 cert.example.com 访问该令牌。如果成功,challenge 通过并颁发证书。
HTTP-01 是生成证书的最简单方法,因为它不需要直接访问 DNS 提供商。这种类型的 challenge 总是通过 HTTP 80 支持的 DNS 端口 进行。注意,当使用 HTTP-01 challenge 时,cert-manager 将利用 Ingress controller 来提供 challenge 令牌。
DNS-01:这个 challenge 使用令牌创建 DNS TXT 记录,然后由颁发机构进行验证。如果令牌被认可,则证明您拥有对该域名的所有权,并且可以立即为其记录颁发证书。与 HTTP-01 challenge 不同的是,使用 DNS-01 challenge 时,FQDN 不需要解析服务器的 IP 地址(甚至不存在)。此外,当 80 端口被屏蔽时,可以使用 DNS-01。不方便的是需要通过访问 cert-manager 安装的 API 令牌提供对 DNS 基础设施的访问权限。
Ingress Controllers
Ingress controller 是 Kubernetes 的一种 service,它被专门用于从集群外部引入流量,将流量负载均衡到内部 Pods(一组单个或多个容器),并管理 egress 出向流量。此外,Ingress controller 通过 Kubernetes API 进行控制,当添加、移除 Pods 或 Pods 出现故障时,它将监控并更新负载均衡配置。
有关 Ingress controller 的更多信息,请参阅以下博客:
在下面的示例中,我们将使用由 F5 NGINX 开发和维护的 NGINX Ingress Controller。
证书管理 示例
这些示例假定您拥有一个可供测试使用的有效 Kubernetes 安装,并且该安装可以分配一个外部 IP 地址(Kubernetes LoadBalancer 对象)。此外,它还假定您可以在 80 和 443 端口(如果使用 HTTP-01 challenge)或只在 443 端口(如果使用 DNS-01 challenge)上接收流量。这些示例都使用 Mac OS X 进行演示,但也可以使用 Linux 或 WSL。
您还需要一个 DNS 提供商以及允许调整 A 记录的 FQDN。如果您使用 HTTP-01 challenge,则只需要添加一个 A 记录(或让人代您添加一个)。如果您使用 DNS-01 challenge,则需要能够对支持的 DNS 提供商或支持的 webhook 提供商进行 API 访问。
部署 NGINX Ingress Controller
最简单的方法是通过 Helm 进行部署。这种部署允许您同时使用 Kubernetes Ingress 和 NGINX Virtual Server CRD。
添加 NGINX 仓库。
2. 更新仓库。
3. 部署 Ingress controller。
4. 检查部署,并检索面向 Ingress controller 的 egress 的 IP 地址。注意,如果没有有效的 IP 地址,则无法继续。
添加 DNS A 记录
具体流程将视您的 DNS 提供商而定。这个 DNS 名称需要能够从 Let’s Encrypt 服务器进行解析,在此之前,您可能需要等待记录传播。有关这方面的更多信息,请参阅 SiteGround 文章《什么是 DNS 传播,为什么需要这么长时间?》
如果能够解析所选择的 FQDN,则可以进入下一步。
部署 cert-manager
下一步是部署最新版本的 cert-manager。同样,我们将使用 Helm 进行部署。
添加 Helm 仓库。
2. 更新仓库。
3. 部署 cert-manager。
4. 验证部署。
部署 NGINX Cafe 示例
我们将使用 NGINX Cafe 示例来提供后端部署和 services。这个示例在 NGINX 提供的文档中十分常见。在此过程中,我们不会部署 Ingress。
克隆 NGINX Ingress GitHub 项目。
2. 进入到示例目录。这个目录中包含几个示例,演示了 Ingress controller 的各种配置。我们使用的是 complete-example 目录下提供的示例。
3. 部署 NGINX Cafe 示例。
4. 使用 kubectl get 命令验证部署和 services。您需要确保 Pods 显示为 READY,而 service 显示为 running。下面的示例为您提供了一个代表性样本。注意,kubernetes 服务是系统服务,与 NGINX Cafe 示例在同一个命名空间(默认)中运行。
部署 ClusterIssuer
在 cert-manager 中,ClusterIssuer 可被用来颁发证书。这是一个集群范围对象,可以被任何命名空间引用,也可以被向指定证书颁发机构发起的任何证书请求所使用。在这个示例中,任何对 Let’s Encrypt 证书的请求都可以由这个 ClusterIssuer 来处理。
为选择的 challenge 类型部署 ClusterIssuer。虽然这不在本文的讨论范围内,但简单提一下,您可以通过高级配置选项在 ClusterIssuer 中指定多个解析器(根据选择器字段选择)。
ACME challenge 基础知识
可使用自动证书管理环境 (ACME) 协议来确定您是否拥有某个域名,进而确定能否被颁发 Let’s Encrypt 证书。对于这个 challenge,需要传递以下参数:
metadata.name:ClusterIssuer 名称,在 Kubernetes 安装中需要是唯一的。这个名称将在后面的证书颁发示例中用到。
spec.acme.email:这是您为生成证书而使用 Let’s Encrypt 注册的电子邮件地址。这应该是您的电子邮件。
spec.acme.privateKeySecretRef:这是您将用来存储私钥的 Kubernetes secret 的名称。spec.acme.solvers:这应保持不变——它指出了您所使用的 challenge 类型(或者 ACME 所说的解析程序)(HTTP-01 或 DNS-01),以及它应该应用于哪种 Ingress 类型(在这种情况下,将是 nginx)。
使用 HTTP-01
这个示例显示了如何设置 ClusterIssuer 以使用 HTTP-01 challenge 来证明域名所有权和接收证书。
创建 ClusterIssuer,使用 HTTP-01 challenge。
2. 验证该 ClusterIssuer(应该显示为 Ready)。
使用 DNS-01
这个示例显示了如何设置 ClusterIssuer 以使用 DNS-01 challenge 来验证域名所有权。根据具体的 DNS 提供商,您可能需要使用 Kubernetes Secret 来存储令牌。这个示例使用的是 Cloudflare。注意命名空间的使用。部署到 cert-manager 命名空间中的 cert-manager 应用需要访问 Secret。
在这个示例中,您需要一个 Cloudflare API 令牌,您可以从账户中创建该令牌。这将需要放在下面的 <API Token> 行中。如果您使用的不是 Cloudflare,则需要遵循提供商的文档。
为 API 令牌创建 Secret。
2. 创建颁发机构,使用 DNS-01 challenge。
3. 验证颁发机构(它应显示为 ready)。
部署 Ingress
完成上述步骤后,即可为应用部署 Ingress 资源。这将把流量路由到我们先前部署的 NGINX Cafe 应用中。
使用 Kubernetes Ingress
如果您使用标准的 Kubernetes Ingress 资源,则要使用以下部署 YAML 来配置 Ingress 并请求证书。
需要检查清单的一些关键部分:
被调用的 API 是标准 Kubernetes Ingress。
该配置的一个关键部分位于 metadata.annotations 下,在这里我们可以把 acme.cert-manager.io/http01-edit-in-place 设置为 “true”。这个值是必填项,可以调整 challenge 的解决方式。如欲了解更多信息,请参阅支持的注释文档。这也可以通过使用 master/minion setup 来处理。
spec.ingressClassName 是指我们已安装并将使用的 NGINX Ingress Controller。
spec.tls.secret Kubernetes Secret 资源存储 Let’s Encrypt 颁发证书时所返回的证书密钥。
我们的主机名 cert.example.com 是为 spec.tls.hosts 和 spec.rules.host 指定的。我们的 ClusterIssuer 就为这个主机名颁发证书。
spec.rules.http 部分定义了路径以及满足这些路径上的请求的后端 Services。例如,到 /tea 的流量将被引导到 tea-svc 上的 80 端口。
根据您的安装修改上述清单。至少需要更改 spec.rules.host 和 spec.tls.hosts 的值,但建议您审查配置中的所有参数。
应用清单。
等待证书颁发,READY 字段的值会变为 “True”。
使用 NGINX 虚拟服务器/虚拟路由
如果您使用 NGINX CRD,则需要使用以下部署 YAML 来配置 Ingress。
更多实践代码点击NGINX社区官网查看
查看证书
您可以通过 Kubernetes API 查看证书。这将显示有关该证书的细节,包括其大小和关联私钥。
如要查看实际的证书和密钥,则可以运行以下命令。(注意:这揭露了 Kubernetes Secrets 的一个弱点。也就是说,它们可以被任何具有必要访问权限的人员读取)。
测试 Ingress
测试证书。在这里您可以使用任何想用的方法。下面的示例使用了 cURL。如果成功,则会出现一个类似于前面所示的代码,其中包括服务器名称、服务器的内部地址、日期、选择的 URI(路由)(coffee 或 tea)以及请求 ID。如果失败,则会生成 HTTP 错误代码,最可能是 400 或 301。
证书更新
刚开始,我们就提到这种方法将消除管理证书更新的需要。然而,我们尚未解释如何做到这一点。为什么呢?因为这是 cert-manager 的一个核心内置部分。在这个自动化过程中,当 cert-manager 意识到证书不存在、已过期、即将在 15 天内过期时,或者当用户通过 CLI 请求新的证书时,它将自动请求新的证书。简单至极。
常见问题
关于 NGINX Plus?
如果您是 NGINX Plus 用户,那么唯一的区别就是要安装 NGINX Ingress Controller。请参阅 NGINX 文档中的安装 Helm 部分,了解如何修改上述 Helm 命令以完成安装。
我应该使用哪种 challenge 类型?
这主要取决于您的用例。
HTTP-01 challenge 方法要求 80 端口对互联网开放,并且 DNS A 记录已根据 Ingress controller 的 IP 地址正确配置。除了创建 A 记录以外,这种方法不要求访问 DNS 提供商。
当无法将 80 端口暴露在互联网上时,可以使用 DNS-01 challenge 方法,它只要求 cert-manager 对 DNS 提供商具有 egress 访问权。但这种方法要求您能够访问 DNS 提供商的 API,所需的访问级别因具体提供商而异。
如何进行故障排除?
由于 Kubernetes 错综复杂,因此很难提供有针对性的故障排除信息。当您遇到问题时,请在 NGINX 社区的官方微信群中向我们提问(NGINX Plus 用户可以使用他们的普通支持选项)。
NGINX 唯一中文官方社区 ,尽在 nginx.org.cn
版权声明: 本文为 InfoQ 作者【NGINX开源社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/c1a38500c4008fc54fba796f9】。文章转载请联系作者。
评论