一、Cert-manager原理
紧接着上个部分:https://blog.csdn.net/tushanpeipei/article/details/121369497?spm=1001.2014.3001.5501。我们已经实现了使用CFSSL的方式自己设置CA机构颁发证书。但是由于CA机构是自己产生的,非权威,也就是说无法受到访问者的认可,因此游览器会有风险提醒,所以我们需要前往权威的CA机构去申请自己的证书。
Letsencrypt-CA是一家免费提供证书的CA机构,但是申请到证书的时间只有90天。由于每90天就要去重新申请证书,存在一定的麻烦。所以在K8s中可以安装一个cert-manager的组件。在创建完成cert-manager后会生产一个名叫clusterissuer的CRD(cluster defined resources)的自定义资源,可以帮助我们去申请和续约证书(自动续约)。申请流程如下:
当Cluster-issuer向Letsencrypt-CA申请后, Letsencrypt-CA有两种方式检查申请者是否为站点的拥有者。第一种方式是http01,也是最常见的方式。大体的原理是要求申请者在自己网页的站点中设置的某个地方存储一个token,Letsencrpt-CA会来这个位置访问这个token,如果能够正确找到的话,说明申请者拥有这个站点的所有权,否则则验证失败。但是由于我们的域名目前无法被外界访问,所以这个方式无法使用。
DNS01的方式则是访问申请者站点的DNS服务器(申请人有访问权)。首先需要在站点对应的DNS服务器上生成一个token,然后将这个token告诉给Letencrypt-CA。然后Letsencrypt-CA可以通过这个key向DNS服务器中写入一些内容。如果能够正确写入内容到DNS服务器中,说明申请人有对应的DNS服务器的访问权,也就证明了其有对应站点的控制权。
两种方式的具体介绍请查看:https://letsencrypt.org/zh-cn/docs/challenge-types/。这里我们采用DNS01的方式完成实验。
二、创建完成Cluster-issuer
Cert-manager安装地址下载地址:https://cert-manager.io/docs/installation/
安装完成后查看Cert-Manager:
root@vms71:~/cert-manager# kubectl get crd | grep cert
certificaterequests.cert-manager.io 2021-12-01T12:33:08Z
certificates.cert-manager.io 2021-12-01T12:33:08Z
challenges.acme.cert-manager.io 2021-12-01T12:33:08Z
clusterissuers.cert-manager.io 2021-12-01T12:33:09Z
issuers.cert-manager.io 2021-12-01T12:33:09Z
orders.acme.cert-manager.io 2021-12-01T12:33:09Z
首先了解一下Clusterissuer的yaml文件,这一步中不创建创建:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-dns01
spec:
acme:
privateKeySecretRef:
name: letsencrypt-dns01
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- dns01:
cloudflare:
email: my-cloudflare-acc@example.com
apiTokenSecretRef:
key: api-token
name: cloudflare-api-token-secret
其中,server: https://acme-v02.api.letsencrypt.org/directory表示这个clusterissuer申请证书的CA机构的地址(letenypt)。dns01则表示使用dns01的方式申请证书。具体内容请参考官方文档:https://cert-manager.io/docs/configuration/acme/dns01/
文档中注明了所支持的DNS服务器,这里我们选用Cloudflare做域名服务器。
可以在https://dash.cloudflare.com/login主页注册一个账号。并添加对应的域名ck8s.top(这个域名已经在阿里云上购买,非之前使用的ck8s.com),并继续点击continue完成后续的步骤。
接着在阿里云控制台中找到自己的域名服务器,并修改DNS服务器为Cloudflare(在Cloudflare中会有显示):
阿里云修改内容如下:
然后根据指南https://cert-manager.io/docs/configuration/acme/dns01/cloudflare/,在cloudflare中生成能够证明自己身份的token。首先在自己的Cloudflare中点击Profile,进入个人主页。在点击API Tokens,并创建Token
接着创建自定义Token:
添加完如下信息后,点击下一步,并创建Token:
这个时候,页面中就会显示我们的Token和测试的命令。我们可以复制以后在任意设备上进行测试。
[root@localhost ~]# curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
> -H "Authorization: Bearer xxxxx" \
> -H "Content-Type:application/json"
{"result":{"id":"9293b3b342f3b0976b211678df3616e2","status":"active"},"success":true,"errors":[],"messages":[{"code":10000,"message":"This API Token is valid and active","type":null}]}[root@localhost ~]#
可以看到,success为ture,errors为空,说明Letsencrypt能够使用这个token在cloudflare中完成认证操作。所以我们需要将这个key通过Clusterissuer告诉Letsencrypt。首先查看Clusterissuer的yaml文件:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-dns01
spec:
acme:
privateKeySecretRef:
name: letsencrypt-dns01
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- dns01:
cloudflare:
email: my-cloudflare-acc@example.com
apiTokenSecretRef:
key: api-token
name: cloudflare-api-token-secret
可以看到其中携带了Token的secret信息(apiTokenSecretRef)。所以我们需要按照其给的key和name创建对应secret。注意:key和name的名字可以修改,只要和secret的对应即可。
kubectl create secret generic cloudflare-api-token-secret --from-literal=api-token=自己的token值 -n cert-manager
然后使用yaml文件创建Clusterissuer,并查看是否创建成功:
root@vms71:~/cert-manager# kubectl get clusterissuers.cert-manager.io
NAME READY AGE
letsencrypt-dns01 True 27s
三、申请证书
方式一:通过证书申请请求进行申请
申请请求的yaml文件如下:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: cert-ck8s-top
spec:
dnsNames:
- www.ck8s.top
issuerRef:
kind: ClusterIssuer
name: letsencrypt-dns01
secretName: cert-ck8s-top-tls
其中dnsNames表示为哪个站点申请证书。issuerRef下的name表示了这个证书申请文件发生到的clusterIssuer。secretName表示将申请到的证书存放在哪个secret中。申请后,请等待一定的时间,确定证书的状态为True:
root@vms71:~/cert-manager# kubectl get certificate
NAME READY SECRET AGE
cert-ck8s-top True cert-ck8s-top-tls 6m43s
编辑Ingress,使用自己从权威机构申请的证书。Ingress的yaml文件如下:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- www.ck8s.top
secretName: cert-ck8s-top-tls
rules:
- host: www.ck8s.top
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc1
port:
number: 80
可以看到我们将 secretName修改为cert-ck8s-top-tls,也就是存放证书的secret。然后查看ingress是否部署成功:
root@vms71:~/tls# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
minimal-ingress <none> www.ck8s.top 10.104.95.7 80, 443 2d8h
接着在同一网段内随便选择一台设备作为client访问www.ck8s.com进行测试。首先是在client中修改/etc/hosts文件,添加对应关系:
192.168.26.72 www.ck8s.top www
其中192.168.26.72为映ingress-controler的地址。然后再client上使用游览器访问www.ck8s.top,可以看到,证书已经被更新,且没有风险提醒(因为是从权威CA申请到的证书)。
方式二:创建ingress时直接申请证书并替换
方式以存在一定的麻烦,因为我们需要手动的申请证书并且将证书替换到ingress里面。所以在方式二中,我们可以在创建ingress的时候,直接让其到Cluster-issuer中申请证书。
首先删除第一步创建的证书申请请求和申请到的证书:
root@vms71:~/cert-manager# kubectl delete -f ct.yaml
certificate.cert-manager.io "cert-ck8s-top" deleted
root@vms71:~/cert-manager# kubectl get certificate
NAME READY SECRET AGE
cert-ck8s-top-tls True cert-ck8s-top-tls 76m
root@vms71:~/cert-manager# kubectl delete certificate cert-ck8s-top-tls
certificate.cert-manager.io "cert-ck8s-top-tls" deleted
修改ingress.yaml文件,如下所示:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
cert-manager.io/cluster-issuer: "letsencrypt-dns01"
spec:
tls:
- hosts:
- www.ck8s.top
secretName: cert-ck8s-top-tls
rules:
- host: www.ck8s.top
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc1
port:
number: 80
只需要在原来的yaml文件的annotations下添加如下一行即可,指定cluster-issuer的名称。
cert-manager.io/cluster-issuer: "letsencrypt-dns01"
申请完成后,查看证书是否申请成功。
root@vms71:~/tls# kubectl get certificate
NAME READY SECRET AGE
cert-ck8s-top-tls True cert-ck8s-top-tls 116s
然后继续在Client上进行校验(这次使用命令行来检测):
curl -vk https://www.ck8s.top
可以看到其中显示的证书颁发机构为Let’s Encrypt,说明替换成功。
issuer: C=US; O=Let's Encrypt; CN=R3
整理资料来源:《老段CKS课程》