在之前的文章中,我们在 k3s 集群上部署了几个简单的网站。 这些都是非加密网站。 这当然没问题,而且它们可以工作,但是非加密是非常老旧的方式! 现在,大多数网站都已加密。 在本文中,我们将安装cert-manager 并使用它在我们的集群上部署 TLS 加密网站。 不仅网站将被加密,而且它们还将使用有效的公共证书,这些证书是从 Let's Encrypt 自动配置和自动续订的! 让我们开始吧!
所需材料
要学习本文,您需要我们在之前的文章中构建的 k3s Raspberry Pi 集群。 此外,您还需要一个公共静态 IP 地址和一个您拥有并可以创建 DNS 记录的域名。 如果您有为您提供域名的动态 DNS 提供程序,这也可能有效。 但是,在本文中,我们将使用静态 IP 和 CloudFlare 手动创建 DNS “A” 记录。
当我们在本文中创建配置文件时,如果您不想手动输入它们,它们都可以在此处下载。
我们为什么要使用 cert-manager?
Traefik(k3s 预先捆绑)实际上具有内置的 Let's Encrypt 支持,因此您可能想知道我们为什么要安装第三方软件包来执行相同的操作。 在撰写本文时,Traefik 的 Let's Encrypt 支持检索证书并将它们存储在文件中。 Cert-manager 检索证书并将它们存储在 Kubernetes **secrets** 中。 **Secrets** 可以简单地按名称引用,因此,我认为更易于使用。 这是我们将在本文中使用 cert-manager 的主要原因。
安装 cert-manager
我们主要会遵循 cert-manager 文档 在 Kubernetes 上进行安装。 但是,由于我们正在使用 ARM 架构,因此我们将进行细微的更改,因此我们将在此处介绍该过程。
第一步是创建 cert-manager 命名空间。 命名空间有助于将 cert-manager 的 pod 与我们的默认命名空间分开,因此当我们使用我们自己的 pod 执行诸如 kubectl get pods 之类的操作时,不必看到它们。 创建命名空间很简单
kubectl create namespace cert-manager
安装说明让您下载 cert-manager YAML 配置文件并一步将其应用到您的集群。 我们需要将该步骤分成两个步骤,以便为我们基于 ARM 的 Pis 修改文件。 我们将一步下载文件并进行转换
curl -sL \
https://github.com/jetstack/cert-manager/releases/download/v0.11.0/cert-manager.yaml |\
sed -r 's/(image:.*):(v.*)$/\1-arm:\2/g' > cert-manager-arm.yaml
这将下载配置文件并更新所有包含的 docker 镜像以成为 ARM 版本。 要检查它的作用
$ grep image: cert-manager-arm.yaml
image: "quay.io/jetstack/cert-manager-cainjector-arm:v0.11.0"
image: "quay.io/jetstack/cert-manager-controller-arm:v0.11.0"
image: "quay.io/jetstack/cert-manager-webhook-arm:v0.11.0"
我们可以看到,这三个镜像现在都在镜像名称中添加了 -arm。 现在我们有了正确的文件,只需将其应用到我们的集群即可
kubectl apply -f cert-manager-arm.yaml
这将安装所有 cert-manager。 我们可以通过使用 kubectl --namespace cert-manager get pods 进行检查,直到所有 pod 都处于 Running 状态,来了解安装何时完成。
这就是 cert-manager 安装的全部内容!
Let's Encrypt 快速概述
关于 Let's Encrypt 的好处是,它们免费为我们提供公开验证的 TLS 证书! 这意味着我们可以拥有一个完全有效的 TLS 加密网站,任何人都可以访问我们的家庭或爱好项目,这些项目不会赚钱来支持自己,而无需自掏腰包购买 TLS 证书! 此外,当将 Let's Encrypt 证书与 cert-manager 一起使用时,获取证书的整个过程都是自动化的。 证书续订也是自动化的!
但是这是如何运作的呢? 这是该过程的简化说明。 我们(或代表我们的 cert-manager)向 Let's Encrypt 发出针对我们拥有的域名的证书请求。 Let's Encrypt 通过使用 ACME DNS 或 HTTP 验证机制来验证我们是否拥有该域。 如果验证成功,Let's Encrypt 会向我们提供证书,cert-manager 会将这些证书安装在我们的网站(或其他 TLS 加密端点)中。 这些证书有效期为 90 天,之后需要重复该过程。 但是,Cert-manager 会自动为我们更新证书。
在本文中,我们将使用 HTTP 验证方法,因为它更易于设置并且适用于大多数用例。 这是将在后台发生的基本过程。 Cert-manager 将向 Let's Encrypt 发出证书请求。 作为回应,Let's Encrypt 将发布所有权验证质询。 挑战是在请求证书的域名下的特定 URL 上放置一个 HTTP 资源。 该理论是,如果我们可以将该资源放置在该 URL 中,并且 Let's Encrypt 可以远程检索它,那么我们一定是该域的所有者。 否则,要么我们无法将资源放置在正确的位置,要么我们无法操纵 DNS 以允许 Let's Encrypt 访问它。 在这种情况下,cert-manager 会将资源放置在正确的位置,并自动创建一个临时 Ingress 记录,该记录会将流量路由到正确的位置。 如果 Let's Encrypt 可以读取质询并且质询正确,它会将证书发回给 cert-manager。 然后,Cert-manager 将证书存储为 secrets,我们的网站(或其他任何东西)将使用这些证书来通过 TLS 保护我们的流量。
为质询准备我们的网络
我假设您想在您的家庭网络上设置它,并且有一个以某种方式连接到更广泛的互联网的路由器/接入点。 如果不是这种情况,则以下过程可能不是您需要的。
为了使质询过程正常工作,我们需要请求证书的域名在端口 80 上路由到我们的 k3s 集群。为此,我们需要告诉世界的 DNS 系统它在哪里。 因此,我们需要将域名映射到我们的公共 IP 地址。 如果您不知道您的公共 IP 地址是什么,您可以访问诸如 WhatsMyIP 之类的网站,它会告诉您。 接下来,我们需要输入一个 DNS “A” 记录,该记录将我们的域名映射到我们的公共 IP 地址。 为了使此功能可靠地工作,您需要一个静态公共 IP 地址,或者您可以使用动态 DNS 提供程序。 一些动态 DNS 提供商会向您颁发一个域名,您可以使用这些说明。 我没有尝试过,因此我不能确定它是否适用于所有提供商。
在本文中,我们将假设一个静态公共 IP 并使用 CloudFlare 设置 DNS “A” 记录。 如果您愿意,可以使用您自己的 DNS 提供商。 重要的一点是您可以设置“A”记录。
对于本文的其余部分,我将使用 k3s.carpie.net 作为示例域,因为这是我拥有的域。 显然,您可以用您拥有的任何域名替换它。
好的,为了举例,假设我们的公共 IP 地址是 198.51.100.42。 我们将转到我们的 DNS 提供商的 DNS 记录部分,并添加一个类型为“A”的记录,名称为 k3s.carpie.net(CloudFlare 假定该域名,因此我们可以在那里只输入 k3s),并输入 198.51.100.42 作为 IPv4 地址。

请注意,有时 DNS 更新需要一段时间才能传播。 您可能需要几个小时才能解析该名称。 在继续之前,必须解析该名称。 否则,我们所有的证书请求都将失败。
我们可以使用 dig 命令检查名称是否可以解析
$ dig +short k3s.carpie.net
198.51.100.42
继续运行以上命令,直到返回 IP。 关于 CloudFlare 的注意事项:ClouldFlare 提供一项通过代理流量来隐藏您实际 IP 的服务。 在这种情况下,我们将返回一个 CloudFlare IP 而不是我们的 IP。 这应该可以很好地满足我们的目的。
网络配置的最后一步是配置路由器,将端口 80 和 443 上的传入流量路由到我们的 k3s 集群。遗憾的是,路由器配置界面差异很大,所以我无法准确地告诉你你的界面会是什么样子。大多数情况下,我们需要的管理页面位于“端口转发”或类似名称下。我甚至见过它被列在“游戏”下(显然端口转发主要用于游戏)!让我们看看我的路由器的配置是什么样的。

如果你拥有我的设置,你需要访问 192.168.0.1 才能登录到路由器管理应用程序。对于此路由器,它位于NAT / QoS -> 端口转发下。在这里,我们将端口 80、TCP 协议设置为转发到 192.168.0.50(kmaster,即我们的主节点的 IP 地址)的端口 80。我们还将端口 443 设置为映射到 kmaster。从技术上讲,这对于挑战不是必需的,但在文章的最后,我们将部署一个启用 TLS 的网站,我们需要映射 443 才能访问它。因此,现在就映射它是很方便的。我们保存并应用更改,一切就绪!
配置 cert-manager 以使用 Let's Encrypt(测试环境)
现在我们需要配置 cert-manager 以通过 Let's Encrypt 颁发证书。Let's Encrypt 提供了一个测试环境,供我们整理配置。它对错误和请求频率的容忍度更高。如果我们在生产环境中胡乱操作,我们很快就会发现自己被暂时禁止!因此,我们将使用测试环境手动测试请求。
创建一个文件,letsencrypt-issuer-staging.yaml,内容如下
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-staging
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: <your_email>@example.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: traefik
请确保将电子邮件地址更新为你的地址。如果出现问题或我们做了不好的事情,Let's Encrypt 将通过此方式与我们联系!
现在我们使用以下命令创建颁发者
kubectl apply -f letsencrypt-issuer-staging.yaml
我们可以通过以下方式检查颁发者是否已成功创建
kubectl get clusterissuers
Clusterissuers 是 cert-manager 创建的一种新的 Kubernetes 资源类型。
现在让我们手动请求一个测试证书。对于我们的站点,我们不需要这样做;我们只是测试该过程以确保我们的配置正确。
创建一个证书请求文件,le-test-certificate.yaml,内容如下
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
name: k3s-carpie-net
namespace: default
spec:
secretName: k3s-carpie-net-tls
issuerRef:
name: letsencrypt-staging
kind: ClusterIssuer
commonName: k3s.carpie.net
dnsNames:
- k3s.carpie.net
此记录只是说我们要使用名为 letsencrypt-staging 的 ClusterIssuer(我们在上一步中创建的)为域 k3s.carpie.net 请求证书,并将证书文件存储在名为 k3s-carpie-net-tls 的 Kubernetes Secret 中。
像往常一样应用它
kubectl apply -f le-test-certificate.yaml
我们可以使用以下命令检查状态
kubectl get certificates
如果我们看到类似
NAME READY SECRET AGE
k3s-carpie-net True k3s-carpie-net-tls 30s
我们就一切就绪了!(这里的关键是 READY 为 True)。
排除证书请求问题
这是顺利的情况。如果 READY 为 False,我们可以等待一段时间,然后再次检查状态,以防需要一些时间。如果它仍然是 False,那么我们需要排除一个问题。此时,我们可以遍历 Kubernetes 资源链,直到找到一条告诉我们问题的状态消息。
假设我们完成了上述请求,并且 READY 为 False。我们开始使用以下命令进行故障排除
kubectl describe certificates k3s-carpie-net
这将返回大量信息。通常,有用的信息位于 Events: 部分,该部分通常位于底部。假设最后一个事件是 Created new CertificateRequest resource "k3s-carpie-net-1256631848。然后我们将描述该请求
kubectl describe certificaterequest k3s-carpie-net-1256631848
现在假设那里的最后一个事件是 Waiting on certificate issuance from order default/k3s-carpie-net-1256631848-2342473830。
好的,我们可以描述订单
kubectl describe orders default/k3s-carpie-net-1256631848-2342473830
假设该事件说 Created Challenge resource "k3s-carpie-net-1256631848-2342473830-1892150396" for domain "k3s.carpie.net"。让我们描述一下挑战
kubectl describe challenges k3s-carpie-net-1256631848-2342473830-1892150396
从此处返回的最后一个事件是 Presented challenge using http-01 challenge mechanism。这看起来还不错,因此我们扫描描述输出并看到一条消息 Waiting for http-01 challenge propagation: failed to perform self check GET request … no such host。终于!我们找到了问题!在这种情况下,no such host 意味着 DNS 查找失败,因此我们将返回并手动检查我们的 DNS 设置,并确保我们域的 DNS 可以正确解析,并进行所需的任何更改。
清理我们的测试证书
我们实际上想要一个用于我们使用的域名的真实证书,因此让我们继续清理我们刚刚创建的证书和 Secret
kubectl delete certificates k3s-carpie-net
kubectl delete secrets k3s-carpie-net-tls
配置 cert-manager 以使用 Let's Encrypt(生产环境)
现在我们已经可以正常使用测试证书了,是时候升级到生产环境了。就像我们为 Let's Encrypt 测试环境配置 cert-manager 一样,我们现在需要对生产环境执行相同的操作。创建一个文件(如果需要,可以复制并修改测试环境文件),命名为 letsencrypt-issuer-production.yaml,内容如下
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: <your_email>@example.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
class: traefik
(如果你从测试环境复制,则唯一更改的是 server: URL。不要忘记电子邮件)!
使用以下命令应用
kubectl apply -f letsencrypt-issuer-production.yaml
为我们的网站请求证书
重要的是要注意,到目前为止我们完成的所有步骤都是一次性设置!对于将来的任何其他请求,我们都可以从说明中的这一点开始!
让我们部署我们在 上一篇文章 中部署的相同站点。(如果你仍然有它,你可以只修改 YAML 文件。如果没有,你可能想要重新创建它并重新部署它)。
我们只需要修改 mysite .yaml 的 Ingress 部分为
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: mysite-nginx-ingress
annotations:
kubernetes.io/ingress.class: "traefik"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
rules:
- host: k3s.carpie.net
http:
paths:
- path: /
backend:
serviceName: mysite-nginx-service
servicePort: 80
tls:
- hosts:
- k3s.carpie.net
secretName: k3s-carpie-net-tls
请注意,上面仅显示了 mysite.yaml 的 Ingress 部分。更改是添加了 annotation cert-manager.io/cluster-issuer: letsencrypt-prod。这告诉 traefik 在创建证书时使用哪个颁发者。唯一添加的另一项是 tls: 块。这告诉 traefik 我们希望在主机 k3s.carpie.net 上使用 TLS,并且我们希望将 TLS 证书文件存储在 Secret k3s-carpie-net-tls 中。
请记住,我们没有创建这些证书!(好吧,我们创建了类似命名的测试证书,但是我们删除了它们。)Traefik 将读取此信息并开始查找 Secret。当它找不到它时,它会看到注释,说我们要使用 letsencrypt-prod 颁发者来获取证书。从那里,它将发出请求并将证书安装在 Secret 中,供我们使用!
我们完成了!让我们尝试一下。
它就在那里,拥有所有加密的 TLS 美感!恭喜!
8 条评论