kubernetes运维之-cert-manager自动签发Lets Encrypt证书并通过Ingress实现https网站全自动管理

前言

在我们实际的云原生业务场景,web服务可谓是多不胜数,尤其是证书管理方面一直是很头疼的存在,有些时候我们的业务对安全等级要求并不高,奈何业务数量多,维护证书繁琐程度高,大多是重复劳动,并且公有云侧免费SSL证书也有一定的数量限制,亦或需要额外购买证书,运营成本加剧,所以我们需要一种全自动web站点管理工具,让证书从签发到项目上线一套大保健全套就搞定!

说到免费的SSL证书,大家首先想到的肯定是Let’s Encrypt,而使用过Let’s Encrypt的同学应该也知道,它有效期只有三个月,三个月后要重新续期,在k8s上使用该免费证书又是一种挑战,所以前段时间经过研究发现cert-manager工具符合我们的预期,在Kubernetes集群中,我们可以通过 Kubernetes 上的Ingress-nginx 结合 Let’s Encrypt 实现外部服务的自动化 HTTPS,这样一些非关键性的web业务也可以获得安全保障啦哈哈哈!!!

本文章就从一个真实的kubernetes业务环境来向大家展示证书管理的具体实现!

关于Let’s encrypt(ACME)

为了在我们的网站上启用 HTTPS,我们需要从证书颁发机构(CA)获取证书(一种文件),或者从公有云方面申请证书,再将证书部署到我们的网站上面来。Let’s Encrypt 正是其中一家CA证书颁发机构,它可以实现上面所述的过程,一般来说这个过程可以通过一些脚本来进行操作, 但需要支持ACME 协议才行否则是签发不下来的。

请添加图片描述

关于cert-manager

cert-manager 是一个云原生证书管理开源项目,为 Kubernetes 或 OpenShift 集群中的工作负载创建 TLS 证书 并在证书过期之前续订证书。支持多类免费证书机构的证书签发:比如我们刚才提及的Let’s Encrypt以及HashiCorp Vault等机构。

它的工作逻辑基本分为以下五部曲:
1、创建ClusterIssuer或者Issuer资源用于创建颁发者,决定cert-manager签发证书的方式,然后会在cert-manager上的namespace下生成该颁发者的secret用于证书申请的准备。

2、通过创建Certificate资源来告知cert-manager :在哪个namespace生成证书、需要签发的域名的证书名称,域名对应的secret资源,以及的引用ClusterIssuer或者Issuer资源等等信息。

3、cert-manager拿着创建好的Certificate资源与ClusterIssuer或者Issuer资源的secret通过内部或外部的webhook向所支持的域名服务提供商对域名进行解析,这里会发起certificaterequests与challenges动作。

4、解析通过acme校验后将证书返回至cert-manager,certificatere对应项会变成True验证通过状态,再将证书转换到对应namespace下的secret资源做证书引用准备。

5、在Ingress-controller上生成ingress资源引用该证书secret即可实现https可信访问。
在这里插入图片描述

模拟环境

先决条件

一定记得有一个公网IP,切记!
然后在公有云上解析个测试域名,A记录即可~~
例如:a.baidu.com

环境描述

这里我们模拟一套生产环境,由单主从kubernetes集群模拟,kubernetes版本为1.28并部署helm包管理软件,案例上采用的阿里云ECS,配置均为2核4G,2M带宽。

在这里插入图片描述

目标实现计划

总结就是一句话:来吧,加固我们的网站,提升我们的运维效率~~~,干就完了!
请添加图片描述

一、部署cert-manager和webhook

1、添加Jestack Helm存储库并安装cert-manager

# 创建命名空间
kubectl create namespace cert-manager

# 添加资源库,更新资源库
helm repo add jetstack https://charts.jetstack.io
helm repo update

# 安装cert-manager
helm upgrade --install cert-manager jetstack/cert-manager --namespace cert-manager --set installCRDs=true

2、安装webhook

# 安装webhook,这里一定记得要和cert-manager安装到同一个命名空间下
helm upgrade --install alidns-webhook alidns-webhook --repo https://wjiec.github.io/alidns-webhook \
--namespace cert-manager --set groupName=acme.yourcompany.com

由于带宽限制,下载速度可能会慢一些,这里大家等待一会儿就好啦~~

二、申请Accesskey-ID

1、RAM授权

在阿里域名所在的主账号下创建一个阿里ram账号,并具有管理DNS的权限,允许控制台登录。

2、验证ram账号

登录创建的ram账号,输入我们定义好的账号密码等信息,点击下一步,如果能成功登录那就说明RAM账号有效。
在这里插入图片描述

3、生成Accesskey-ID

鼠标移动到用户头像,在头像下方菜单列表选择“AccessKey管理”,然后点击“创建AccessKey”,记录好生成的“Accesskey-ID”与“Secret Key”到安全的地方。

三、创建证书颁发机构

1、Accesskey-ID信息转码

由于kubernetes的secret资源是以加密方式存储,所以这里我们需要将“Accesskey-ID”这些信息进行转码,然后创建对应的secret资源,作为证书办法机构申请的钥匙。

# 加密格式
## 这里注意:生成的加密字符串需要去除“Cg==”字符串,这个字符串含义是换行符;
如果传入该换行符将可能导致秘钥验证不通过。
echo "Accesskey-ID" |base64
xxxxxxxCg==

2、创建证书办法机构密钥对

# alidns-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: alidns-secret
  namespace: cert-manager
data:
  access-key-id: TFRBSTV0S3JUQW1SeWxxxxxxx 
  access-key-secret: ZUtSOE5NTnQ0Nxxxxxxx
## 这里将上步骤转化来的加密字符串分别填入对应的位置就可以,声明在命名空间cert-manager

3、创建证书颁发机构

# clusterissuer.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    email: 1256581633@qq.com
    server: https://acme-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - dns01:
        webhook:
         groupName: acme.yourcompany.com
         solverName: alidns
         config:
          region: ""
          accessKeyIdRef:
            name: alidns-secret
            key: access-key-id
          accessKeySecretRef:
            name: alidns-secret
            key: access-key-secret

## 这里需要注意
1、email处可以填写为自己的企业邮箱,主要用于证书过期时候的提醒
2、这里我声明的是ClusterIssuer,这样意味着这个机构对kubernetes的全局命名空间都生效;
此外privateKeySecretRef一定要与name值相同,这样确保后续生成的secret资源绑定。
3、顺便一提,前期我们测试证书签发的时候server建议填写下述地址
- https://acme-staging-v02.api.letsencrypt.org/directory
主要用于验证操作,如果没有问题就可以切到yaml文件所声明的地址

四、创建证书

# ssl-cert-test.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: cert-test-ssl
  namespace: cert-manager
spec:
  secretName: cert-test-ssl-tls
  issuerRef:
    name: letsencrypt-prod
    kind: ClusterIssuer
  dnsNames:
  - certssl.xxxxxx.cn

## 这里需要注意
1、为了测试方便我将后续前端服务交付至cert-manager所在的cert-manager命名空间下;
所以namespace也是和颁发机构是相同的

2、“issuerRef”是用来与证书办法机构绑定的,说白了就是走哪种签发证书机构去申请证书。
3、“secretName”值一定要记住,以便用于前端服务的ingress引用。
4、“dnsNames”是写需要对哪个域名进行签发证书操作

五、生效上述配置

[root@core ssl-cert-tools]# kubectl apply -f .

此时,我们的cert-manager与webhook程序就证书签发进行自动化操作阶段,也称为所谓的“挑战”阶段,即acem与域名服务提供商进行域名验证+证书签发。

这里观察webhook日志,这里我们发现webhook程序已经拿着我们的证书颁发机构的secret身份令牌去请求阿里的DNS域名解析接口去进行解析记录的“创建”与“删除”的操作。

[root@core ssl-cert-tools]# kubectl logs -f -n cert-manager alidns-alidns-webhook-7b56577747-5g46c 
I0410 05:21:45.390934       1 requestheader_controller.go:169] Starting RequestHeaderAuthRequestController
I0410 05:21:45.390989       1 shared_informer.go:240] Waiting for caches to sync for RequestHeaderAuthRequestController
I0410 05:21:45.391027       1 configmap_cafile_content.go:202] Starting client-ca::kube-system::extension-apiserver-authentication::client-ca-file
I0410 05:21:45.391031       1 shared_informer.go:240] Waiting for caches to sync for client-ca::kube-system::extension-apiserver-authentication::client-ca-file
I0410 05:21:45.391057       1 configmap_cafile_content.go:202] Starting client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file
I0410 05:21:45.391062       1 shared_informer.go:240] Waiting for caches to sync for client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file
I0410 05:21:45.391485       1 secure_serving.go:197] Serving securely on [::]:443
I0410 05:21:45.391992       1 dynamic_serving_content.go:130] Starting serving-cert::/tls/tls.crt::/tls/tls.key
I0410 05:21:45.392101       1 tlsconfig.go:240] Starting DynamicServingCertificateController
I0410 05:21:45.491108       1 shared_informer.go:247] Caches are synced for client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file 
I0410 05:21:45.491108       1 shared_informer.go:247] Caches are synced for RequestHeaderAuthRequestController 
I0410 05:21:45.491147       1 shared_informer.go:247] Caches are synced for client-ca::kube-system::extension-apiserver-authentication::client-ca-file 
Decoded configuration: {{{alidns-secret} access-key-id} {{alidns-secret} access-key-secret} }
I0410 05:22:39.090081       1 trace.go:205] Trace[395976000]: "Create" url:/apis/example.com/v1alpha1/alidns,user-agent:cert-manager-challenges/v1.14.4 (linux/amd64) cert-manager/f5ddc412723722518f401f9ce6ec6fc950e72c04,client:172.16.0.237 (10-Apr-2024 05:22:37.670) (total time: 1419ms):
Trace[395976000]: ---"Object stored in database" 1418ms (05:22:00.089)
Trace[395976000]: [1.419366217s] [1.419366217s] END
I0410 05:23:47.434521       1 trace.go:205] Trace[1810118401]: "Create" url:/apis/example.com/v1alpha1/alidns,user-agent:cert-manager-challenges/v1.14.4 (linux/amd64) cert-manager/f5ddc412723722518f401f9ce6ec6fc950e72c04,client:172.16.0.237 (10-Apr-2024 05:23:45.071) (total time: 2362ms):
Trace[1810118401]: ---"Object stored in database" 2362ms (05:23:00.434)
Trace[1810118401]: [2.362668424s] [2.362668424s] END

在阿里DNS域名解析控制台处也可以洞察到webhook的操作。
在这里插入图片描述

同时观察certificate资源,发现对应证书已经签发成功。

PS:“READY”处已经为“True”

[root@core ssl-cert-tools]# kubectl get certificate -A
NAMESPACE      NAME                                READY   SECRET                              AGE
cert-manager   cert-test-ssl                       True    cert-test-ssl-tls

六、发布前端服务+配置ingress

让我们创建一个web服务模拟一下实际的生产环境吧~~

1、创建web业务

# test-deploy-ssl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-end
  namespace: cert-manager
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: test-end
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: test-end
    spec:
      containers:
      - image: nginx
        imagePullPolicy: Always
        name: test-end
        ports:
        - containerPort: 80
          protocol: TCP
        resources: {}
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  name: test-end
  namespace: cert-manager
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: test-end
  type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-end
  namespace: cert-manager
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
    # 开启强制跳转https
    nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'
spec:
  # 配置tls证书
  tls:
    - hosts:
      # 写入业务域名
      - certssl.xxxxxx.cn
      # 写入创建Certificate定义的“secretName”
      secretName: cert-test-ssl-tls 
  ingressClassName: nginx
  rules:
  - host: certssl.xxxxxx.cn
    http:
      paths:
      - backend:
          service:
            name: test-end
            port:
              number: 80
        path: /
        pathType: Prefix

2、生效配置

[root@core ssl-cert-tools]# kubectl apply -f .

六、访问验证

通过访问业务URL,发现Web页已经是https状态了,并且发现证书是可信状态,至此全过程结束
在这里插入图片描述

在这里插入图片描述

最后总结

不难发现,在我们这个模拟生产环境的kubernetes集群上,使用cert-manager这个证书管理工具来管理实际业务中大大小小的证书还是很方便的,当kubernetes集群中存在一个ClusterIssuer的角色,我们每一次创建完certificate资源,之后的证书续期工作都是由cert-manager来自动管理,这样我们可以更好的提高运维效率,将时间用在更有价值的地方,这点贼省心啊哈哈哈~

不过对于一些关键性的业务场景,由于Lets Encrypt证书无企业级支持,并且安全强度较低,所以还是推荐小伙伴选择企业版的SSL域名证书,更好更强的保障自己的业务哦~~~

目前我这边生产环境已经使用上它了,体验感还是非常好的,感兴趣的小伙伴赶紧来种草啊~~~

  • 31
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值