前言
因为Google Chrome和运营商劫持干扰访问者体验的努力推动了大型网站加速应用全站HTTPS,而Let's Encrypt这个项目通过自动化把配置和维护 HTTPS 变得更加简单,Let's Encrypt设计了一个 ACME 协议目前版本是v2,并在2018年支持通配符证书Wildcard Certificate Support is Live。官网主推的客户端是Certbot,任何人都可以基于 ACME 协议实现一个客户端,比如大名鼎鼎的acme.sh。本文主要使用certbot-dns-route53插件为例,由于certbot官方DNS Plugins插件支持有限,如果你需要支持aliyun/tencentyun/godaddy dns可以参考certbot-letencrypt-wildcardcertificates-alydns-au,随着Docker容器化和K8S(Kubernetes)的进击,相信会促进certbot多样化玩法。
使用certbot代替acme.sh免费申请wildcard通配符证书和自动更新实践小结
更新历史
2020年02月19日 - 初稿
阅读原文 - https://wsgzao.github.io/post...
基础知识
关于 HTTPS
引维基百科的说法
超文本传输安全协议(英语:Hypertext Transfer Protocol Secure,缩写:HTTPS)是一种网络安全传输协议。在计算机网络上,HTTPS经由超文本传输协议进行通信,但利用SSL/TLS来对数据包进行加密。HTTPS开发的主要目的,是提供对网络服务器的身份认证,保护交换数据的隐私与完整性
HTTPS的主要思想是在不安全的网络上创建一安全信道,并可在使用适当的加密包和服务器证书可被验证且可被信任时,对窃听和中间人攻击提供合理防护。
HTTPS的信任继承基于预先安装在浏览器中的证书颁发机构(如Symantec、Comodo、GoDaddy和GlobalSign等)(意即“我信任证书颁发机构告诉我应该信任的”)。因此,一个到某网站的HTTPS连接可被信任,当且且当:
- 用户相信他们的浏览器正确实现了HTTPS且安装了正确的证书颁发机构;
- 用户相信证书颁发机构仅信任合法的网站;
- 被访问的网站提供了一个有效的证书,意即,它是由一个被信任的证书颁发机构签发的(大部分浏览器会对无效的证书发出警告);
- 该证书正确地验证了被访问的网站(如,访问https://example.com 时收到了给 example.com 而不是其他组织的证书);
- 或者互联网上相关节点是值得信任的,或者用户相信本协议的加密层(TLS或SSL)不能被窃听者破坏。
HTTP 和 HTTPS 区别
HTTP 协议传输的数据都是未加密的,也就是明文的,因此使用 HTTP 协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了 SSL(Secure Sockets Layer)协议用于对 HTTP 协议传输的数据进行加密,从而就诞生了 HTTPS。简单来说,HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,要比 HTTP 协议安全。
HTTPS 和 HTTP 的区别主要如下:
- HTTPS 协议需要到 CA 申请证书,一般免费证书较少,因而需要一定费用。
- HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
- HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是 80,后者是 443。
- HTTP 的连接很简单,是无状态的;HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。
Types of SSL Certificates for a Secure Business Website
关于 TLS/SSL
传输层安全协议(英语:Transport Layer Security,缩写:TLS),及其前身安全套接层(Secure Sockets Layer,缩写:SSL)是一种安全协议,目的是为互联网通信,提供安全及数据完整性保障
为什么要部署 HTTPS
说到底,就是 HTTPS 更安全。甚至为了安全,一个专业可靠的网站, HTTPS 是必须的。 Firefox 和 Chrome 都计划将没有配置 SSL 加密的 HTTP 网站标记为不安全(貌似 Firefox 50 已经这么干了),目前它们也正在联合其他相关的基金会与公司推动整个互联网 HTTPS 化,现在大家访问的一些主要的网站。如 Google 多年前就已经全部启用 HTTPS ,国内的淘宝、搜狗、知乎、百度等等也全面 HTTPS 了。甚至 Google 的搜索结果也正在给予 HTTPS 的网站更高的排名和优先收录权。
怎么部署 HTTPS
你只需要有一张被信任的 CA ( Certificate Authority )也就是证书授权中心颁发的 SSL 安全证书,并且将它部署到你的网站服务器上。一旦部署成功后,当用户访问你的网站时,浏览器会在显示的网址前加一把小绿锁,表明这个网站是安全的,当然同时你也会看到网址前的前缀变成了 HTTPS ,不再是 HTTP 了。
怎么获得 SSL 安全证书
理论上,我们自己也可以签发 SSL 安全证书,但是我们自己签发的安全证书不会被主流的浏览器信任,所以我们需要被信任的证书授权中心( CA )签发的安全证书。而一般的 SSL 安全证书签发服务都比较贵,比如 Godaddy 、 GlobalSign 等机构签发的证书一般都需要 20 美金一年甚至更贵,不过为了加快推广 HTTPS 的普及, EEF 电子前哨基金会、 Mozilla 基金会和美国密歇根大学成立了一个公益组织叫 ISRG ( Internet Security Research Group ),这个组织从 2015 年开始推出了 Let’s Encrypt 免费证书。这个免费证书不仅免费,而且还相当好用,所以我们就可以利用 Let’s Encrypt 提供的免费证书部署 HTTPS 了
Let’s Encrypt简介
Let’s Encrypt 是 一个叫 ISRG ( Internet Security Research Group ,互联网安全研究小组)的组织推出的免费安全证书计划。参与这个计划的组织和公司可以说是互联网顶顶重要的先驱,除了前文提到的三个牛气哄哄的发起单位外,后来又有思科(全球网络设备制造商执牛耳者)、 Akamai 加入,甚至连 Linux 基金会也加入了合作,这些大牌组织的加入保证了这个项目的可信度和可持续性。
部署 HTTPS 网站的时候需要证书,证书由 CA 机构签发,大部分传统 CA 机构签发证书是需要收费的,这不利于推动 HTTPS 协议的使用。
Let’s Encrypt 也是一个 CA 机构,但这个 CA 机构是免费的!!!也就是说签发证书不需要任何费用。
Let’s Encrypt 由于是非盈利性的组织,需要控制开支,他们搞了一个非常有创意的事情,设计了一个 ACME 协议,目前该协议的版本是 v1。
那为什么要创建 ACME 协议呢,传统的 CA 机构是人工受理证书申请、证书更新、证书撤销,完全是手动处理的。而 ACME 协议规范化了证书申请、更新、撤销等流程,只要一个客户端实现了该协议的功能,通过客户端就可以向 Let’s Encrypt 申请证书,也就是说 Let’s Encrypt CA 完全是自动化操作的。
任何人都可以基于 ACME 协议实现一个客户端,官方推荐的客户端是Certbot 。
Let’s Encrypt 通配符证书
在没有出现通配符证书之前,Let’s Encrypt 支持两种证书。
1)单域名证书:证书仅仅包含一个主机。
2)SAN 证书:一张证书可以包括多个主机(Let’s Encrypt 限制是 20),也就是证书可以包含下列的主机:www.example.com、www.example.cn、blog.example.com 等等。
证书包含的主机可以不是同一个注册域,不要问我注册域是什么?注册域就是向域名注册商购买的域名。
对于个人用户来说,由于主机并不是太多,所以使用 SAN 证书完全没有问题,但是对于大公司来说有一些问题:
- 子域名非常多,而且过一段时间可能就要使用一个新的主机。
- 注册域也非常多。
读者可以思考下,对于大企业来说,SAN 证书可能并不能满足需求,类似于 sina 这样的网站,所有的主机全部包含在一张证书中,而使用 Let’s Encrypt 证书是无法满足的。
通配符证书就是证书中可以包含一个通配符,比如 .example.com、.example.cn,读者很快明白,大型企业也可以使用通配符证书了,一张证书可以防止更多的主机了。
这个功能可以说非常重要,从功能上看 Let’s Encrypt 和传统 CA 机构没有什么区别了,会不会触动传统 CA 机构的利益呢?
如何申请 Let’s Encrypt 通配符证书
为了实现通配符证书,Let’s Encrypt 对 ACME 协议的实现进行了升级,只有 v2 协议才能支持通配符证书。
也就是说任何客户端只要支持 ACME v2 版本,就可以申请通配符证书了,是不是很激动。
在了解该协议之前有几个注意点:
客户在申请 Let’s Encrypt 证书的时候,需要校验域名的所有权,证明操作者有权利为该域名申请证书,目前支持三种验证方式:
- dns-01:给域名添加一个 DNS TXT 记录。
- http-01:在域名对应的 Web 服务器下放置一个 HTTP well-known URL 资源文件。
- tls-sni-01:在域名对应的 Web 服务器下放置一个 HTTPS well-known URL 资源文件。
而申请通配符证书,只能使用 dns-01 的方式
Certbot简介
What’s Certbot?
Certbot is a free, open source software tool for automatically using Let’s Encrypt certificates on manually-administrated websites to enable HTTPS.
Certbot is made by the Electronic Frontier Foundation (EFF), a 501(c)3 nonprofit based in San Francisco, CA, that defends digital privacy, free speech, and innovation.
Certbot 的官方网站是 https://certbot.eff.org/ ,打开这个链接选择自己使用的 web server 和操作系统,EFF 官方会给出详细的使用方法,如果DNS在官方的支持插件列表中可以按官方文档操作,但如果是国内的DNS可以参考certbot-letencrypt-wildcardcertificates-alydns-au
DNS plugin's name on the Documentation list
certbot插件介绍
Certbot 现在需要运行在安装了Python (2.7 or 3.4)的类unix系统上,内存大于512MB(如果小于的话,官方解决方案),默认是需要root权限的,比如写证书操作需要root权限。
Certbot客户机支持获取和安装证书的两种插件:auth
和install
,当使用certonly参数的时候,只会获取证书,并不会安装证,获取的证书位于/etc/letsencrypt目录下
主要插件的介绍:
Getting certificates (and choosing plugins)
Plugin | Auth | Install | Notes | Challenge types (and port) |
---|---|---|---|---|
apache | Y | Y | 自动化获取并安装证书 | tls-sni-01 (443) |
webroot | Y | N | 已经有运行的服务,通过验证webroot目录来获取证书 | http-01 (80) |
nginx | Y | Y | 使用nginx自动获取和安装证书 | tls-sni-01 (443) |
standalone | Y | N | 建立一个standalone WEB服务,需要80或者443端口可用,如果你没有类似nginx和apache等服务,这很有用 | http-01 (80) or tls-sni-01 (443) |
DNS plugins | Y | N | 通过修改dns服务器的text记录,来获取证书,野卡证书只能通过此方式获取 | dns-01 (53) |
manual | Y | N | 通过自己给指令获取证书,支持添加定制脚本来完成任务 | http-01 (80), dns-01 (53) or tls-sni-01 (443) |
解析:
- 如果你使用standalone插件,那么需要使用80和443端口,因为要建一个监听这些端口的服务,如果你有别的服务使用了该端口,那么就会出问题了。
- webroot方式,如果你使用了nginx,那么你需要更改一些nginx配置,确保能验证你对该域名的所有权限
插件的具体使用可以参考letsencrypt证书-管理工具certbot
我个人推荐选择DNS plugins
或者 manual
方式来管理
certbot-dns-route53实践
因为域名在Amazon Route 53,所以选择使用certbot-dns-route53插件会比较方便,敏感信息都用xxx打码了但不影响阅读理解
https://github.com/certbot/ce...
# Create a virtual environment
pip install virtualenv
cd /root
virtualenv certbot
source certbot/bin/activate
# Update its pip and setuptools (VENV/bin/pip install -U setuptools pip) to avoid problems with cryptography's dependency on setuptools>=11.3.
certbot/bin/pip install -U setuptools pip
pip list
Package Version
---------- -------
pip 20.0.2
setuptools 44.0.0
wheel 0.34.2
# Make sure you have libssl-dev and libffi (or your regional equivalents) installed. You might have to set compiler flags to pick things up (I have to use CPPFLAGS=-I/usr/local/opt/openssl/include LDFLAGS=-L/usr/local/opt/openssl/lib on my macOS to pick up brew's openssl, for example).
pip install certbot-dns-route53
# create aws credentials
mkdir ~/.aws/
vim ~/.aws/credentials
[default]
aws_access_key_id=xxx
aws_secret_access_key=xxx
# generate certificate
certbot certonly \
-n --agree-tos --email xxx \
--dns-route53 \
-d "*.xxx"
(certbot) [root@xxx ~]# certbot certonly \
> -n --agree-tos --email xxx \
> --dns-route53 \
> -d "*.xxx"
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Found credentials in shared credentials file: ~/.aws/credentials
Plugins selected: Authenticator dns-route53, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for xxx
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/xxx/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/xxx/privkey.pem
Your cert will expire on 2020-05-19. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
certbot证书默认存放路径结构
All generated keys and issued certificates can be found in /etc/letsencrypt/live/$domain
. In the case of creating a SAN certificate with multiple alternative names, $domain
is the first domain passed in via -d parameter. Rather than copying, please point your (web) server configuration directly to those files (or create symlinks). During the renewal, /etc/letsencrypt/live
is updated with the latest necessary files.
# check letsencrypt directory
[root@xxx ~]# tree /etc/letsencrypt/
/etc/letsencrypt/
├── accounts
│ └── acme-v02.api.letsencrypt.org
│ └── directory
│ └── xxx
│ ├── meta.json
│ ├── private_key.json
│ └── regr.json
├── archive
│ └── xxx
│ ├── cert1.pem
│ ├── chain1.pem
│ ├── fullchain1.pem
│ └── privkey1.pem
├── csr
│ ├── 0000_csr-certbot.pem
│ └── 0001_csr-certbot.pem
├── keys
│ ├── 0000_key-certbot.pem
│ └── 0001_key-certbot.pem
├── live
│ ├── xxx
│ │ ├── cert.pem -> ../../archive/xxx/cert1.pem
│ │ ├── chain.pem -> ../../archive/xxx/chain1.pem
│ │ ├── fullchain.pem -> ../../archive/xxx/fullchain1.pem
│ │ ├── privkey.pem -> ../../archive/xxx/privkey1.pem
│ │ └── README
│ └── README
├── renewal
│ └── xxx.conf
└── renewal-hooks
├── deploy
├── post
└── pre
15 directories, 18 files
- live 目录下存放的将会链接到最新的证书和私钥
- csr keys 用来存放当前代理的授权密钥对
- account 用来存放证书的管理信息, 这里涉及ACME
- renewal 存放当前代理所管理的域的信息
如果是配置Nginx SSL证书,通常只需要按照下面这样修改即可
ssl_certificate /etc/letsencrypt/live/xxx/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/xxx/privkey.pem;
Certbot supports a lot of command line options. Here’s the full list, from certbot --help all
:
(certbot) [root@xxx ~]# certbot -h
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...
Certbot can obtain and install HTTPS/TLS/SSL certificates. By default,
it will attempt to use a webserver both for obtaining and installing the
certificate. The most common SUBCOMMANDS and flags are:
obtain, install, and renew certificates:
(default) run Obtain & install a certificate in your current webserver
certonly Obtain or renew a certificate, but do not install it
renew Renew all previously obtained certificates that are near
expiry
enhance Add security enhancements to your existing configuration
-d DOMAINS Comma-separated list of domains to obtain a certificate for
(the certbot apache plugin is not installed)
--standalone Run a standalone webserver for authentication
(the certbot nginx plugin is not installed)
--webroot Place files in a server's webroot folder for authentication
--manual Obtain certificates interactively, or using shell script
hooks
-n Run non-interactively
--test-cert Obtain a test certificate from a staging server
--dry-run Test "renew" or "certonly" without saving any certificates
to disk
manage certificates:
certificates Display information about certificates you have from Certbot
revoke Revoke a certificate (supply --cert-name or --cert-path)
delete Delete a certificate (supply --cert-name)
manage your account:
register Create an ACME account
unregister Deactivate an ACME account
update_account Update an ACME account
--agree-tos Agree to the ACME server's Subscriber Agreement
-m EMAIL Email address for important account notifications
More detailed help:
-h, --help [TOPIC] print this message, or detailed help on a topic;
the available TOPICS are:
all, automation, commands, paths, security, testing, or any of the
subcommands or plugins (certonly, renew, install, register, nginx,
apache, standalone, webroot, etc.)
-h all print a detailed help page including all topics
--version print the version number
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
certbot自动更新证书
简单介绍2种常见的需求,其他情况如使用容器renew的朋友相信应该都不用参考本文了
# 最简单的手动renew命令,看到success表示成功
certbot renew --force-renewal
(certbot) [root@xxx ~]# certbot renew --force-renewal
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/xxx.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found credentials in shared credentials file: ~/.aws/credentials
Plugins selected: Authenticator dns-route53, Installer None
Renewing an existing certificate
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/xxx/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/xxx/fullchain.pem (success)
使用crontab定期执行
# 编辑certbot_renew.sh,强制更新并重新reload nginx加载新证书
vim /root/certbot_renew.sh
#!/bin/bash
certbot renew --force-renew
nginx -s reload
# 如果是virtualenv虚拟环境可以这样写
#!/bin/bash
export PATH=$PATH:/usr/local/bin
source /root/source certbot/bin/activate
certbot renew --force-renew
nginx -s reload
# 添加执行权限
chmod a+x /root/certbot_renew.sh
# 设置定时任务自动更新证书,“At 01:01 on day-of-month 1.”
vim /etc/crontab
1 1 1 * * /root/certbot_renew.sh >/root/crontab.log 2>&1
# 如果需要记录日志可以这样写
1 1 1 * * echo `date -R` >> /var/log/certbot.crontab.log; certbot renew --force-renewal >> /var/log/certbot.crontab.log 2>&1; nginx -s reload
# certbot官方使用 python 产生了一个分钟的随机数,让更新时间随机一些
echo "0 0,12 * * * root python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew" | sudo tee -a /etc/crontab > /dev/null
参考文章
How To Secure Apache with Let's Encrypt on CentOS 7
How To Secure Nginx with Let's Encrypt on Ubuntu 18.04
How To Secure Apache with Let's Encrypt on Ubuntu 18.04
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。