为 KubeSphere 集群启用免费的泛域名 SSL 证书并实现证书自动更新和分发
作者:scwang18,主要负责技术架构,在容器云方向颇有研究。
前言
KubeSphere 集群默认安装的证书是自签发证书,浏览器访问访问会发出安全提醒。本文记录了利用 let's encrytp
泛域名证书实现 Kubernetes 集群外部服务自动证书配置和证书到期自动更新,支持 HTTPS 访问。我们还部署了证书自动分发组件,实现证书文件自动分发到其他 namespace 。
架构
在 KubeSphere 集群中使用 HTTPS 协议,需要一个证书管理器、一个证书自动签发服务
cert-manager 是一个云原生证书管理开源项目,用于在 KubeSphere 集群中提供 HTTPS 证书并自动续期,支持 Let’s Encrypt
, HashiCorp Vault
这些免费证书的签发。在 KubeSphere 集群中,我们可以通过 Kubernetes Ingress 和 Let’s Encrypt
实现外部服务的自动化 HTTPS。
Issuers/ClusterIssuers:定义使用什么证书颁发机构 (CA) 来去颁发证书,Issuers 和 ClusterIssuers 区别是: issuers 是一个名称空间级别的资源,只能用来签发自己所在 namespace 下的证书,ClusterIssuer 是个集群级别的资源 可以签发任意 namespace 下的证书
Certificate:定义所需的 X.509 证书,该证书将更新并保持最新。Certificate 是一个命名空间资源,当 Certificate 被创建时,它会去创建相应的 CertificateRequest 资源来去申请证书。
安装证书管理器
安装证书管理器比较简单,直接执行以下脚本就可以了。
$ kubectl create ns cert-manager
$ helm uninstall cert-manager -n cert-manager
$ helm install cert-manager jetstack/cert-manager \
-n cert-manager \
--version v1.8.0 \
--set installCRDs=true \
--set prometheus.enabled=false \
--set 'extraArgs={--dns01-recursive-nameservers-only,--dns01-recursive-nameservers=119.29.29.29:53\,8.8.8.8:53}'
选择证书颁发者
cert-manager 支持以下几种证书颁发者:
- SelfSigned
- CA
- Vault
- Venafi
- External
- ACME
我们选择使用 ACME 来颁发证书。
选择证书校验方式
常用的校验方式有 HTTP-01 、DNS-01 。
DNS-01 校验原理
DNS-01 的校验原理是利用 DNS 提供商的 API Key 拿到 DNS 控制权限, 在 Let’s Encrypt 为 ACME 客户端提供令牌后,ACME 客户端 (cert-manager) 将创建从该令牌和我的帐户密钥派生的 TXT 记录,并将该记录放在 _acme-challenge。 然后 Let’s Encrypt 将向 DNS 系统查询该记录,如果找到匹配项,就可以颁发证书。此方法支持泛域名证书。
HTTP-01 校验原理
HTTP-01 的校验原理是给域名指向的 HTTP 服务增加一个临时 location ,Let’s Encrypt 会发送 HTTP 请求到 http:///.well-known/acme-challenge/,参数中 YOUR_DOMAIN 就是被校验的域名,TOKEN 是 ACME 协议的客户端负责放置的文件,ACME 客户端就是 cert-manager,它通过修改或创建 Ingress 规则来增加这个临时校验路径并指向提供 TOKEN 的服务。Let’s Encrypt 会对比 TOKEN 是否符合预期,校验成功后就会颁发证书。此方法仅适用于给使用 Ingress 暴露流量的服务颁发证书,不支持泛域名证书。
优劣对比
HTTP-01 的校验方式的优点是: 配置简单通用,不管使用哪个 DNS 提供商都可以使用相同的配置方法;缺点是:需要依赖 Ingress,如果服务不是通过 Ingress 暴露的就不适用,而且不支持泛域名证书。
DNS-01 的校验方式的优点是没有 HTTP-01 校验方式缺点,不依赖 Ingress,也支持泛域名;缺点就是不同 DNS 提供商的配置方式不一样,而且只有 cert-manager 支持的 DNS 提供商才可以选择这种方式。
Cert-manager 支持使用外部 webhook 的接入 DNS 提供商,正好公司使用腾讯云的 DNSPOD 属于支持的行列。我们可以选择 DNS-01 。
HTTP-01 配置示例
这个配置示例仅供参考,使用这种方式,有多少的 Ingress 服务,就需要申请多少张证书,比较麻烦,但是配置较为简单,不依赖 DNS 服务商。
1. 创建 CA 群集证书颁发者
证书管理器需要 Issuer 或 ClusterIssuer 资源,才能颁发证书。 这两种 Kubernetes 资源的功能完全相同,区别在于 Issuer 适用于单一命名空间,而 ClusterIssuer 适用于所有命名空间。
# ClusterIssuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: scwang18@xxx.xxx
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: issuer-account-key
solvers:
- http01:
ingress:
class: nginx
说明:
- metadata.name: 是我们创建的签发机构的名称,后面我们创建证书的时候会引用它;
- spec.acme.email: 是你自己的邮箱,证书快过期的时候会有邮件提醒,不过 cert-manager 会利用 acme 协议自动给我们重新颁发证书来续期;
- spec.acme.server: 是 acme 协议的服务端,我们使用 Let’s Encrypt;
- spec.acme.privateKeySecretRef: 指示此签发机构的私钥将要存储到哪个 Secret 对象中;
- spec.acme.solvers: 这里指示签发机构校验方式,有 http01 和 dns01 两种,该字段下配置的 class 和 name 只能同时存在一个, class 指定使用的 Ingress class 名称, name 比较少用,通常用于 Kubernetes 的 Ingress。
$ kubectl apply -f ClusterIssuer.yaml -n cert-manager
执行成功后,会将申请的证书文件放置在 issuer-account-key 这个 Secret 中。
查看证书是否自动创建成功:
$ kubectl -n infra get certificate
2. 在 Ingress 中使用上步申请到的 SSL 证书
# ingreess-wikijs.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt
nginx.ingress.kubernetes.io/proxy-body-size: "0"
name: ingress-wikijs
spec:
ingressClassName: nginx
rules:
- host: wiki.xxx.xxx
http:
paths:
- backend:
service:
name: wikijs
port:
number: 3000
path: /
pathType: Prefix
tls:
- hosts:
- wikijs.xxx.xxx
secretName: ingress-wikijs-tls
注意:在 annotations 里 设置
cert-manager.io/cluster-issuer
为签名创建的集群证书颁发者letsencrypt
。
使用 yaml 文件创建 ingress 后,就可以使用该 Ingress 对外提供 HTTPS 服务了。
# 执行创建 ingress
kubectl apply -f ingress-wikijs.yaml -n infra
DNS01 配置示例
使用这种方式需要 DNS 服务商支持通过 API 创建 DNS 记录,正好我的 DNS 服务商是腾讯云 dnspod 支持,因此在我们的及群里,最终采用了这种方式。
这个方式的配置会比较麻烦,踩了很久的坑,主要是因为我的集群启用了本地 DNS 服务器,默认 cert-manager 会通过本地 DNS 服务器去验证通过 API 创建的 DNS txt 记录,会一直检查不到新增的 txt 记录,造成在 challenge 阶段就一直 pendding。解决方案附后。
1. 在 dnspod 创建 API ID 和 API Token
参考腾讯云官方文档(https://support.dnspod.cn/Kb/showarticle/tsid/227/)
记录下创建的 API ID 和 API Token (加码处理,需要自行获取自己的 API ID 和 API Token)。
AKIDVt3z4uVss11xjIdmddgMmHXXssssHp9D2buxrWR8
SekbG2gqdflQs5xxxviGagX8TYO
2. 安装 cert-manager-webhook-dnspod
使用 helm 安装 roc/cert-manager-webhook-dnspod。
$ helm repo add roc https://charts.imroc.cc
$ helm uninstall cert-manager-webhook-dnspod -n cert-manager
$ helm install cert-manager-webhook-dnspod roc/cert-manager-webhook-dnspod \
-n cert-manager \
--set clusterIssuer.secretId=AKIDVt3z4uVss11xjIdmddgMmHXXssssHp9D2buxrWR8 \
--set clusterIssuer.secretKey=SekbG2gqdflQs5xxxviGagX8TYO \
--set clusterIssuer.email=xxx@xxx.xxx
3. 创建泛域名证书
# ipincloud-crt.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ipincloud-crt
spec:
secretName: ipincloud-crt
issuerRef:
name: dnspod
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- "*.xxx.xxx"
创建集群证书颁发者:
$ kubectl apply -f ipincloud-crt.yaml -n infra
4. 验证证书
查看证书是否创建成功:
$ kubectl get Certificate -n cert-manager
NAME READY SECRET AGE
cert-manager-webhook-dnspod-ca True cert-manager-webhook-dnspod-ca 18m
cert-manager-webhook-dnspod-webhook-tls True cert-manager-webhook-dnspod-webhook-tls 18m
ipincloud-crt True ipincloud-crt 3m12s
以上可以看出 ipincloud-crt 已经创建成功, READY 状态也是 True。
查看证书对应的域名:
$ kubectl describe Certificate ipincloud-crt -n cert-manager
Name: ipincloud-crt
Namespace: cert-manager
Labels: <none>
Annotations: <none>
API Version: cert-manager.io/v1
Kind: Certificate
Metadata:
Creation Timestamp: 2022-05-07T14:19:07Z
...
Spec:
Dns Names:
*.xxx.xxx
Issuer Ref:
Group: cert-manager.io
Kind: ClusterIssuer
Name: dnspod
Secret Name: ipincloud-crt
Status:
Conditions:
Last Transition Time: 2022-05-07T14:19:14Z
Message: Certificate is up to date and has not expired
Observed Generation: 1
Reason: Ready
Status: True
Type: Ready
Not After: 2022-08-05T13:19:11Z
Not Before: 2022-05-07T13:19:12Z
Renewal Time: 2022-07-06T13:19:11Z
Revision: 1
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Issuing 4m35s cert-manager-certificates-trigger Issuing certificate as Secret does not exist
Normal Generated 4m35s cert-manager-certificates-key-manager Stored new private key in temporary Secret resource "ipincloud-crt-4ml59"
Normal Requested 4m35s cert-manager-certificates-request-manager Created new CertificateRequest resource "ipincloud-crt-r76wp"
Normal Issuing 4m28s cert-manager-certificates-issuing The certificate has been successfully issued
从 Certificate 的描述信息可以看到,这个证书是对应所有 *.xxx.xxx
的泛域名。
查看证书内容:
$ kubectl describe secret ipincloud-crt -n cert-manager
Name: ipincloud-crt
Namespace: cert-manager
Labels: <none>
Annotations: cert-manager.io/alt-names: *.xxx.xxx
cert-manager.io/certificate-name: ipincloud-crt
cert-manager.io/common-name: *.xxx.xxx
cert-manager.io/ip-sans:
cert-manager.io/issuer-group: cert-manager.io
cert-manager.io/issuer-kind: ClusterIssuer
cert-manager.io/issuer-name: dnspod
cert-manager.io/uri-sans:
Type: kubernetes.io/tls
Data
====
tls.crt: 5587 bytes
tls.key: 1675 bytes
TLS 证书保存在 cert-manager 命名空间里的 ipincloud-crt secret。可以供所有 ``*.xxx.xxx` 的服务使用。
其他
这个过程中,遇到最大的坑是:我的集群使用了自建的 DNS 服务器,默认 cert-manager 会使用这个集群的自建 DNS SERVER 进行证书发行的验证,虽然通过调用 dnspod 的 webook 在 腾讯云 DNS 服务器上创建的 _acme-challenge 握手数据,但是在我的自建 DNS 里是查不到的,所以会一直卡 pending 状态。
$ kubectl get challenge -A
NAMESPACE NAME STATE DOMAIN AGE
cert-manager ipincloud-crt-f9kp6-381578565-136350475 pending xxx.xxx 24s
查看原因是:
Waiting for DNS-01 challenge propagation: DNS record for "xxx.xxx" not yet
$ kubectl -n cert-manager describe challenge ipincloud-crt-f9kp6-381578565-136350475
Name: ipincloud-crt-f9kp6-381578565-136350475
Namespace: cert-manager
Labels: <none>
Annotations: <none>
API Version: acme.cert-manager.io/v1
Kind: Challenge
---
中间略
---
Status:
Presented: true
Processing: true
Reason: Waiting for DNS-01 challenge propagation: DNS record for "xxx.xxx" not yet propagated
State: pending
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Started 41s cert-manager-challenges Challenge scheduled for processing
Normal Presented 39s cert-manager-challenges Presented challenge using DNS-01 challenge mechanism
查了很多资料,在官网上找到解决方案。办法是让 cert-manager 强制使用指定的 DNS 服务器进行握手验证。
我是用的是 helm 安装 cert-manager,所以添加一下 set 参数。
--set 'extraArgs={--dns01-recursive-nameservers-only,--dns01-recursive-nameservers=119.29.29.29:53\,8.8.8.8:53}'
参考文档:https://cert-manager.io/docs/configuration/acme/dns01/#setting-nameservers-for-dns01-self-check
配置证书复制到其他 namespace
安装 kubed
$ helm repo add appscode https://charts.appscode.com/stable/
$ helm repo update
$ helm install kubed appscode/kubed \
--version v0.13.2 \
--namespace cert-manager
修改 Certificated 文件
为 certificated 对象设置 secretTemplate, 设置需要同步到哪些 namespace。
# ipincloud-crt.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: ipincloud-crt
spec:
secretName: ipincloud-crt
issuerRef:
name: dnspod
kind: ClusterIssuer
group: cert-manager.io
dnsNames:
- "*.xxx.xxx"
secretTemplate:
annotations:
kubed.appscode.com/sync: "cert-manager-tls=ipincloud-crt"
给需要同步的目标 namespace 打 label
上一步的 secretTemplate 里指定了同步的目标 namespace 的 label 过滤条件 cert-manager-tls=ipincloud-crt
, 因此,我们需要对接收同步 secret 的 namespace 打上相应的 label。
$ kubectl label ns default cert-manager-tls=ipincloud-crt
$ kubectl label ns app cert-manager-tls=ipincloud-crt
$ kubectl label ns dev-app cert-manager-tls=ipincloud-crt
$ kubectl label ns dev-infra cert-manager-tls=ipincloud-crt
$ kubectl label ns dev-wly cert-manager-tls=ipincloud-crt
$ kubectl label ns infra cert-manager-tls=ipincloud-crt
$ kubectl label ns istio-system cert-manager-tls=ipincloud-crt
$ kubectl label ns uat-app cert-manager-tls=ipincloud-crt
$ kubectl label ns uat-wly cert-manager-tls=ipincloud-crt
$ kubectl label ns wly cert-manager-tls=ipincloud-crt
$ kubectl label ns kubesphere-controls-system cert-manager-tls=ipincloud-crt
查看是否复制成功
查看目标 namespace 是否复制 secret 成功。
$ kubectl get secret ipincloud-crt
NAME TYPE DATA AGE
ipincloud-crt kubernetes.io/tls 2 18m
查看复制的 secret ,可以看到 label 信息中记录了证书来源信息。
$ kubectl describe secret ipincloud-crt
Name: ipincloud-crt
Namespace: default
Labels: kubed.appscode.com/origin.cluster=unicorn
kubed.appscode.com/origin.name=ipincloud-crt
kubed.appscode.com/origin.namespace=cert-manager
Annotations: cert-manager.io/alt-names: *.xxx.xxx
cert-manager.io/certificate-name: ipincloud-crt
cert-manager.io/common-name: *.xxx.xxx
cert-manager.io/ip-sans:
cert-manager.io/issuer-group: cert-manager.io
cert-manager.io/issuer-kind: ClusterIssuer
cert-manager.io/issuer-name: dnspod
cert-manager.io/uri-sans:
kubed.appscode.com/origin:
{"namespace":"cert-manager","name":"ipincloud-crt","uid":"b4713633-731e-4151-844f-0f6d9cf6352c","resourceVersion":"12531075"}
Type: kubernetes.io/tls
Data
====
tls.crt: 5587 bytes
tls.key: 1675 bytes
使用 TLS 证书配置 Ingress
设置 Ingress
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: wikijs
namespace: infra
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: '0'
spec:
ingressClassName: nginx
tls:
- hosts:
- wiki.xxx.xxx
secretName: ipincloud-crt
rules:
- host: wiki.xxx.xxx
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: wikijs
port:
number: 3000
测试
以上配置完成后,就可以使用 HTTPS 来访问新的 wiki.js 服务了。
$ curl -I https://wiki.xxx.xxx
HTTP/1.1 302 Found
Date: Sat, 07 May 2022 14:52:39 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 28
Connection: keep-alive
X-Frame-Options: deny
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-UA-Compatible: IE=edge
Referrer-Policy: same-origin
Content-Language: zh
Set-Cookie: loginRedirect=%2F; Max-Age=900; Path=/; Expires=Sat, 07 May 2022 15:07:39 GMT
Location: /login
Vary: Accept, Accept-Encoding
Strict-Transport-Security: max-age=15724800; includeSubDomains
如上所示,就是成功启动了 HTTPS 。
参考
- https://artifacthub.io/packages/helm/cert-manager/cert-manager
- https://www.1nth.com/post/k8s-cert-manager/
- https://cert-manager.io/docs/configuration/acme/dns01/#setting-nameservers-for-dns01-self-check
本文由博客一文多发平台 OpenWrite 发布!
为 KubeSphere 集群启用免费的泛域名 SSL 证书并实现证书自动更新和分发的更多相关文章
- Let'sEncrypt 免费通配符/泛域名SSL证书添加使用教程
Let'sEncrypt 免费通配符/泛域名SSL证书添加使用教程 通配符证书一般还是比较贵的一般最便宜的通配符证书5.60美元一年,只不过Let'sEncrypt的有效期是3个月,对于一般用户来说基 ...
- [细节版]Let'sEncrypt 免费通配符/泛域名SSL证书添加使用教程
参考网址:https://lnmp.org/faq/letsencrypt-wildcard-ssl.html 使用的dns服务商:阿里云 , 更多服务商地址可见参考网址. 遇见的问题一. [Sat ...
- kubesphere集群搭建(多节点)
kubesphere官网:https://kubesphere.io/docs/advanced-v2.0/zh-CN/introduction/intro/ 一.准备环境 1.准备服务器 maste ...
- 分布式存储系统之Ceph集群启用Dashboard及使用Prometheus监控Ceph
前文我们了解了Ceph之上的RadosGW基础使用相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16768998.html:今天我们来聊一聊Ceph启 ...
- 新开源HTML5单文件网页版ACME客户端,可在线申请Let's Encrypt、ZeroSSL免费HTTPS多域名通配符泛域名SSL/TLS证书(RSA/ECC/ECDSA)
目录 开源项目的起源 项目地址 使用方法 第一步:选择Let's Encrypt.ZeroSSL或其他证书颁发机构 第二步:证书配置,填写域名 第三步:完成域名所有权的验证 第四步:下载保存证书PEM ...
- kubesphere集群节点扩容
原有的节点是 : master[123] , node[1234] 新加的节点node5 一.修改配置文件hosts.ini [root@master0 ~]# /conf/hosts.ini [al ...
- Let’s Encrypt Wildcard 免费泛域名SSL证书获取安装
2018 年 1 月Let’s Encrypt CA 宣布免费提供通配符证书(Wildcard certificate).通配符证书是一种可被多个子域使用的公钥证书.这意味着,单个证书可用于提供多台服 ...
- Let's Encrypt泛域名SSL证书申请
操作系统:CentOS 7 github:https://github.com/Neilpang/acme.sh 有中文说明: https://github.com/Neilpang/acme.sh ...
- 在 Linux 部署多节点 Kubernetes 集群与 KubeSphere 容器平台
KubeSphere 是在 Kubernetes 之上构建的以应用为中心的企业级容器平台,所有供为用户提供简单易用的操作界面以及向导式操作方式.同时,KubeSphere Installer 提供了 ...
- Kubernetes 多集群在开源项目 KubeSphere 的应用
Kubernetes 多集群使用场景 随着容器的普及和 Kubernetes 的日渐成熟,企业内部运行多个 Kubernetes 集群已变得颇为常见.概括起来,多个集群的使用场景主要有以下几种. 多集 ...
随机推荐
- mini_imagenet 数据集生成工具
最近在看小样本方面的论文,发现这个mini_imagenet这个数据集比较常用,但是却不好找,找了半天也没有找到,最后在找到了这样的答案: 小样本学习(Few shot learning)标准数据集( ...
- NVIDIA公司的半成品项目cule——GPU端运行的Atari2600游戏环境——已经废弃的项目
官网介绍地址: https://developer.nvidia.com/blog/new-open-source-gpu-accelerated-atari-emulator-for-reinfor ...
- 自己实现一个自动检测网卡状态,并设置ip地址,源码见文章底部
阅读本文前,请先学习下面几篇文章 <搞懂进程组.会话.控制终端关系,才能明白守护进程干嘛的?> <简简单单教你如何用C语言列举当前所有网口!> <Linux下C语言操作网 ...
- 关于Protobuf在使用中的一些注意点
Protobuf是谷歌旗下的一款二进制序列化协议 协议的编写 在项目中新建一个xxx.proto文件 文件的格式 第一行写protobuf的版本 syntax = "proto3" ...
- SpringBoot静态文件映射问题
如果遇到这种情况,检查静态文件(js/css/img)是不是在默认的static路径下,在查看application配置中的 static-path-pattern: 是否和前端映射路径完全相同,要是 ...
- Redis实战之session共享
当线上集群时候,会出现session共享问题. 虽然Tomcat提供了session copy的功能,但是缺点比较明显: 1:当Tomcat多的时候,session需要大量同步到多台集群上,占用内网宽 ...
- python pyqt6 QMenu 设定圆角边框
本来这个没有必要写,但是因为写的过程中,按照网上的写法运行,不知道为什么QMenu的右下角有圆角边框与直角背景颜色会覆盖显示 所以还是有必要写一下 menu = QMenu(self.tool_but ...
- 神经网络之卷积篇:详解池化层(Pooling layers)
详解池化层 除了卷积层,卷积网络也经常使用池化层来缩减模型的大小,提高计算速度,同时提高所提取特征的鲁棒性,来看一下. 先举一个池化层的例子,然后再讨论池化层的必要性.假如输入是一个4×4矩阵,用到的 ...
- Dell存储备份告警:
创建时间 修改日期 对象名称 消息 类型 告警状态 已确认 告警定义 类型 23-3-12 11:59:26 23-3-12 11:59:37 copyMirrorswap 2 CMs Operati ...
- 使用js闭包实现可取消的axios请求
在平常开发中,经常会遇到重复请求的情况,也许是因为网络问题,也许是因为接口问题等等,传统做法是客户端采用防抖来限制用户发送接口的频率,一般出个loading转圈圈的形式, 但是很少使用取消请求的做法, ...