这里探讨使用Let's Encrypt实现Kubernetes Ingress中自动创建、管理和部署证书,实现HTTPS支持。
HTTPS是什么?
- HTTPS是加密的http协议,提供数据通道加密和服务器验证功能。
- 使用支持https的浏览器上网,数据传输是加密的、而且可以防止中间被篡改;
- 对服务器需要进行验证,如果是假冒服务器浏览器会告警并拒绝与之连接,从而保护用户免于上当受骗。
- 不过,仅仅一个协议,也不是万能的。
- 比如浏览器如果就是被篡改的版本,完全可能将网站资源指向错误的路标;
- 证书依赖第三方机构认证,已经出现过假冒证书的情况,自签名证书也难以提供真正的安全;
- 部分浏览器或定制程序可以越过证书验证直接访问资源(不建议使用)。
- 需要指出的是,在隐私保护方面,https不支持IP地址隐藏、也不支持域名加密。
在Kubernetes中使用HTTPS
在Kubernetes集群中使用HTTPS协议发布服务,需要一个证书管理器、一个证书自动签发服务,主要通过Ingress来发布https服务,因此需要Ingress Controller并进行配置,启用https及其路由。
在Kubernetes中使用HTTPS的支持软件架构组成如下:
几天以前,读到 Troy Hunt写的关于HTTPS的文章,标题是 "HTTPS is easy"(https://my.oschina.net/u/2306127/blog/1929249)。 HTTPS 并不难,尤其是在 Kubernetes这样的平台上。不幸的是,不是所有的人都同意这一观点。我理解对于大型机构来说,把所有的流量都转化到HTTPS上是非常困难的事情。但你可以将HTTPS用于所有的外部流量,通过 Kubernetes ingress 和 Let's Encrypt 实现外部服务端点的自动化。意味着,只要你愿意,可以直接 "切换到 HTTPS"。所提供的插件可以处理需要做的一切。
预先要求
为了在Kubernetes中自动化HTTPS,需要先部署 ingress controller。 什么是 ingress呢? 通过ingress(中文译:入口)在 Kubernetes中的使用, 可以控制外部流量的路由。Ingress controller 与 Kubernetes API 实现了集成,但其服务需要安装相应的引擎(目前有Nginx和Traefic两种)。
要求的软件:
- Ingress controller,在 Kubernetes上部署。
- 自动化的 DNS(域名服务)。
我写过一些关于ingress controller的文章。如何满足这些需求,可以参考:AWS Cost Savings by Utilizing Kubernetes Ingress with Classic ELB。
部署到一起
管理 SSL/TLS 证书的组件是Cert manager。它对于每一个ingress endpoint将会自动创建一个新的证书。当 certificates 过期时还能自动更新。Cert manager 也可以和其它的providers一起工作,例如HashiCorp Vault。在我的与Kubernetes相关的文章中,我使用 Helm来部署,主要是为了方便,但在生产环境下,我并不建议如此。参见 read my blog post about Helm。
你需要配置一个缺缺省的 cluster issuer,当部署Cert manager的时候,用于支持 kubernetes.io/tls-acme: "true"
annotation来自动化TLS:
ingressShim.defaultIssuerName=letsencrypt-prod
ingressShim.defaultIssuerKind=ClusterIssuer
部署证书管理器
你将在后面定义 letsencrypt-prod
cluster issuer。先来部署 Cert manager:
⚡ helm install --name cert-manager
--namespace ingress
--set ingressShim.defaultIssuerName=letsencrypt-prod
--set ingressShim.defaultIssuerKind=ClusterIssuer
stable/cert-manager
⚡ kubectl get pod -n ingress --selector=app=cert-manager
NAME READY STATUS RESTARTS AGE
cert-manager-cert-manager-7797579f9-m4dbc 1/1 Running 0 1m
当安装 Cert manager 提供的 Kubernetes custom resources:
⚡ kubectl get crd
NAME AGE
certificates.certmanager.k8s.io 1m
clusterissuers.certmanager.k8s.io 1m
issuers.certmanager.k8s.io 1m
创建证书签发服务
最后一步,定义集群范围内的 issuer letsencrypt-prod
,在上面的步骤中我们已经设置了。使用自定义资源来定义cluster issuer clusterissuers.certmanager.k8s.io
:
⚡ cat << EOF| kubectl create -n ingress -f -
apiVersion: certmanager.k8s.io/v1alpha1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: me@example.com
privateKeySecretRef:
name: letsencrypt-prod
http01: {}
EOF
注意: 使用有效的 email 地址!
创建一个服务进行测试
现在测试一下。部署一个新的Ghost blog 到集群上,将通过ghost.test.akomljen.com
域名访问,缺省使用了 HTTPS 。使用Helm来安装:
⚡ cat > values.yaml <<EOF
serviceType: ClusterIP
ghostHost: ghost.test.akomljen.com
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
hosts:
- ghost.test.akomljen.com
tls:
- secretName: test-app-tls
hosts:
- ghost.test.akomljen.com
mariadb:
replication:
enabled: true
EOF
⚡ helm install --name test-app
-f values.yaml
stable/ghost
注意: 这里有一个 a Helm issue, boolean 值无法作为 string 被正确滴解析。这就是为什么我要使用文件而不是 --set
和 --set-string
参数来更新缺省值的原因。
几分钟后,你可以使用定义的endpoint打开网页,HTTPS缺省支持!
总结
很容易,对吧?我们很幸运有像 Troy Hunt 这样的专家来促进安全的网络机制,使大家能够更容易地实施。同时,云原生的技术帮助我们自动这些事情。