欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

使用 acme.sh+ZeroSSL 在入口处自动更新免费 https 证书

最编程 2024-03-05 14:42:26
...

本文介绍了如何使用acme.sh和ZeroSSL CA自动更新k8s的ingress中的免费https服务器证书。首先安装acme.sh,然后生成https证书,包括注册账号和申请证书,最后使用自定义的Shell脚本更新ingress中的https证书,并配置crontab在https证书文件更新后自动调用该脚本更新k8s secrets。

安装acme.sh

可以使用官网或者Github的Shell脚本在线安装,也可以将项目git clone到本地后安装,这里选择后一种更加灵活的安装方式:

yum install git -y
git clone https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install  \
--home /opt/acme.sh \
--config-home /opt/acme.sh/configs \
--cert-home /opt/acme.sh/certs \
--accountemail  "postmaster@ityoudao.cn" \
--useragent "d0-dev@ityoudao."
  • 其中,--home参数指定安装主目录,默认值为~/.acme.sh--config-home参数指定生成的各种文件存放目录,默认值为--home指定的目录;--cert-home参数指定生成的证书和密钥文件存放目录,默认值为--config-home指定的目录;--accountemail参数指定用户的邮箱,证书到期可能会收到邮件提醒,注意修改为自己的邮箱;--useragent参数指定发送给CA厂商的请求的user-agent头,随便填写。访问acme.sh的安装文档可以查看详细的安装文档。
  • 我们稍微关注一下它的输出,看看它做了哪些事:
# 安装到/opt/acme.sh目录
[Sat Jan 13 17:40:04 CST 2024] Installing to /opt/acme.sh
[Sat Jan 13 17:40:04 CST 2024] Installed to /opt/acme.sh/acme.sh
# 修改了.bashrc、.cshrc、.tcshrc文件
[Sat Jan 13 17:40:04 CST 2024] Installing alias to '/root/.bashrc'
[Sat Jan 13 17:40:04 CST 2024] OK, Close and reopen your terminal to start using acme.sh
[Sat Jan 13 17:40:04 CST 2024] Installing alias to '/root/.cshrc'
[Sat Jan 13 17:40:04 CST 2024] Installing alias to '/root/.tcshrc'
# 修改了crontab
[Sat Jan 13 17:40:05 CST 2024] Installing cron job
no crontab for root
no crontab for root
[Sat Jan 13 17:40:05 CST 2024] Good, bash is found, so change the shebang to use bash as preferred.
[Sat Jan 13 17:40:08 CST 2024] OK

# 初始化LE_WORKING_DIR、LE_CONFIG_HOME两个环境变量,添加了acme.sh命令行别名
[root@k8s-master acme.sh]# tail -n 1 /root/.bashrc 
. "/opt/acme.sh/acme.sh.env"
[root@k8s-master acme.sh]# cat "/opt/acme.sh/acme.sh.env"
export LE_WORKING_DIR="/opt/acme.sh"
export LE_CONFIG_HOME="/opt/acme.sh/configs"
alias acme.sh="/opt/acme.sh/acme.sh --config-home '/opt/acme.sh/configs'"

# crontab中配置了证书自动更新任务
[root@k8s-master acme.sh]# crontab -l
5 4 * * * "/opt/acme.sh"/acme.sh --cron --home "/opt/acme.sh" --config-home "/opt/acme.sh/configs" > /dev/null

生成https证书

acme.sh支持Let’s Encrypt、ZeroSSL、Google、Buypass、SSL.com等常见的免费https证书的CA厂商,这几个CA厂商的对比如下:
CA厂商的对比

以前acme.sh的默认CA厂商是Let’s Encrypt,从2021年发布的v3.0版本开始,默认CA厂商换成了ZeroSSL。可以使用acme.sh --set-default-ca --server letsencrypt命令设置默认CA厂商,也可以在一些命令中添加--server letsencrypt参数直接指定CA厂商,详细的配置参考Server。这里使用默认的ZeroSSL CA,访问使用ZeroSSL.com CA查看使用ZeroSSL CA生成https证书的详细步骤。

在CA厂商申请https证书需要校验域名所有权,可以使用http方式验证,也可以使用dns方式验证,这里选择让acme.sh自动配置dns的验证方式。

  1. 登录DNS服务提供商的控制台,获取拥有修改DNS解析权限的AccessKey。这里使用的是腾讯云,登录腾讯云控制台,创建子账号,获取SecretId和SecretKey:
用户名: acme.sh
访问方式: 编程访问
用户权限: QcloudDNSPodFullAccess(云解析 DNS 全读写访问权限)
SecretId: AKIDgFcosutiN2X8asxxxxxxxxxxxxxxxxxx 
SecretKey: 7EMl7NQI5oV1Mhv7xxxxxxxxxxxxxxxx
  1. 使用acme.sh --register-account命令注册ZeroSSL.com的账号,注意改为自己的邮箱:
source /root/.bashrc
acme.sh --register-account -m postmaster@ityoudao.cn --server zerossl
  • 返回Registered代表账号注册成功了:
[root@k8s-master acme.sh]# source /root/.bashrc
[root@k8s-master acme.sh]# acme.sh --register-account -m postmaster@ityoudao.cn --server zerossl
[Sat Jan 13 18:01:48 CST 2024] Create account key ok.
[Sat Jan 13 18:01:48 CST 2024] No EAB credentials found for ZeroSSL, let's get one
[Sat Jan 13 18:01:50 CST 2024] Registering account: https://acme.zerossl.com/v2/DV90
[Sat Jan 13 18:01:56 CST 2024] Registered
[Sat Jan 13 18:01:57 CST 2024] ACCOUNT_THUMBPRINT='i3JMAVGCs4ihDamGIQGDgxxxxxxxxxxxxxxxxxxxxxx'
  1. 使用acme.sh --issue命令申请https证书:
# 设置SecretId和SecretKey两个环境变量
# https://github.com/acmesh-official/acme.sh/blob/master/dnsapi/dns_tencent.sh
export Tencent_SecretId="AKIDgFcosutiN2X8asxxxxxxxxxxxxxxxxxx"
export Tencent_SecretKey="7EMl7NQI5oV1Mhv7xxxxxxxxxxxxxxxx"

# 申请https证书
acme.sh --issue --dns dns_tencent -d *.dev.ityoudao.cn -d dev.ityoudao.cn
  • 如果遇到报错,可以添加--debug参数查看详细日志;另外,可以添加--force参数强制更新证书(比如在下次更新日期之前强制更新证书)。

  • 如果使用阿里云或者DNSPod的DNS服务,申请https证书的方法如下:

# 阿里云
export Ali_Key="LTAI5tDBRV2fxxxxxxxxxxxx"
export Ali_Secret="0tLWTpemxLCkm1oxxxxxxxxxxxxxxx"
acme.sh --issue --dns dns_ali -d *.dev.ityoudao.cn

# DNSPod
export DP_Id='220xxx'
export DP_Key='815607ebc4ba6006xxxxxxxxxxxxxxxx'
acme.sh --issue --dns dns_dp -d *.dev.ityoudao.cn
  • 更多云厂商的DNS API配置参考DNS API

  • 我们看看它的输出,以便遇到报错时更容易判断问题出在哪里:

[root@k8s-master acme.sh]# export Tencent_SecretId="AKIDgFcosutiN2X8asxxxxxxxxxxxxxxxxxx"
[root@k8s-master acme.sh]# export Tencent_SecretKey="7EMl7NQI5oV1Mhv7xxxxxxxxxxxxxxxx"
[root@k8s-master acme.sh]# acme.sh --issue --dns dns_tencent -d *.dev.ityoudao.cn -d dev.ityoudao.cn
# 使用ZeroSSL CA,符合预期
[Sat Jan 13 18:07:37 CST 2024] Using CA: https://acme.zerossl.com/v2/DV90
# 创建私钥,位于/opt/acme.sh/certs/*.dev.ityoudao.cn_ecc/*.dev.ityoudao.cn.key
[Sat Jan 13 18:07:37 CST 2024] Creating domain key
[Sat Jan 13 18:07:37 CST 2024] The domain key is here: /opt/acme.sh/certs/*.dev.ityoudao.cn_ecc/*.dev.ityoudao.cn.key
# 配置DNS解析记录_acme-challenge,以便验证域名所有权
[Sat Jan 13 18:07:37 CST 2024] Multi domain='DNS:*.dev.ityoudao.cn,DNS:dev.ityoudao.cn'
[Sat Jan 13 18:07:37 CST 2024] Getting domain auth token for each domain
[Sat Jan 13 18:07:48 CST 2024] Getting webroot for domain='*.dev.ityoudao.cn'
[Sat Jan 13 18:07:48 CST 2024] Getting webroot for domain='dev.ityoudao.cn'
[Sat Jan 13 18:07:48 CST 2024] Adding txt value: IStQgGQiveey89NQInLhQpfpnS44BCaDkI0gRq17C18 for domain:  _acme-challenge.dev.ityoudao.cn
[Sat Jan 13 18:07:53 CST 2024] The txt record is added: Success.
[Sat Jan 13 18:07:53 CST 2024] Adding txt value: tKWdhO0Agr8OKLCpavdCjuFxtKD9f3h7TQmwgpNTzO4 for domain:  _acme-challenge.dev.ityoudao.cn
[Sat Jan 13 18:07:57 CST 2024] The txt record is added: Success.
# 等待DNS解析记录_acme-challenge生效,如果因为网络等原因无法在本地验证DNS解析记录是否生效,
# 可以使用`--dnssleep`参数跳过跳过自动校验,比如添加`--dnssleep 120`参数强制等待120秒,
# 120秒后新添加的DNS解析记录一般都生效了,然后执行下一步操作
[Sat Jan 13 18:07:57 CST 2024] Let's check each DNS record now. Sleep 20 seconds first.
[Sat Jan 13 18:08:18 CST 2024] You can use '--dnssleep' to disable public dns checks.
[Sat Jan 13 18:08:18 CST 2024] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck
[Sat Jan 13 18:08:18 CST 2024] Checking dev.ityoudao.cn for _acme-challenge.dev.ityoudao.cn
[Sat Jan 13 18:08:19 CST 2024] Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 35
[Sat Jan 13 18:08:26 CST 2024] Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 7
[Sat Jan 13 18:08:27 CST 2024] Domain dev.ityoudao.cn '_acme-challenge.dev.ityoudao.cn' success.
[Sat Jan 13 18:08:27 CST 2024] Checking dev.ityoudao.cn for _acme-challenge.dev.ityoudao.cn
[Sat Jan 13 18:08:27 CST 2024] Domain dev.ityoudao.cn '_acme-challenge.dev.ityoudao.cn' success.
[Sat Jan 13 18:08:27 CST 2024] All success, let's return
# 等待CA厂商验证域名所有权
[Sat Jan 13 18:08:27 CST 2024] Verifying: *.dev.ityoudao.cn
[Sat Jan 13 18:08:29 CST 2024] Processing, The CA is processing your order, please just wait. (1/30)
[Sat Jan 13 18:08:35 CST 2024] Success
[Sat Jan 13 18:08:35 CST 2024] Verifying: dev.ityoudao.cn
[Sat Jan 13 18:08:37 CST 2024] Processing, The CA is processing your order, please just wait. (1/30)
[Sat Jan 13 18:08:43 CST 2024] Success
# 移除DNS解析记录_acme-challenge
[Sat Jan 13 18:08:43 CST 2024] Removing DNS records.
[Sat Jan 13 18:08:43 CST 2024] Removing txt: IStQgGQiveey89NQInLhQpfpnS44BCaDkI0gRq17C18 for domain: _acme-challenge.dev.ityoudao.cn
[Sat Jan 13 18:08:49 CST 2024] Removed: Success
[Sat Jan 13 18:08:49 CST 2024] Removing txt: tKWdhO0Agr8OKLCpavdCjuFxtKD9f3h7TQmwgpNTzO4 for domain: _acme-challenge.dev.ityoudao.cn
[Sat Jan 13 18:08:55 CST 2024] Removed: Success
# 等待CA厂商下发证书
[Sat Jan 13 18:08:55 CST 2024] Verify finished, start to sign.
[Sat Jan 13 18:08:55 CST 2024] Lets finalize the order.
[Sat Jan 13 18:08:55 CST 2024] Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/om6evn7xxxxxxx-Rb7bpCA/finalize'
[Sat Jan 13 18:09:02 CST 2024] Order status is processing, lets sleep and retry.
[Sat Jan 13 18:09:02 CST 2024] Retry after: 15
[Sat Jan 13 18:09:18 CST 2024] Polling order status: https://acme.zerossl.com/v2/DV90/order/om6evn7xxxxxxx-Rb7bpCA
[Sat Jan 13 18:09:34 CST 2024] Order status is processing, lets sleep and retry.
[Sat Jan 13 18:09:34 CST 2024] Retry after: 15
[Sat Jan 13 18:09:50 CST 2024] Polling order status: https://acme.zerossl.com/v2/DV90/order/om6evn7xxxxxxx-Rb7bpCA
# 下载证书
[Sat Jan 13 18:10:09 CST 2024] Downloading cert.
[Sat Jan 13 18:10:09 CST 2024] Le_LinkCert='https://acme.zerossl.com/v2/DV90/cert/3xXyf7wxxxxxxxx-HKEVeA'
[Sat Jan 13 18:10:30 CST 2024] Cert success.
# 证书的信息
-----BEGIN CERTIFICATE-----
MIIEFzCCA5ygAwIBAgIRALiAkJeSxpqkjEsVCC7GUL4wCgYIKoZIzj0EAwMwSzEL
MAkGA1UEBhMCQVQxEDAOBgNVBAoTB1plcm9TU0wxKjAoBgNVBAMTIVplcm9TU0wg
RUNDIERvbWFpbiBTZWN1cmUgU2l0ZSBDQTAeFw0yNDAxMTMwMDAwMDBaFw0yNDA0
MTIyMzU5NTlaMBwxGjAYBgNVBAMMESouZGV2Lml0eW91ZGFvLmNuMFkwEwYHKoZI
zj0CAQYIKoZIzj0DAQcDQgAE9KLYb2ie9vJYoOTq95vp+CVRm7Y2TV0VjTpnm8u0
bo2KEOkjxDaFujMsEPUy2k4ibDnFsDeaQcY1QpQo5KWgo6OCAo4wggKKMB8GA1Ud
IwQYMBaAFA9r5kvOOUeu9n6QHnnwMJGSyF+jMB0GA1UdDgQWBBT1yLyrOmeq7fry
jztY7sm6r5E6FTAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHSUE
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwSQYDVR0gBEIwQDA0BgsrBgEEAbIxAQIC
TjAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwB
AgEwgYgGCCsGAQUFBwEBBHwwejBLBggrBgEFBQcwAoY/aHR0cDovL3plcm9zc2wu
Y3J0LnNlY3RpZ28uY29tL1plcm9TU0xFQ0NEb21haW5TZWN1cmVTaXRlQ0EuY3J0
MCsGCCsGAQUFBzABhh9odHRwOi8vemVyb3NzbC5vY3NwLnNlY3RpZ28uY29tMIIB
BAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYAdv+IPwq2+5VRwmHM9Ye6NLSkzbsp3GhC
Cp/mZ0xaOnQAAAGNAkwnKAAABAMARzBFAiEA8c8BDIFdr0B433fwoYtM94e8o1ax
YdUM68RTNKs57loCIC9gpP/0XRkM9JzCqgeAIYfSXveH65mjF+6bE3ceYzE4AHYA
O1N3dT4tuYBOizBbBv5AO2fYT8P0x70ADS1yb+H61BcAAAGNAkwnrAAABAMARzBF
AiEAozyTbFItJfvky9uWWXA9/vBN4O2u0i/pPSfQoMsGZckCIFr0ZbRc93HIi7+u
/6Ns/pjUDnyONWb1Hd8GhkunXVuyMC0GA1UdEQQmMCSCESouZGV2Lml0eW91ZGFv
LmNugg9kZXYuaXR5b3VkYW8uY24wCgYIKoZIzj0EAwMDaQAwZgIxAIhdcmQCNmme
3QoQWOHKuGaCuYiUrKO5ktBBoeHx6OQ8JdN5jF3yqa7IZD/0K6D17wIxAJgFZlFN
UsH3XHR19mWhi169MOUfrVeg15ok3p1GcZ9eomf1855FQ+pz6eJ5pVmFBg==
-----END CERTIFICATE-----
# 汇总生成的证书和密钥文件,分别是证书、密钥、中间CA证书(ZeroSSL CA)、包含完整证书链的证书
[Sat Jan 13 18:10:30 CST 2024] Your cert is in: /opt/acme.sh/certs/*.dev.ityoudao.cn_ecc/*.dev.ityoudao.cn.cer
[Sat Jan 13 18:10:30 CST 2024] Your cert key is in: /opt/acme.sh/certs/*.dev.ityoudao.cn_ecc/*.dev.ityoudao.cn.key
[Sat Jan 13 18:10:30 CST 2024] The intermediate CA cert is in: /opt/acme.sh/certs/*.dev.ityoudao.cn_ecc/ca.cer
[Sat Jan 13 18:10:30 CST 2024] And the full chain certs is there: /opt/acme.sh/certs/*.dev.ityoudao.cn_ecc/fullchain.cer
  1. 使用acme.sh --install-cert命令安装https证书
  • nginx和apache安装https证书的示例如下:
# 宿主机上使用systemd部署的nginx
acme.sh --install-cert -d ityoudao.cn \
--key-file       /opt/nginx/conf/all.ityoudao.cn.key \
--fullchain-file /opt/nginx/conf/all.ityoudao.cn.pem \
--reloadcmd     "systemctl force-reload nginx.service"

# 使用docker容器部署的nginx
acme.sh --install-cert -d jumpserver.ityoudao.cn \
--key-file       /opt/jumpserver/config/nginx/cert/server.key  \
--fullchain-file /opt/jumpserver/config/nginx/cert/server.crt \
--reloadcmd     "docker restart jms_web"

# 宿主机上部署的apache
acme.sh --install-cert -d online.domain.com \
--cert-file /etc/apache2/2.2/ssl/online.domain.com-cert.pem \
--key-file /etc/apache2/2.2/ssl/online.domain.com-key.pem \
--fullchain-file /etc/apache2/2.2/ssl/letsencrypt.pem \
--reloadcmd "service apache2 force-reload"
  • 注意https证书和密钥的路径,必须和nginx或者apache配置文件中指定的路径一致。
  • 下次证书自动更新之后,acme.sh会自动执行acme.sh --install-cert命令安装新的https证书。

因为我们的k8s集群存在多套免费的https证书,因此没有使用acme.sh --install-cert命令安装https证书,而是使用crontab的方式,在acme.sh更新完全部证书之后,自动调用自定义Shell脚本统一安装新的https证书。

  1. 使用acme.sh --info命令查看https证书信息
[root@k8s-master acme.sh]# acme.sh --info -d *.dev.ityoudao.cn
[Sat Jan 13 18:40:41 CST 2024] The domain '*.dev.ityoudao.cn' seems to have a ECC cert already, lets use ecc cert.
DOMAIN_CONF=/opt/acme.sh/certs/*.dev.ityoudao.cn_ecc/*.dev.ityoudao.cn.conf
Le_Domain=*.dev.ityoudao.cn
Le_Alt=dev.ityoudao.cn
Le_Webroot=dns_tencent
Le_PreHook=
Le_PostHook=
Le_RenewHook=
Le_API=https://acme.zerossl.com/v2/DV90
Le_Keylength=ec-256
Le_OrderFinalize=https://acme.zerossl.com/v2/DV90/order/om6evn7xxxxxxx-Rb7bpCA/finalize
Le_LinkOrder=https://acme.zerossl.com/v2/DV90/order/om6evn7xxxxxxx-Rb7bpCA
Le_LinkCert=https://acme.zerossl.com/v2/DV90/cert/3xXyf7wxxxxxxxx-HKEVeA
Le_CertCreateTime=1705140630
Le_CertCreateTimeStr=2024-01-13T10:10:30Z
Le_NextRenewTimeStr=2024-03-12T10:10:30Z
Le_NextRenewTime=1710238230
  • 输出的信息其实来自于/opt/acme.sh/certs/*.dev.ityoudao.cn_ecc/*.dev.ityoudao.cn.conf,里面包含了证书的域名Le_Domain、X509v3主题备选名称Le_Alt、创建日期Le_CertCreateTimeStr和下次更新日期Le_NextRenewTimeStr(60天之后自动更新)、安装证书之后的reload命令Le_ReloadCmd等信息,可以直接编辑该文件来修改下次更新、安装证书的配置。
  1. 查看生成的配置、证书和密钥等文件
# 1. 生成的配置文件目录
[root@k8s-master acme.sh]# ll /opt/acme.sh/configs/
total 8
-rw-r--r-- 1 root root 462 Jan 13 18:10 account.conf
drwxr-xr-x 3 root root  30 Jan 13 18:01 ca
-rw-r--r-- 1 root root 421 Jan 13 18:10 http.header
# 查看账号配置,如果更换了SecretKey,可以直接改这里的参数
[root@k8s-master acme.sh]# cat /opt/acme.sh/configs/account.conf | egrep -v '^ *$'
#LOG_FILE="/opt/acme.sh/configs/acme.sh.log"
#LOG_LEVEL=1
#AUTO_UPGRADE="1"
#NO_TIMESTAMP=1
CERT_HOME='/opt/acme.sh/certs'
ACCOUNT_EMAIL='postmaster@ityoudao.cn'
UPGRADE_HASH='afacdfcb95e063325d8fxxxxxxxxxxxxxxxxxxxx'
USER_AGENT='d0-dev@ityoudao.'
SAVED_Tencent_SecretId='AKIDgFcosutiN2X8asxxxxxxxxxxxxxxxxxx'
SAVED_Tencent_SecretKey='7EMl7NQI5oV1Mhv7xxxxxxxxxxxxxxxx'
USER_PATH='/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin'

# 2. 生成的证书和密钥目录
[root@k8s-master acme.sh]# ll /opt/acme.sh/certs/
total 0
drwxr-xr-x 2 root root 192 Jan 13 18:10 *.dev.ityoudao.cn_ecc
[root@k8s-master acme.sh]# ll /opt/acme.sh/certs/\*.dev.ityoudao.cn_ecc/
total 32
-rw-r--r-- 1 root root 2668 Jan 13 18:10 ca.cer
-rw-r--r-- 1 root root 1480 Jan 13 18:10 *.dev.ityoudao.cn.cer
-rw-r--r-- 1 root root  579 Jan 13 18:10 *.dev.ityoudao.cn.conf
-rw-r--r-- 1 root root  497 Jan 13 18:07 *.dev.ityoudao.cn.csr
-rw-r--r-- 1 root root  210 Jan 13 18:07 *.dev.ityoudao.cn.csr.conf
-rw------- 1 root root  227 Jan 13 18:07 *.dev.ityoudao.cn.key
-rw-r--r-- 1 root root 4148 Jan 13 18:10 fullchain.cer
# 查看证书请求文件
[root@k8s-master acme.sh]# openssl req -text -noout -in /opt/acme.sh/certs/\*.dev.ityoudao.cn_ecc/\*.dev.ityoudao.cn.csr
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: CN=*.dev.ityoudao.cn
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub: 
                    04:f4:a2:d8:6f:68:9e:f6:f2:58:a0:e4:ea:f7:9b:
                    e9:f8:25:51:9b:b6:88:4d:5d:15:8d:3a:67:9b:cb:
                    b4:6e:8d:8a:10:e9:23:c4:b1:85:ba:33:b1:10:f5:
                    32:da:4e:22:6c:39:c5:b0:37:9a:41:c6:35:42:94:
                    28:e4:a5:a0:a3
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        Attributes:
        Requested Extensions:
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication, TLS Web Client Authentication
            X509v3 Subject Alternative Name: 
                DNS:*.dev.ityoudao.cn, DNS:dev.ityoudao.cn
    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:20:13:27:a3:ef:54:4d:ca:88:88:d8:05:a5:69:ac:
         0a:02:5e:67:cc:67:b1:d8:4d:e2:9f:19:f5:90:20:62:a8:c3:
         02:21:00:ad:d4:a3:9b:c4:43:8e:1c:3e:e5:78:a4:51:8d:0e:
         1e:71:b6:90:bb:f2:67:b5:98:4f:3b:06:0b:b1:cd:32:1c
# 查看证书请求配置文件,以后我们用openssl生成服务器证书、客户端证书时可以参考该配置
[root@k8s-master acme.sh]# cat /opt/acme.sh/certs/\*.dev.ityoudao.cn_ecc/\*.dev.ityoudao.cn.csr.conf | grep -v '^$'
[ req_distinguished_name ]
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ v3_req ]
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=DNS:*.dev.ityoudao.cn,DNS:dev.ityoudao.cn
  1. 后面再生成其他https证书,只需要执行acme.sh --issue命令申请https证书和acme.sh --install-cert命令安装https证书(可选)即可,比如这里再生成一个单域名证书:
acme.sh --issue --dns dns_tencent -d business-dev.ityoudao.cn

更新ingress中的https证书

我们的k8s集群中主要使用泛域名,比如开发环境为*.dev.ityoudao.cn,对应ingress中配置的secret名称为all.dev.ityoudao.cn(将泛域名中的*替换为all);同时兼容以前配置的少量不太符合规范的单域名,比如business-dev.ityoudao.cn,对应ingress中配置的secret名称为business-dev.ityoudao.cn(secret名称和单域名一样)。另外,每个业务用到的名字空间都创建这些k8s secret。

  1. 完整的Shell脚本/opt/acme.sh/renew-secrets.sh如下:
# d0-dev@ityoudao
# 更新哪些域名的证书
DOMAIN_LIST="*.dev.ityoudao.cn business-dev.ityoudao.cn"
# 更新哪些名字空间的证书
NAMESPACES="default odcp ops"
CERTS_DIR=/opt/acme.sh/certs

# 带`--force`参数强制更新k8s secrets,否则当且仅当证书serial变化了才更新k8s secrets
if [ "$1" == "--force" ]; then IS_FORCE=1; else IS_FORCE=0; fi

logger -t acme.sh "Starting to renew the certificate of these domains: ${DOMAIN_LIST}"
for DOMAIN in $DOMAIN_LIST
do
    logger -t acme.sh "Starting to renew the certificate of this domain: ${DOMAIN}"
    # 获取证书和密钥文件名
    FILENAME_CERT="${CERTS_DIR}/${DOMAIN}_ecc/${DOMAIN}.cer"
    FILENAME_KEY="${CERTS_DIR}/${DOMAIN}_ecc/${DOMAIN}.key"
    # 获取k8s secrets名称
    if [[ ${DOMAIN} =~ ^\*.* ]]; then
        #SECRET_NAME=$(echo ${DOMAIN} | sed 's/\*/all/g')
        SECRET_NAME="${DOMAIN/\*/all}"
    else
        SECRET_NAME=${DOMAIN}
    fi
    logger -t acme.sh "Kubernetes secret name is ${SECRET_NAME}"
    # 检查k8s secrets是否存在
    kubectl get secret -n default ${SECRET_NAME} &> /dev/null
    if [ $? -ne 0 ]; then  
        logger -t acme.sh "Kubernetes secret default/${SECRET_NAME} does not exist, will create it."
        IS_FORCE=1
    fi
    # 检查k8s secrets中的证书是否需要更新
    if [ $IS_FORCE -eq 1 ]; then
        logger -t acme.sh "Forced renewing kubernetes secrets for ${DOMAIN}."
    elif [ "$(openssl x509 -noout -serial -in ${FILENAME_CERT})" != "$(openssl x509 -noout -serial -in  <(kubectl get secret -n default ${SECRET_NAME} -o jsonpath='{.data.tls\.crt}'|base64 -d))" ]; then
        logger -t acme.sh "Need to renew kubernetes secrets for ${DOMAIN}."
    else
        logger -t acme.sh "No need to renew kubernetes secrets for ${DOMAIN}."
        continue
    fi
    # 更新k8s secrets
    for NAMESPACE in ${NAMESPACES}
    do
        kubectl create secret tls -n ${NAMESPACE} ${SECRET_NAME} --cert=${FILENAME_CERT} --key=${FILENAME_KEY} --dry-run=client -o yaml | kubectl apply  -f -
        # v1.16
        # kubectl create secret tls -n ${NAMESPACE} ${SECRET_NAME} --cert=${FILENAME_CERT} --key=${FILENAME_KEY} --dry-run=true -o yaml | kubectl apply  -f -
        logger -t acme.sh "Kubernetes secret ${NAMESPACE}/${SECRET_NAME} has been renewed."
    done
done
  1. 执行一下该Shell脚本,第一次会创建新的secrets:
[root@k8s-master acme.sh]# bash /opt/acme.sh/renew-secrets.sh
secret/all.dev.ityoudao.cn created
secret/all.dev.ityoudao.cn created
secret/all.dev.ityoudao.cn created
secret/business-dev.ityoudao.cn created
secret/business-dev.ityoudao.cn created
secret/business-dev.ityoudao.cn created
  1. 修改crontab以便在acme.sh更新完全部证书之后,自动调用该Shell脚本更新ingress中的https证书:
# crontab -e
5 4 * * * "/opt/acme.sh"/acme.sh --cron --home "/opt/acme.sh" --config-home "/opt/acme.sh/configs" > /dev/null && bash /opt/acme.sh/renew-secrets.sh

至此配置完成!总结一下,本文介绍了使用acme.sh和ZeroSSL自动更新k8s ingress中的免费https证书的详细步骤。通过安装acme.sh,注册ZeroSSL账号,生成和安装https证书,以及使用Shell脚本自动更新ingress证书,实现了一套简便而有效的证书管理系统,可以在开发或者测试环境中使用该免费https证书的方案。