使用acme.sh和acme-dns申请Google免费泛域名SSL证书

提醒:本文最后更新于 851 天前,文中所描述的信息可能已发生改变,请仔细核实。

上来,先给传送门,不想看唠叨,想直接进入正题,请点这里

好久不见,甚是想念,上一篇文章发表时间已经过去很久。这段时间确实忙,也有很多私人事,导致一直没更新。

说起来,Let’s Encrypt出来这么多年,我推荐过给很多人,但自己从未使用过,也没有实际操作过任何ACME客户端(想想其实也不是太好)。

恰遇目前域名两年期泛域名证书(所谓野卡)即将过期,赞助商也不再赞助了,所以考虑使用像Let’s Encrypt如此的免费自动化的证书颁发机构颁发的证书。

可能为了安全、防止滥用等各种原因(我猜,没有细究),这些机构颁发的证书大多为90天上限(也有付费给一年期的)。

也就是说一年下来,证书需要不断更新,而非一年一次或两年一次,手动更新证书蛮累的。所以催生基于使用ACME协议的自动签发客户端来获取证书。

这么多年过去了,ACME客户端发展得十分成熟,常见有Certbot、acme.sh等等,感兴趣的也可以通过这里查看其它客户端。

运气不错的是今年3月底Google刚刚推出了公共证书服务,即与Let’s Encrypt类似的自动化公共证书管理服务。目前处于内测阶段,签发服务需使用Google Cloud的API(Public Certificate Authority API),除激活该API外,还需申请资格。

它颁发的证书和Google各项服务使用相同的根证书GTS(Google Trust Services)。其OCSP有国内节点,未受阻断且速度不错。但GTS的ACME Endpoint被阻断,国内服务器正常来说因为访问不了签发服务器而签发不了。

这次我将使用acme.sh来签发其泛域名证书。因为泛域名证书是必须通过域名的TXT记录(也叫ACME Challenge)来验证域名归属的,所以顺便讲解如何使用acme-dns来自动生成验证记录。

也主要是我使用的域名服务商(Google Domain)并未提供REST API,也就是无法通过请求API来自动更新TXT记录(手动更新岂不累死)。所以只能使用acme-dns这个项目,它提供了一个专门用于TXT记录更新的简单API。

其实即便你的域名服务商他们提供API服务的话,我也十分推荐你使用ACME-DNS这个项目,因为这个API,它只有它自身域的TXT控制权限,而非你的域名的所有控制权限。如果你不想配置太多(或者说不在意太多),也可以参考acme.sh的DNSAPI说明来配置,这看个人选择。


啰嗦够多,让我们进入正题。

本文基于CentOS 8 x64和Nginx。Windows Server用户可以88了。

首先让我们申请下Google公共证书授权服务的使用资格。

这一过程,需要你准备一个GCP(Google Cloud Platform)账号,然后通过这里创建项目。

项目名称和项目ID随意,也可以自定义好记的,一会申请API时要用。

创建好了之后,去启用“Public Certificate Authority API”,找不到的可以通过如下地址(记得修改项目ID):

https://console.cloud.google.com/apis/library/publicca.googleapis.com?project=你的项目ID

接着到这里填写申请表申请测试资格。

带星号部分需要填写:

1.“电子邮箱地址”填写可以收到邮件的邮箱,审核通过后会发邮件给你(建议与GCP帐号相同)。

2.“Google Cloud Project ID”填写你刚刚新建好的项目ID(不记得就去GCP仪表盘复制黏贴一下)。

3.“Estimated usage”填写每季度你大概会签发多少张证书(根据你的实际)。

稍等一两个工作日,待你收到来自“Public CA Preview Access”发给你的邮件后,进入GCP,在你创建的项目下,在右上角点击“激活 Cloud Shell”,打开Google Cloud Shell。

在底部出来的Console命令行下,输入:

gcloud beta publicca external-account-keys create

可能会弹出提示让您授权访问权限,授权即可。随后便会得到b64MacKeykeyId,类似如下:

Created an external account key
[b64MacKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
keyId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]

得到密钥一会在acme.sh配置中使用,该密钥是有有效期的,所以要尽快使用。

接下来,让我们进入第二步,在服务器端,打开Shell界面,安装acme.sh和acme-dns。

yum install ca-certificates curl wget golang socat openssl openssl-libs openssl-devel crontabs -y
wget -O - https://get.acme.sh | sh
ldconfig
export GOPATH=/tmp/acme-dns/.lib
cd /tmp
git clone https://github.com/joohoi/acme-dns.git
cd acme-dns
go build
mkdir -p /etc/acme-dns/
cat acme-dns.service > /usr/lib/systemd/system/acme-dns.service
cp config.cfg /etc/acme-dns/config.cfg
mv acme-dns /usr/local/bin/acme-dns
setcap 'cap_net_bind_service=+ep' /usr/local/bin/acme-dns
useradd --system --user-group -m -d /var/lib/acme-dns acme-dns
systemctl daemon-reload

以上是我根据官方文档重写的脚本,复制黏贴即可。

其实修改acme-dns配置文件我也有自动化脚本,但每个人实际情况不一样,还是希望大家动手配置下。

如果你想懒且域名服务商提供API,那么你可以跳过下面这部分,查看acme.sh的配置。

那么在acme-dns配置文件/etc/acme-dns/config.cfg中,建议修改下面列举的这几项:

1.listen,你可以使用如“你域名对外IP:53”,或者监听全局的“:53”。
2.protocol,建议只选择“udp”。
3.domain和nsname按照实际(如果你会配的话),不会配的话,建议两个都使用“auth.你的域名”。
4.nsadmin填写你的邮箱,也可以保持不变。
5.records,根据第三点填写,如果你按我说的配,那么将本项内容中所有“auth.example.org”替换为“auth.你的域名”;“198.51.100.1”替换为“你域名对外IP:53”。
6.ip可以填写为“127.0.0.1”,如果你只是自用。
7.port不要与你服务器其他服务的端口冲突,你可以使用如“8053”。
8.tls填写为“none”,如果你刚刚第六点填写的ip项是对外ip,那么建议使用“letsencrypt”并设置acme_cache_dir为“/var/lib/acme-dns/cert”。

根据上面的配置后,记得放通你服务器防火墙的53端口流量。

然后,在Shell中,执行(根据上面写的第六、七、八点):

systemctl enable acme-dns
systemctl start acme-dns

export ACMEDNS_BASE_URL="http://127.0.0.1:8053"
curl -s -X POST $ACMEDNS_BASE_URL/register | python2 -m json.tool > /tmp/acme-dns.challenges
export ACMEDNS_USERNAME="$(cat /tmp/acme-dns.challenges | awk -F"\"" '/username/{print $4}')"
export ACMEDNS_PASSWORD="$(cat /tmp/acme-dns.challenges | awk -F"\"" '/password/{print $4}')"
export ACMEDNS_SUBDOMAIN="$(cat /tmp/acme-dns.challenges | awk -F"\"" '/subdomain/{print $4}')"
echo "FULLDOMAIN = $(cat /tmp/acme-dns.challenges | awk -F"\"" '/fulldomain/{print $4}')"

curl -X POST \
  -H "X-Api-User: $ACMEDNS_USERNAME" \
  -H "X-Api-Key: $ACMEDNS_PASSWORD" \
  -d "{\"subdomain\": \"$ACMEDNS_SUBDOMAIN\", \"txt\": \"___validation_token_received_from_the_ca___\"}" \
  $ACMEDNS_BASE_URL/update

看下最后得到的结果是不是:

{"txt": "___validation_token_received_from_the_ca___"}

是的话,说明acme-dns已经正常了。

再然后根据上面写的第五点和刚刚得到的FULLDOMAIN去你的域名服务商添加记录,如:

auth A 你域名对外IP
auth NS auth.你的域名
_acme-challenge.你的域名 CNAME FULLDOMAIN

那么在等DNS生效的期间,让我们来配置acme.sh。

acme.sh --set-default-ca --server google
acme.sh --register-account --server google -m <你的GCP邮箱> --eab-hmac-key <b64MacKey> --eab-kid <keyId>

acme.sh --issue --server google -d '*.你的域名' -d 你的域名 \
 --dns dns_acmedns --keylength ec-256 \
--cert-file /path/to/server.ecc.crt \
--key-file /path/to/server.ecc.key \
--fullchain-file /path/to/bundle.ecc.crt \
--ca-file /path/to/issuer.ecc.crt \
--reloadcmd "systemctl reload nginx"

acme.sh --issue --server google -d '*.你的域名' -d 你的域名 \
--dns dns_acmedns --keylength 2048 \
--cert-file /path/to/server.rsa.crt \
--key-file /path/to/server.rsa.key \
--fullchain-file /path/to/bundle.rsa.crt \
--ca-file /path/to/issuer.rsa.crt \
--reloadcmd "systemctl reload nginx"

这样就获得ECC和RSA双证书,其中/path/to/是你存放证书的路径(参考nginx配置文件)。

如果你刚刚没有配置acme-dns且你域名服务商提供了相应API,你可以参考acme.sh的DNSAPI说明找到你的域名服务商来配置,替换刚刚命令中dns_acmedns为对标的域名服务商API插件名。

至此,acme.sh和acme-dns便配置完了。现在acme.sh会自动每60天为你重新签约证书并重新加载nginx。

如果你需要邮件提醒的话,可以查阅acme.sh的set-notify说明

值得注意的是目前Google的ECC证书不提供完整ECDSA链,仅最终用户证书为ECC(Let's Encrypt是全链ECC)。

它也不支持Punycode编码的域名(类似xn--1.xn--2这种),虽然较其他签发商,它支持了IP地址签注,但仅限IP地址块的所有者进行验证。

还有就是GTS证书本身也使用到GlobalSign的根证书,所以兼容性会比较好。

最后补充一些图片:

来自“Public CA Preview Access”发过来的邮件:

证书路径:


其他备注:

启用“Public Certificate Authority API”,除了使用文中所提链接,也可以通过Cloud Shell执行以下命令启用:

gcloud config set project 你的项目ID
gcloud services enable publicca.googleapis.com

注意,如果你已经在你创建的项目页面下的话,可以不输入第一行。

转载请注明转自:kn007的个人博客的《使用acme.sh和acme-dns申请Google免费泛域名SSL证书