Atlantis
GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

2.1 通配符证书

1. 前言

TLS(旧称 SSL) 已经是网络数据传输的必备加密手段,如今是 2024 年,笔者认为已经没有必要讨论是否需要 TLS,而是需要确认要使用哪一个版本的,自建服务推荐最低使用 TLS 1.2 版本。

对于部署在集群中的服务,最常见的需求就是暴露到公网,然后通过域名访问它,这就涉及到配置 DNS 解析和签发 TLS 证书,配置解析简单,但签发证书就比较麻烦了。

常见的免费证书都是 DV 证书,只支持验证单个域名,如果使用这种证书,光是签发和维护就是很大的工作量,因此推荐使用通配符证书,它可以保护多个域名(主机),而无需为每个域名单独购买证书。证书中包含一个星号 (*) 通配符,表示该证书可以保护所有以该通配符开头的主域名。

2. 申请证书

acme.sh 是一个纯 shell 实现的证书申请工具,它实现了 acme 协议, 可以从 letsencrypt 生成免费的证书。

官方链接:acme.sh

笔者的域名托管在 cloudflare,它提供了 API 接口可用于txt 解析记录, 验证域名所有权,下面是通过 acme.sh 申请通配符证书的示例:

2.1 安装 acme.sh

安装很简单, 一个命令:

curl https://get.acme.sh

安装过程执行了以下两步操作:

  1. 安装过程进行了以下几步把 acme.sh 安装到你的 home 目录下:~/.acme.sh,并创建一个 alias 方便使用: alias acme.sh=~/.acme.sh/acme.sh
  2. 自动创建 cronjob, 每天 0:00 点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书

2.2 生成证书

这里使用 DNS 的方式验证域名所有权,首先在 cloudflare 创建一个拥有编辑区域 DNS 权限的多区域 API 令牌:

然后选择一个域名进入首页可以查看到账户 ID

这样我们就得到了两个变量:CF_TokenCF_Account_ID

然后在终端执行以下命令:

export CF_Token=<多区域 API 令牌>
export CF_Token=<账户 ID>
acme.sh --issue --dns dns_cf -d wbuntu.com -d '*.wbuntu.com' -d '*.app.wbuntu.com'

这里我们签发了三个域名:

  1. wbuntu.com:对 wbuntu.com 主域名有效
  2. *.wbuntu.com:对 wbuntu.com 的所有一级子域名有效,如:www.wbuntu.com、test.wbuntu.com
  3. *.app.wbuntu.com:对 app.wbuntu.com 的所有一级子域名有效,如:caddy.app.wbuntu.com

letsencrypt 尚不支持多层级通配符证书,如:*.*.wbuntu.com,由于后续演示的大多数应用都会用 app.wbuntu.com 的子域名,这里就多签发一个通配符。

等待命令运行成功后,可以在 ~/.acme.sh 下查看到证书(目前 acme.sh 默认生成 ecc 证书)

➜  ~ ls ~/.acme.sh
account.conf  acme.sh  acme.sh.env  acme.sh.log  ca  deploy  dnsapi  http.header  notify  wbuntu.com_ecc
➜  ~ ls ~/.acme.sh/wbuntu.com_ecc
backup  ca.cer  fullchain.cer  wbuntu.com.cer  wbuntu.com.conf  wbuntu.com.csr  wbuntu.com.csr.conf  wbuntu.com.key

其中 fullchain.cer 与 wbuntu.com.key 为我们需要的证书和对应的密钥。

3. 部署证书并开启自动更新

K3s 自带了 traefik 作为 ingress-controller,我们可以把它当作集群的入口,像使用 nginx 一样配置转发规则,将请求从入向流量根据域名转发到对应的服务。

traefik 支持通过原生的 ingess 与自带的 ingressroute 配置转发规则,在下一节中会介绍,这里我们只需要将证书转换为 secret 保存即可。

使用 acme.sh 的 --install-cert 子命令可以拷贝和安装证书,且可以指定一个触发应用程序重新加载证书的命令,下面我们会先将证书拷贝到 /tmp 目录,然后执行一个脚本更新集群 kube-system 命名空间下的 secret:tls-cert

在 /root/dev/bin 创建一个脚本 update_cert.sh 内容如下:

#!/bin/bash

pushd /tmp

kubectl create secret tls tls-cert --cert=wbuntu.crt --key=wbuntu.key --dry-run=client -o yaml > /tmp/tls-cert.yaml

if kubectl -n kube-system get secret tls-cert &> /dev/null; then
    echo "creating secret: kube-system/tls-cert..."
    kubectl -n kube-system replace -f /tmp/tls.yaml
else
    echo "updating secret: kube-system/tls-cert..."
    kubectl -n kube-system apply -f /tmp/tls.yaml
fi
popd

然后执行安装证书命令:

acme.sh --install-cert -d wbuntu.com --key-file /tmp/wbuntu.key --fullchain-file /tmp/wbuntu.crt --reloadcmd "/root/dev/bin/update_cert.sh"

最后检查下 secret:

➜  ~ kubectl -n kube-system get secret tls-cert
NAME       TYPE                DATA   AGE
tls-cert   kubernetes.io/tls   2      575d

可以看到证书成功创建出来了,如果部署了 web 服务并通过 ingressroute 暴露了出来,就可以在浏览器中查看到证书信息: