写点什么

用 Terraform 申请 Letsencrypt 证书

发布于: 2021 年 05 月 26 日

Let’s Encrypt 是一家全球性的证书颁发机构(CA)。他们让世界各地的人们和组织获取、续期和管理 SSL/TLS 证书。网站可以使用他们的证书来启用安全的 HTTPS 连接。


Let’s Encrypt 提供域名验证型(DV)证书。他们不提供组织验证(OV)或扩展验证(EV),这主要是因为他们无法自动化地颁发这些类型的证书。


他们不会对证书收取费用。Let’s Encrypt 是一个非营利性组织,他们的任务是通过促进 HTTPS 的广泛采用来创建一个更加安全和尊重隐私的 Web 环境。他们的服务免费且易于使用,因此每个网站都可以使用它来部署 HTTPS。


Let's Encrypt 使用 ACME 协议来自动化签发证书,通过支持 ACME 协议的客户端,首先由客户端向证书颁发机构证明该服务器拥有域名的控制权。之后,该客户端就可以申请、续期或吊销该域名的证书。


证明拥有域名的所有权有两种方法:


  • 在该域名下配置一条 TXT 类型的 DNS 记录

  • 在该域名指定 URI 下放置一个指定的 HTTP 资源


Let's Encrypt 官方推荐的客户端是 Certbot。Certbot 是一个免费开源的 Let's Encrypt 命令行客户端,由电子前哨基金会发行,目前 Let's Encrypt 主流的用法是使用该命令行客户端或是封装的 Docker 容器来调用 Let's Encrypt 服务生成证书。


Certbot 足够强大,但使用上还是略有不便,主要是 Certbot 主要是面向小型个人网站设计的,设计思路就是直接在托管站点的 Web 服务器上生成、替换证书。它支持 Apache、Nginx、Haproxy、Plesk 等主流服务器软件,但在云原生时代,这种在服务器上生成文件的方法还是略显陈旧。


Terraform 官方提供了一个插件:vancluever/acme,通过该插件可以使用 Terraform 代码生成 Let's Encrypt 证书。更加贴心的是,该 Provider 可以安全地反复执行terraform apply,它会检查当前证书的状态,如果没有证书,则申请一个新证书;如果存在证书且证书距离过期时间很短,那么它什么都不会做;如果证书快要过期,则会续期,并返回续期后的新证书。


直接上代码:


terraform {  required_providers {    acme = {      source  = "vancluever/acme"      version = "2.1.1"    }  }}
provider "acme" { server_url = "https://acme-v02.api.letsencrypt.org/directory"}
resource "tls_private_key" "private_key" { algorithm = "RSA"}
resource "acme_registration" "reg" { account_key_pem = tls_private_key.private_key.private_key_pem email_address = "xxx@hotmail.com"}
resource "acme_certificate" "lonegunman" { account_key_pem = acme_registration.reg.account_key_pem common_name = "www.lonegunman.xyz" key_type = "4096" dns_challenge { provider = "dnspod" config = { DNSPOD_API_KEY = var.dnspod_api_key DNSPOD_TTL = "600" DNSPOD_HTTP_TIMEOUT = "10m" } }}
output "privkey" { value = acme_certificate.lonegunman.private_key_pem}
output "cert" { value = "${acme_certificate.lonegunman.certificate_pem}${acme_certificate.lonegunman.issuer_pem}"}
复制代码


比较简单,里面要解释的部分有两点。


一是dns_challenge。该插件仅支持 DNS 证明,并且它支持大量 DNS 服务商的集成验证。这里我个人域名目前托管在 DNSPOD,也在支持列表之中,所以provider我们填写"dnspod"。DNSPOD 有一个坑,它生成的 API 密钥有 ID 和 Token 两部分,这里 DNSPOD_API_KEY 的值必须是以ID,Token的形式编码,否则 DNSPOD 会抱怨 Token 格式错误。


第二个问题是生成的服务器证书,也就是output "cert"的值。光是certificate_pem不包含证书签发者信息,并不足以构成一个合法的证书,所以必须以"${acme_certificate.lonegunman.certificate_pem}${acme_certificate.lonegunman.issuer_pem}"的形式拼接起来才是证书内容。


运行terraform apply后就如果一切顺利,那么就可以得到证书和密钥。



随后我们可以把证书以及密钥保存到例如 K8s Secret、AWS Parameter Store、Hashicorp Vault 等机密存储当中,再挂载到诸如 API Gateway、Ingress、Load Balancer 等服务中去。而且由于可以安全地反复执行terraform apply,我们可以使用 K8s Cronjob 或是 AWS Fargate 搭配 Cloudwatch Cron 定期续期证书。使用 Terraform 模块,我们可以轻松管理多个域名的证书的申请、定期续期、安全存储。

发布于: 2021 年 05 月 26 日阅读数: 13
用户头像

还未添加个人签名 2017.10.17 加入

还未添加个人简介

评论

发布
暂无评论
用Terraform申请Letsencrypt证书