前言很久很久以前,互联网大陆是一个野蛮开放的世界,在这片大陆上,任何人都可以发布网站、交换信息。然而野蛮的生长既带来了繁荣,也带来了混乱。一大批仿冒者开始蠢蠢欲动,一套马甲就可以假冒一个网站,被发现了换个马甲继续行骗。所有的私密信息都以明文的方式传递,传递途中更不知道被多少人窃听。不明真相的群众被骗的血本无归,既欺骗了广大的群众,又侵害了本尊的权益。随后,官方推出了一些列的举措整顿了互联网大陆。而在业界,一种加密的数字证书逐渐流行起来。这种证书不仅能认证网站所有者的身份,还可以起到传输数据加密、完整性验证、防篡改的功能。这就是 HTTPS 证书,一种简单却极其有效的解决方案。而到了今天,HTTPS 证书已经成为了支付交易,第三方调用(例如微信小程序)等场景的必备条件,也是不少网站安全防护的最低标准。然而,一般的证书签发机构申请一份 HTTPS 证书动辄需要一年几千几万,对于个人站长或小型企业来说也是一笔不小的费用。直到有一天,一个神秘的组织横空出世 —— Let's Encrypt 。这个组织的愿景是,让天下的网站都能用上证书,构建一个更安全的互联世界。这简直就是个人站长和中小型网站的福音啊!在 Let's Encrypt 组织的不断努力下,迄今已有超过 1.8 亿个网站申请了免费的 HTTPS 证书.虽然 Let's Encrypt 的免费证书已经推出了好多年,但是我仍旧发现不少网站还是没有证书,甚至是一些比较“知名”的网站也没有。比如说这位:可能他们的架还没吵完。HTTPS 证书?安全?不存在的!公章都没了!╮(╯▽╰)╭所以,我觉得还是有必要来唠唠这个证书的申请问题。顺便说下,当前流行的 Kubernetes 集群中的使用方法。申请 HTTPS 通配符证书在 Let's Encrypt 组织成立之初,证书只能一个域名一个域名申请,每个二级域名都需要重新申请新的证书。虽说证书的申请步骤可以做到完全自动化,不过一张全域名的通配符证书,对于较大型网站来说,还是非常必要的。终于,在 2018 年 3 月 13 日 Let's Encrypt 提供了通配符证书功能。接下来,我们就来申请一下 Let's Encrypt 的通配符证书。首先,我们来了解下 Let's Encrypt 申请证书的验证方式。Let's Encrypt 提供了三种方式来验证域名。http://<YOUR_DOMAIN>/.well-known/acme-challenge/<TOKEN>
_acme-challenge.<YOUR_DOMAIN>
而申请通配符证书,只支持第三种 DNS-01 验证方式。Let’s Encrypt 组织还很贴心的为不少 DNS 解析服务商 提供了自动整合申请。不过,别找了,大部分都是国外的,国内似乎只有阿里云 DNS。如果你的 DNS 解析服务商不在列表里,没关系,因为我的也不在,那就来和我手动操作吧。注意,Let’s Encrypt 申请的证书只有 90 天的有效期。DNS 检查首先,确保你的 DNS 解析服务器能被外网访问到。大部分正规的公有云 DNS 解析服务是没有问题的,如果是自建或者小众 DNS,那就各显神通吧。通过 DNSViz 可以分析域名的 DNS 解析服务,使用非常简单,输入域名,等待几分钟即可。分析报告非常详细,还能帮助我们找出 DNS 解析设置的不少问题。下面是 DNS 解析服务器状态分析页面。添加证书颁发机构授权 CAACAA 也是一种 DNS 记录,它允许站点所有者指定允许哪些证书颁发机构(CA)颁发包含其域名的证书。这主要是用于避免证书被意外的颁发,现已经作为了强制检查机制。最常见的 CAA 错误就是 SERVFAIL ,可能像下面这样。DNS problem: SERVFAIL looking up CAA for www.example.com主要是 DNS 解析服务的 CAA 认证失败或者为空或者是不支持。首先确认你的 DNS 解析服务商支持 CAA,目前主流的公有云服务商都是支持的。然后添加一条 CAA 记录即可。由 Let’s Encrypt 签发证书的话,值必须是 0 issue "letsencrypt.org"CAA 有优先级,CAA 可以指定二级域名,或者是父域名,默认找最匹配的域名,如果不存在,则找父域名。安装 certbotCertbot 是一个可以自动从 Let’s Encrypt 申请域名证书的客户端程序。它还提供多种插件,提供了多种系统和软件的自动化申请部署流程。安装也非常简单,在 官网 上可根据操作系统和对应的软件选择安装文档。例如,CentOS 系统的安装方式如下。sudo yum install certbot申请通配符证书请安装 1.0.0 及以上版本。手动获取通配符证书安装完成后,执行如下命令申请证书。(请替换下面 *.example.com 为你的域名)certbot certonly –manual -d *.example.com –preferred-challenges dns –server https://acme-v02.api.letsencrypt.org/directory为了实现通配符证书,Let’s Encrypt 对 ACME 协议的实现进行了升级,只有 v2 协议才能支持通配符证书。使用 –server 指定 API。首先需要我们进行确认。然后生成了随机 TOKEN,需要我们添加到 DNS 的 TXT 记录上。打开 DNS 解析控制台,添加 TXT 记录,类似下面这样。需要确保解析设置成功,可以通过如下命令来获取解析记录。dig -t txt _acme-challenge.example.com @8.8.8.8返回的解析记录值应该为之前给我们的 TOKEN。_acme-challenge.example.com. 300 IN TXT "7q1qb…IAj4"修改成功后返回之前的命令行,回车下一步。稍等片刻后,输出如下内容就申请成功啦!我们申请的证书就放在了输出文件的路径下了,主要是四个文件:cert.pem:证书chain.pem:证书链fullchain.pem:完整的证书链,就是 cert.pem 和 chain.pem 的整合privkey.pem:私钥配置证书申请完证书就轮到我们使用证书了。因为我们在 Kubernetes 集群中使用,可能有下面这几个地方需要配置。CDN/对象存储Kubernetes 集群托管了我们的服务,但是静态资源还是托管在 CDN 或者对象存储服务(例如 S3,OSS)等比较好。一般我们使用的 CDN 或者对象存储服务都有域名和 HTTPS 配置,每家的控制台都不一样,不过大同小异。主要的步骤一般是配置域名,开启 HTTPS,上传我们申请到的 fullchain.pem 完整证书链和 privkey.pem 私钥文件。配置完成后,一般等一会即可生效,可以通过我们配置的域名的 https 协议访问测试。不过有一点需要注意,我们申请的私钥是 X.509 格式的,文件头是—–BEGIN PRIVATE KEY—–而许多服务商需要的是下面这样的—–BEGIN RSA PRIVATE KEY—–这是两种不同的格式规范,我们可以通过 openssl 命令来进行转换。openssl rsa -in privkey.pem -out out.pemNginxNginx 可以用作 Kubernetes 集群的前置负载均衡器,或者作为 Ingress Controller。Nginx 配置证书非常简单,如果是单机且直接对外访问,可以直接通过 certbot 的 Nginx 插件自动配置(使用 –nginx 参数,参考 文档 )。复杂的场景下我们也可以手动配置,主要是在 Nginx Server 的配置块的下面几个配置项:listen 443 ssl; # 监听 443 端口的 server
ssl_certificate /etc/letsencrypt/live/<path-to>/fullchain.pem; # fullchain 的证书
ssl_certificate_key /etc/letsencrypt/live/<path-to>/privkey.pem; # 私钥
include /etc/letsencrypt/options-ssl-nginx.conf; # 这是 Nginx SSL 配置
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # 这是密钥参数配置,用来增强安全性,不知道怎么配也可以不管,详解可以看 http://www.ruanyifeng.com/blog/2014/09/illustration-ssl.html当然,如果要增加 HTTP 自动跳转 HTTPS,就增加一个 80 Server 的配置块。server {
if ($host = www.example.com) {
return 301 https://$host$request_uri;
} # 自动跳转
server_name www.example.com;
listen 80; # 监听 HTTP 80 端口
return 404;
}TraefikTraefik 是另一个 Kubernetes 上的 Ingress Controller,当然它不仅可用于 Kubernetes,是容器时代比较简单快速的开源边缘路由产品。我比较喜欢它的是天生适合 Kubernetes,简单好用,还提供了 UI Dashboard。在 Kubernetes 集群中安装只需要用 helm chart 即可,配置使用 Ingress 或者 CRD,非常容器化。Traefik 本身提供了 Let's Encrypt 的整合,可以自动申请和更新普通证书。配置也不复杂,这里简单讲一下,一是在 Traefik 容器的启动参数上加上 tls 的 resolver 配置。args:
– …
– "–entryPoints.websecure.address=:443" # 443 端口的 entrypoint,如果使用 helm chart,已经配置好了
– –certificatesresolvers.default.acme.tlschallenge=true # 配置 ACME challenge
– –[email protected] # 配置邮箱
– –certificatesresolvers.default.acme.storage=/data/acme.json # 配置存储文件,可做持久化然后我们用 IngressRoute 来暴露服务, IngressRoute 是 Traefik 提供的 CRD,比 Ingress 提供了更强大的功能。apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroutetls
namespace: default
spec:
entryPoints:
– websecure
routes:
– match: Host(`your.example.com`) && PathPrefix(`/tls`)
kind: Rule
services:
– name: whoami
port: 80
tls:
certResolver: default主要是最后一行,指定我们使用的 resolver 是之前配置的 default,然后 Traefik 就可以帮我们自动申请和更新证书了。完整的例子可以参考 这里 。当然我们申请的是通配符证书,又该如何配置呢?在 Traefik 2.2 版本提供了 tlsstore 的 CRD,可以帮助我们管理通配符证书。首先,创建一个 Secret,保存我们的证书链和私钥信息。apiVersion: v1
kind: Secret
metadata:
name: domainsecret
stringData:
tls.crt: |-
—–BEGIN CERTIFICATE—–
…
—–END CERTIFICATE—–
tls.key: |-
—–BEGIN PRIVATE KEY—–
…
—–END PRIVATE KEY—–tls.crt 是 fullchain.pem 的内容,而 tls.key 是 privkey.pem 的内容。安装 Secret 后再创建一个 tlsstore 的对象,关联刚才创建的 Secret。apiVersion: traefik.containo.us/v1alpha1
kind: TLSStore
metadata:
name: default
namespace: default
spec:
defaultCertificate:
secretName: domainsecret最后,在 IngressRoute 的 tls 中做如下配置即可。tls:
store:
name: default这样所有配置的域名都自动使用了通配符证书了,以后更新也只需要更新 Secret 即可。