• 配置Ingress支持HTTPS访问(二):使用cert-manager申请证书


    一.系统环境

    服务器版本 docker软件版本 Kubernetes(k8s)集群版本 kube-bench版本 CPU架构
    Ubuntu 18.04.5 LTS Docker version 20.10.14 v1.22.2 0.6.7 x86_64

    Kubernetes集群架构:k8scludes1作为master节点,k8scludes2,k8scludes3作为worker节点。

    服务器 操作系统版本 CPU架构 进程 功能描述
    k8scludes1/192.168.110.128 Ubuntu 18.04.5 LTS x86_64 docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico k8s master节点
    k8scludes2/192.168.110.129 Ubuntu 18.04.5 LTS x86_64 docker,kubelet,kube-proxy,calico k8s worker节点
    k8scludes3/192.168.110.130 Ubuntu 18.04.5 LTS x86_64 docker,kubelet,kube-proxy,calico k8s worker节点

    二.前言

    在现代的应用程序开发中,使用HTTPS来保护数据传输的安全性变得越来越重要。而在Kubernetes集群中配置Ingress支持HTTPS访问,可以为我们的应用程序提供更高的安全性。

    本文将介绍如何在Kubernetes集群中配置Ingress支持HTTPS访问,使用Let's Encrypt和cert-manager工具来自动颁发和更新权威证书。

    注意:上一篇博客《Kubernetes集群中配置Ingress支持HTTPS访问(一):cfssl》里,使用cfssl工具生成了证书,实现了https访问,但是那个证书是我们自定义的,不是权威机构颁发的证书,在浏览器里https访问还是有警告,此次使用cert-manager向Let’s Encrypt机构申请的证书,是权威证书,在浏览器里https访问是不会有警告的。

    在Kubernetes集群中配置Ingress支持HTTPS访问的前提是已经有一套可以正常运行的Kubernetes集群,关于Kubernetes(k8s)集群的安装部署,可以查看博客《Ubuntu 安装部署Kubernetes(k8s)集群》https://www.cnblogs.com/renshengdezheli/p/17632858.html。

    三.Let's Encrypt和cert-manager简介

    Let’s Encrypt 是一家免费、开放、自动化的证书颁发机构(CA),它提供了免费的SSL/TLS证书。Let's Encrypt的证书由ACME协议自动颁发和更新。letsencrypt官网为:https://letsencrypt.org/zh-cn/,Let's Encrypt 的运作方式可以查看文档:https://letsencrypt.org/zh-cn/how-it-works/。

    image-20240523173229892

    cert-manager是一个用于管理证书生命周期的工具,它可以自动化证书的颁发和更新。它与Kubernetes紧密集成,可以轻松地在集群中部署和配置。cert-manager官网为:https://cert-manager.io/。

    Let’s Encrypt 可以免费提供证书,不过证书只有90天有效期,过期之后需要重新申请,使用cert-manager工具可以自动向Let’s Encrypt机构申请证书和续约证书,两者结合使用事半功倍。

    四.部署cert-manager

    4.1 安装cert-manager

    在博客《Kubernetes集群中配置Ingress支持HTTPS访问(一):cfssl》里详细介绍了配置ingress对外发布服务的步骤,本文不再赘述。

    cert-manager安装文档为:https://cert-manager.io/docs/installation/。

    安装cert-manager之后,会建立CRD资源类型(自定义资源类型),Kubernetes 1.7之后,提供了CRD(CustomResourceDefinitions)自定义资源的二次开发能力来扩展kubernetes API,通过此扩展可以向kubernetes API中增加新的资源类型,会比修改kubernetes apiserver的源代码或创建自定义的apiserver来的更加的简洁和容易。

    查看crd资源。

    root@k8scludes1:~# kubectl get crd -o wide
    NAME                                                  CREATED AT
    bgpconfigurations.crd.projectcalico.org               2022-04-16T18:41:13Z
    bgppeers.crd.projectcalico.org                        2022-04-16T18:41:13Z
    blockaffinities.crd.projectcalico.org                 2022-04-16T18:41:13Z
    caliconodestatuses.crd.projectcalico.org              2022-04-16T18:41:13Z
    clusterinformations.crd.projectcalico.org             2022-04-16T18:41:13Z
    felixconfigurations.crd.projectcalico.org             2022-04-16T18:41:13Z
    globalnetworkpolicies.crd.projectcalico.org           2022-04-16T18:41:13Z
    globalnetworksets.crd.projectcalico.org               2022-04-16T18:41:13Z
    hostendpoints.crd.projectcalico.org                   2022-04-16T18:41:13Z
    ipamblocks.crd.projectcalico.org                      2022-04-16T18:41:13Z
    ipamconfigs.crd.projectcalico.org                     2022-04-16T18:41:13Z
    ipamhandles.crd.projectcalico.org                     2022-04-16T18:41:13Z
    ippools.crd.projectcalico.org                         2022-04-16T18:41:13Z
    ipreservations.crd.projectcalico.org                  2022-04-16T18:41:13Z
    kubecontrollersconfigurations.crd.projectcalico.org   2022-04-16T18:41:13Z
    networkpolicies.crd.projectcalico.org                 2022-04-16T18:41:13Z
    networksets.crd.projectcalico.org                     2022-04-16T18:41:13Z
    

    创建cert-manager目录存放文件。

    root@k8scludes1:~# mkdir cert-manager
    
    root@k8scludes1:~# cd cert-manager/
    

    下载cert-manager的安装yaml文件。

    root@k8scludes1:~# wget https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.yaml
    
    root@k8scludes1:~/cert-manager# ls
    cert-manager.yaml
    

    查看 cert-manager.yaml 所需的镜像。

    root@k8scludes1:~/cert-manager# grep image cert-manager.yaml 
              image: "quay.io/jetstack/cert-manager-cainjector:v1.8.0"
              imagePullPolicy: IfNotPresent
              image: "quay.io/jetstack/cert-manager-controller:v1.8.0"
              imagePullPolicy: IfNotPresent
              image: "quay.io/jetstack/cert-manager-webhook:v1.8.0"
              imagePullPolicy: IfNotPresent
    

    在k8s的worker节点提前下载 cert-manager.yaml 所需的镜像。

    root@k8scludes2:~# docker pull quay.io/jetstack/cert-manager-cainjector:v1.8.0
    root@k8scludes2:~# docker pull quay.io/jetstack/cert-manager-controller:v1.8.0
    root@k8scludes2:~# docker pull quay.io/jetstack/cert-manager-webhook:v1.8.0
    
    root@k8scludes3:~# docker pull quay.io/jetstack/cert-manager-cainjector:v1.8.0
    root@k8scludes3:~# docker pull quay.io/jetstack/cert-manager-controller:v1.8.0
    root@k8scludes3:~# docker pull quay.io/jetstack/cert-manager-webhook:v1.8.0
    

    查看下载好的镜像。

    root@k8scludes2:~/cert-manager# docker images | grep cert-manager
    quay.io/jetstack/cert-manager-webhook                             v1.8.0    5efca4d28ca6   2 weeks ago     45.4MB
    quay.io/jetstack/cert-manager-cainjector                          v1.8.0    7c3e4d23dcd7   2 weeks ago     38.6MB
    quay.io/jetstack/cert-manager-controller                          v1.8.0    2b8eb1ab5ff9   2 weeks ago     57.4MB
    
    root@k8scludes3:~/cert-manager# docker images | grep cert-manager
    quay.io/jetstack/cert-manager-webhook                             v1.8.0    5efca4d28ca6   2 weeks ago     45.4MB
    quay.io/jetstack/cert-manager-cainjector                          v1.8.0    7c3e4d23dcd7   2 weeks ago     38.6MB
    quay.io/jetstack/cert-manager-controller                          v1.8.0    2b8eb1ab5ff9   2 weeks ago     57.4MB
    

    安装cert-manager。

    root@k8scludes1:~/cert-manager# ls
    cert-manager.yaml
    
    root@k8scludes1:~/cert-manager# kubectl apply -f cert-manager.yaml 
    namespace/cert-manager created
    customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
    customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
    customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
    ......
    deployment.apps/cert-manager-webhook created
    mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
    validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
    

    查看cert-manager命名空间里的所有资源。

    root@k8scludes1:~/cert-manager# kubectl get all -n cert-manager -o wide
    NAME                                           READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
    pod/cert-manager-b4d6fd99b-mndtp               1/1     Running   0          61s   10.244.1.96      k8scludes3   <none>           <none>
    pod/cert-manager-cainjector-74bfccdfdf-l6kh9   1/1     Running   0          61s   10.244.218.162   k8scludes2   <none>           <none>
    ......
    replicaset.apps/cert-manager-webhook-65b766b5f8      1         1         1       61s   cert-manager   quay.io/jetstack/cert-manager-webhook:v1.8.0      app.kubernetes.io/component=webhook,app.kubernetes.io/instance=cert-manager,app.kubernetes.io/name=webhook,pod-template-hash=65b766b5f8
    

    可以看到crd是全局生效的,不受命名空间限制。

    root@k8scludes1:~/cert-manager# kubectl get crd -o wide -n cert-manager
    NAME                                                  CREATED AT
    bgpconfigurations.crd.projectcalico.org               2022-04-16T18:41:13Z
    bgppeers.crd.projectcalico.org                        2022-04-16T18:41:13Z
    blockaffinities.crd.projectcalico.org                 2022-04-16T18:41:13Z
    caliconodestatuses.crd.projectcalico.org              2022-04-16T18:41:13Z
    certificaterequests.cert-manager.io                   2022-04-24T17:07:46Z
    certificates.cert-manager.io                          2022-04-24T17:07:46Z
    challenges.acme.cert-manager.io                       2022-04-24T17:07:46Z
    clusterinformations.crd.projectcalico.org             2022-04-16T18:41:13Z
    clusterissuers.cert-manager.io                        2022-04-24T17:07:46Z
    felixconfigurations.crd.projectcalico.org             2022-04-16T18:41:13Z
    globalnetworkpolicies.crd.projectcalico.org           2022-04-16T18:41:13Z
    globalnetworksets.crd.projectcalico.org               2022-04-16T18:41:13Z
    hostendpoints.crd.projectcalico.org                   2022-04-16T18:41:13Z
    ipamblocks.crd.projectcalico.org                      2022-04-16T18:41:13Z
    ipamconfigs.crd.projectcalico.org                     2022-04-16T18:41:13Z
    ipamhandles.crd.projectcalico.org                     2022-04-16T18:41:13Z
    ippools.crd.projectcalico.org                         2022-04-16T18:41:13Z
    ipreservations.crd.projectcalico.org                  2022-04-16T18:41:13Z
    issuers.cert-manager.io                               2022-04-24T17:07:46Z
    kubecontrollersconfigurations.crd.projectcalico.org   2022-04-16T18:41:13Z
    networkpolicies.crd.projectcalico.org                 2022-04-16T18:41:13Z
    networksets.crd.projectcalico.org                     2022-04-16T18:41:13Z
    orders.acme.cert-manager.io                           2022-04-24T17:07:46Z
    

    查看和cert-manager相关的crd资源。

    root@k8scludes1:~/cert-manager# kubectl get crd | grep cert
    certificaterequests.cert-manager.io                   2022-04-24T17:07:46Z
    certificates.cert-manager.io                          2022-04-24T17:07:46Z
    challenges.acme.cert-manager.io                       2022-04-24T17:07:46Z
    clusterissuers.cert-manager.io                        2022-04-24T17:07:46Z
    issuers.cert-manager.io                               2022-04-24T17:07:46Z
    orders.acme.cert-manager.io                           2022-04-24T17:07:46Z
    

    4.2 创建clusterissuer

    cert-manager会创建clusterissuer自定义资源,clusterissuer会向letsencrypt机构申请证书和续约证书。

    用户向clusterissuer提出申请证书请求,clusterissuer向letsencrypt机构申请证书,letsencrypt机构进行审核,假如申请的域名为www.nginxx.com,letsencrypt,机构会审核www.nginxx.com这个站点是不是你的?审核的方式有:http01和dns01。

    • 使用http01的审核方式:letsencrypt机构会登录到www.nginxx.com,看看能不能访问成功,访问成功就证明是你的网站,我们现在测试环境为内网环境,letsencrypt访问不了;
    • 使用dns01的审核方式:如果www.nginxx.com是你的站点,你肯定有dns服务器的操控权,在DNS服务器上生成一个api token,letsencrypt会尝试使用这个api token往DNS服务器写入内容,如果能写入成功,则说明www.nginxx.com站点是你的,就会审核通过。本文使用dns01的方式。

    现在还没有clusterissuer资源,clusterissuer是全局生效的,不受命名空间限制。

    root@k8scludes1:~/cert-manager# kubectl get clusterissuer
    No resources found
    
    root@k8scludes1:~/cert-manager# kubectl get clusterissuer -n cert-manager
    No resources found
    

    创建Issuer和ClusterIssuer可以去官网找例子:https://cert-manager.io/docs/configuration/acme/dns01/。

    letsencrypt审核域名的方式我们使用DNS01的方式,letsencrypt支持的DNS服务器有限,本次使用Cloudflare DNS服务器。

    root@k8scludes1:~/cert-manager# cat clusterissuer.yaml 
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      #ClusterIssuer的名字
      name: letsencrypt-dns01
    spec:
      acme:
        privateKeySecretRef:
          name: letsencrypt-dns01
          #ClusterIssuer去https://acme-v02.api.letsencrypt.org/directory申请证书
        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            
    

    cert-manager配置cloudflare DNS的yaml文件可以查看官网示例:https://cert-manager.io/docs/configuration/acme/dns01/cloudflare/。

    要使用Cloudflare DNS服务器,需要先注册一个Cloudflare账号,Cloudflare网址为:https://dash.cloudflare.com/login。

    注册成功之后登录Cloudflare。

    image-20240524103751436

    添加站点,但是域名没有注册,现在先去阿里云申请一个域名。

    image-20240524103929142

    4.3 申请域名

    登录阿里云,工作台-->点击域名。

    image-20230728175735298

    点击注册域名。

    image-20230728175803789

    输入域名--->查域名,我申请的域名为rengshengdezheli。

    image-20230728175834038

    选择一个便宜的域名,加入清单。

    image-20230728175900896

    点击域名清单。

    image-20230728175936837

    结算一下。

    image-20230728180017067

    经过个人信息审核之后,域名申请下来了,我的域名为rengshengdezheli.xyz。

    image-20230728180050302

    在域名列表查看域名信息。

    image-20240524104434605

    此时域名申请成功了。

    4.4 Cloudflare添加站点

    使用新申请到的域名,到Cloudflare添加站点。

    image-20240524114157988

    选择免费的计划,点击继续。

    image-20230728180253093

    点击继续。

    image-20230728180341516

    点击确定。

    image-20230728180433585

    4.5 修改阿里云的名称服务器为cloudflare名称服务器

    按照要求要把阿里云的名称服务器更改为cloudflare名称服务器。

    image-20230728180521066

    去到阿里云网站,找到域名,域名列表,点击修改DNS。

    image-20240524115113654

    点击修改DNS服务器。

    image-20230731154352395

    把DNS服务器修改为cloudflare的DNS服务器,最后点击确定。

    image-20230731154440769

    现在就修改好了。

    image-20240524115439795

    返回cloudflare网站,检查名称服务器。

    image-20230731154553888

    配置好之后会出现如下界面。

    image-20230731154640718

    现在域名rengshengdezheli.xyz的DNS服务器就是cloudflare服务器了。

    4.6 获取API Tokens

    根据cert-manager官网的指引:https://cert-manager.io/docs/configuration/acme/dns01/cloudflare/,我们获取API Tokens。

    image-20230731154724032

    回到Cloudflare网站,点击获取您的API令牌。

    image-20230731154809053

    点击创建令牌。

    image-20230731154837238

    创建自定义令牌,点击开始使用。

    image-20230731154911214

    填写API令牌的名称,权限和区域资源按照cert-manager的要求设置,点击继续以显示摘要。

    image-20230731155002676

    点击创建令牌。

    image-20230731155043090

    此时API令牌就创建好了。

    image-20230731155115548

    测试我们创建的令牌是否正常。"success":true表示我们创建的令牌正常了。

    root@k8scludes1:~/cert-manager# curl -X GET "https://api.cloudflare.com/client/v4/user/tokens/verify" \
    >      -H "Authorization: Bearer LKA4oW_7lHqgD66UgbTK5cMYq_4JUQ7kirCGCRj4" \
    >      -H "Content-Type:application/json"
    {"result":{"id":"8ee3954262ba4d0aeaa90c6fbe94af69","status":"active"},"success":true,"errors":[],"messages":[{"code":10000,"message":"This API Token is valid and active","type":null}]}root@k8scludes1:~/cert-manager# 
    

    letsencrypt通过我们创建的API令牌就可以往我们的cloudflare DNS服务器里写入内容,如果成功写入内容,则证明站点rengshengdezheli.xyz是我们的,则审核通过。

    4.7 创建secret存储API token

    现在需要把API令牌告诉letsencrypt,通过clusterissuer告诉letsencrypt我们的API令牌。

    因为创建clusterissuer需要存着API token的secret,所以现在创建secret。

    查看 cert-manager命名空间的secret。

    root@k8scludes1:~/cert-manager# kubectl get secrets -n cert-manager
    NAME                                  TYPE                                  DATA   AGE
    cert-manager-cainjector-token-ltxpd   kubernetes.io/service-account-token   3      19h
    cert-manager-token-k5s55              kubernetes.io/service-account-token   3      19h
    cert-manager-webhook-ca               Opaque                                3      19h
    cert-manager-webhook-token-x94pp      kubernetes.io/service-account-token   3      19h
    default-token-wl2sx                   kubernetes.io/service-account-token   3      19h
    

    创建一个secret存储API令牌,secret的创建方法,官网也有例子。

    apiVersion: v1
    kind: Secret
    metadata:
      name: cloudflare-api-token-secret
    type: Opaque
    stringData:
      api-token: >
    

    本次使用命令行的方式创建secret,--from-literal指定键值对: api-token是键,LKA4oW_7lHqgD66UgbTK5cMYq_4JUQ7kirCGCRj4 就是我们创建的API令牌(API token )。

    root@k8scludes1:~/cert-manager# kubectl create secret generic cloudflare-api-token-secret --from-literal=api-token=LKA4oW_7lHqgD66UgbTK5cMYq_4JUQ7kirCGCRj4 -n cert-manager 
    secret/cloudflare-api-token-secret created
    

    查看创建的secrets。

    root@k8scludes1:~/cert-manager# kubectl get secrets -n cert-manager 
    NAME                                  TYPE                                  DATA   AGE
    cert-manager-cainjector-token-ltxpd   kubernetes.io/service-account-token   3      19h
    cert-manager-token-k5s55              kubernetes.io/service-account-token   3      19h
    cert-manager-webhook-ca               Opaque                                3      19h
    cert-manager-webhook-token-x94pp      kubernetes.io/service-account-token   3      19h
    cloudflare-api-token-secret           Opaque                                1      116s
    default-token-wl2sx                   kubernetes.io/service-account-token   3      19h
    

    4.8 配置clusterissuer

    存储API token的secret创建好了,就可以创建clusterissuer了。

    root@k8scludes1:~/cert-manager# vim clusterissuer.yaml 
    
    root@k8scludes1:~/cert-manager# cat clusterissuer.yaml 
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      #ClusterIssuer名字
      name: letsencrypt-dns01
    spec:
      acme:
        privateKeySecretRef:
          name: letsencrypt-dns01
          #ClusterIssuer去https://acme-v02.api.letsencrypt.org/directory申请证书
        server: https://acme-v02.api.letsencrypt.org/directory
        solvers:
        - dns01:
            cloudflare:
              email: 5386225891@qq.com
              #指定存储着API token的secret,secret的名字为cloudflare-api-token-secret,secret的key为api-token
              apiTokenSecretRef:
                key: api-token
                name: cloudflare-api-token-secret
    

    下面创建clusterissuer。

    root@k8scludes1:~/cert-manager# kubectl apply -f clusterissuer.yaml 
    clusterissuer.cert-manager.io/letsencrypt-dns01 created
    

    clusterissuer创建成功。

    root@k8scludes1:~/cert-manager# kubectl get clusterissuers.cert-manager.io 
    NAME                READY   AGE
    letsencrypt-dns01   True    29s
    
    root@k8scludes1:~/cert-manager# kubectl get clusterissuers.cert-manager.io -o wide
    NAME                READY   STATUS                                                 AGE
    letsencrypt-dns01   True    The ACME account was registered with the ACME server   33s
    

    clusterissuers创建好之后,下面开始申请证书。

    五.申请证书

    查看现在是否有证书,现在没有证书。

    root@k8scludes1:~/cert-manager# kubectl get certificate -o wide
    No resources found in tls-ingress namespace.
    

    编写申请证书的yaml文件。

    root@k8scludes1:~/cert-manager# vim certificate.yaml 
    
    root@k8scludes1:~/cert-manager# cat certificate.yaml 
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      #cert-zheli-com是申请的证书名字
      name: cert-zheli-com
    spec:
      dnsNames:
      #www.rengshengdezheli.xyz表示申请的证书只给www.rengshengdezheli.xyz用
      - www.rengshengdezheli.xyz
      issuerRef:
        kind: ClusterIssuer
        #name: letsencrypt-dns01表示使用哪个ClusterIssuer申请证书
        name: letsencrypt-dns01 
      #secretName: cert-zheli-com-tls表示申请到的证书放在哪个secret里面
      secretName: cert-zheli-com-tls 
    

    现在申请证书。

    root@k8scludes1:~/cert-manager# kubectl apply -f certificate.yaml 
    certificate.cert-manager.io/cert-zheli-com created
    

    查看证书,有证书但是READY状态为False。

    root@k8scludes1:~/cert-manager# kubectl get certificate -o wide
    NAME             READY   SECRET               ISSUER              STATUS                                         AGE
    cert-zheli-com   False   cert-zheli-com-tls   letsencrypt-dns01   Issuing certificate as Secret does not exist   26s
    

    查看secret。

    root@k8scludes1:~/cert-manager# kubectl get secrets -o wide
    NAME                   TYPE                                  DATA   AGE
    cert-zheli-com-btt2t   Opaque                                1      2m16s
    default-token-mxb4r    kubernetes.io/service-account-token   3      7d8h
    test-tls-secret        kubernetes.io/tls                     2      3d8h
    

    查看证书请求。

    root@k8scludes1:~/cert-manager# kubectl get certificaterequests.cert-manager.io -o wide
    NAME                   APPROVED   DENIED   READY   ISSUER              REQUESTOR                                         STATUS                                         AGE
    cert-zheli-com-cbkt2   True                True    letsencrypt-dns01   system:serviceaccount:cert-manager:cert-manager   Certificate fetched from issuer successfully   3m54s
    

    查看challenges,challenges用来验证证书请求是否成功,当证书申请成功之后,challenges会消失,certificaterequests的READY状态变为True。

    root@k8scludes1:~/cert-manager# kubectl get challenges.acme.cert-manager.io -o wide
    No resources found in tls-ingress namespace.
    

    现在cert-zheli-com证书申请成功,READY状态变为True。

    root@k8scludes1:~/cert-manager# kubectl get certificate -o wide
    NAME             READY   SECRET               ISSUER              STATUS                                          AGE
    cert-zheli-com   True    cert-zheli-com-tls   letsencrypt-dns01   Certificate is up to date and has not expired   10m
    

    secret由cert-zheli-com-btt2t变为cert-zheli-com-tls,现在证书就在cert-zheli-com-tls里面了。

    root@k8scludes1:~/cert-manager# kubectl get secrets -o wide
    NAME                  TYPE                                  DATA   AGE
    cert-zheli-com-tls    kubernetes.io/tls                     2      11m
    default-token-mxb4r   kubernetes.io/service-account-token   3      7d8h
    test-tls-secret       kubernetes.io/tls                     2      3d9h
    

    六.配置ingress使用证书

    删除存在的ingress规则。

    root@k8scludes1:~/cert-manager# kubectl get ingress
    NAME         CLASS    HOSTS            ADDRESS           PORTS     AGE
    my-ingress   <none>   www.nginxx.com   192.168.110.129   80, 443   30h
    
    root@k8scludes1:~/cert-manager# kubectl delete ingress my-ingress 
    ingress.networking.k8s.io "my-ingress" deleted
    
    root@k8scludes1:~/cert-manager# kubectl get ingress
    No resources found in tls-ingress namespace.
    

    修改ingress规则,- www.rengshengdezheli.xyz表示申请的证书只给www.rengshengdezheli.xyz这个域名用,secretName: cert-zheli-com-tls表示证书放在cert-zheli-com-tls这个secret里。

    root@k8scludes1:~/cert-manager# vim ingress-rule.yaml 
    
    root@k8scludes1:~/cert-manager# cat ingress-rule.yaml 
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-ingress
      annotations:
        kubernetes.io/ingress.class: "nginx"
    spec:
      tls: 
      - hosts: 
        - www.rengshengdezheli.xyz
        secretName: cert-zheli-com-tls
      rules:
      - host: www.rengshengdezheli.xyz
        http:
          paths:
          #访问网址目录
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx1svc
                port:
                  number: 80
          - path: /ingress
            pathType: Prefix
            backend:
              service:
                name: nginx3svc
                port:
                  number: 80
          - path: /n2
            pathType: Prefix
            backend:
              service:
                name: nginx2svc
                port:
                  number: 80
    

    应用ingress规则。

    root@k8scludes1:~/cert-manager# kubectl apply -f ingress-rule.yaml 
    ingress.networking.k8s.io/my-ingress created
    
    root@k8scludes1:~/cert-manager# kubectl get ingress -o wide
    NAME         CLASS    HOSTS                      ADDRESS   PORTS     AGE
    my-ingress   <none>   www.rengshengdezheli.xyz             80, 443   9s
    

    查看svc,443端口映射为31473了。

    root@k8scludes1:~/cert-manager# kubectl get svc -o wide -n ingress-nginx
    NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE    SELECTOR
    ingress-nginx-controller             NodePort    10.98.61.146    <none>        80:31853/TCP,443:31473/TCP   5d7h   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
    ingress-nginx-controller-admission   ClusterIP   10.102.212.60   <none>        443/TCP                      5d7h   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
    

    七.客户端访问ingress服务

    7.1 Windows客户端访问ingress服务

    证书申请下来之后,使用Windows客户端访问ingress服务。

    注意:C:/Windows/System32/drivers/etc/HOSTS里的IP域名映射也要修改。内容修改如下,192.168.110.129是ingress-nginx-controller所在的机器IP。

    192.168.110.129 www.rengshengdezheli.xyz
    

    浏览器访问https://www.rengshengdezheli.xyz:31473/,可以发现现在浏览器访问https://www.rengshengdezheli.xyz:31473/没有警告了。

    image-20230731155756113

    查看证书,显示连接是安全的。

    image-20230731155821746

    点击查看证书信息。

    image-20230731155845309

    可以看到详细的证书信息。

    image-20230731155909803

    7.2 Linux客户端访问ingress服务

    下面使用Linux客户端访问ingress服务,可以看到证书颁发机构:issuer: CN=R3,O=Let's Encrypt,C=US。

    [root@etcd2 ~]# curl https://www.rengshengdezheli.xyz:31473/
    111
    
    [root@etcd2 ~]# curl -kv https://www.rengshengdezheli.xyz:31473/
    * About to connect() to www.rengshengdezheli.xyz port 31473 (#0)
    *   Trying 192.168.110.129...
    * Connected to www.rengshengdezheli.xyz (192.168.110.129) port 31473 (#0)
    * Initializing NSS with certpath: sql:/etc/pki/nssdb
    * skipping SSL peer certificate verification
    * SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    * Server certificate:
    * 	subject: CN=www.rengshengdezheli.xyz
    * 	start date: 425 16:11:21 2022 GMT
    * 	expire date: 724 16:11:20 2022 GMT
    * 	common name: www.rengshengdezheli.xyz
    * 	issuer: CN=R3,O=Let's Encrypt,C=US
    > GET / HTTP/1.1
    > User-Agent: curl/7.29.0
    > Host: www.rengshengdezheli.xyz:31473
    > Accept: */*
    > 
    < HTTP/1.1 200 OK
    < Date: Mon, 25 Apr 2022 17:51:19 GMT
    < Content-Type: text/html
    < Content-Length: 4
    < Connection: keep-alive
    < Last-Modified: Mon, 25 Apr 2022 17:34:19 GMT
    < ETag: "6266db9b-4"
    < Accept-Ranges: bytes
    < Strict-Transport-Security: max-age=15724800; includeSubDomains
    < 
    111
    * Connection #0 to host www.rengshengdezheli.xyz left intact
    

    八.配置clusterissuer自动申请证书

    上一步,我们申请证书的步骤是创建certificate,然后clusterissuer使用certificate申请证书,最后带有certificate信息的secret和ingress一起使用。

    我们现在使用另外一种方法,创建ingress的时候自动让clusterissuer申请证书,不用创建certificate yaml文件。

    删除证书。

    root@k8scludes1:~/cert-manager# kubectl get certificate
    NAME             READY   SECRET               AGE
    cert-zheli-com   True    cert-zheli-com-tls   48m
    
    root@k8scludes1:~/cert-manager# kubectl delete certificate cert-zheli-com 
    certificate.cert-manager.io "cert-zheli-com" deleted
    
    root@k8scludes1:~/cert-manager# kubectl get certificate
    No resources found in tls-ingress namespace.
    

    删除secret。

    root@k8scludes1:~/cert-manager# kubectl get secrets 
    NAME                  TYPE                                  DATA   AGE
    cert-zheli-com-tls    kubernetes.io/tls                     2      47m
    default-token-mxb4r   kubernetes.io/service-account-token   3      7d8h
    test-tls-secret       kubernetes.io/tls                     2      3d9h
    
    root@k8scludes1:~/cert-manager# kubectl delete secrets cert-zheli-com-tls 
    secret "cert-zheli-com-tls" deleted
    
    root@k8scludes1:~/cert-manager# kubectl get secrets 
    NAME                  TYPE                                  DATA   AGE
    default-token-mxb4r   kubernetes.io/service-account-token   3      7d8h
    test-tls-secret       kubernetes.io/tls                     2      3d9h
    

    修改ingress规则,添加cert-manager.io/cluster-issuer: "letsencrypt-dns01"表示使用名为letsencrypt-dns01的clusterissuer申请证书。

    当我们创建ingress规则之后,会自动使用名为letsencrypt-dns01的clusterissuer申请证书,申请的证书放在名为cert-zheli-com-tls的secret里。

    root@k8scludes1:~/cert-manager# vim ingress-rule.yaml 
    
    root@k8scludes1:~/cert-manager# cat ingress-rule.yaml 
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-ingress
      annotations:
        kubernetes.io/ingress.class: "nginx"
        cert-manager.io/cluster-issuer: "letsencrypt-dns01"
    spec:
      tls: 
      - hosts: 
        - www.rengshengdezheli.xyz
        secretName: cert-zheli-com-tls
      rules:
      - host: www.rengshengdezheli.xyz
        http:
          paths:
          #访问网址目录
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx1svc
                port:
                  number: 80
          - path: /ingress
            pathType: Prefix
            backend:
              service:
                name: nginx3svc
                port:
                  number: 80
          - path: /n2
            pathType: Prefix
            backend:
              service:
                name: nginx2svc
                port:
                  number: 80
    

    现在没有证书。

    root@k8scludes1:~/cert-manager# kubectl get certificate
    No resources found in tls-ingress namespace.
    
    root@k8scludes1:~/cert-manager# kubectl get secrets 
    NAME                  TYPE                                  DATA   AGE
    default-token-mxb4r   kubernetes.io/service-account-token   3      7d9h
    test-tls-secret       kubernetes.io/tls                     2      3d10h
    

    删除以前的ingress规则。

    root@k8scludes1:~/cert-manager# kubectl get ingress
    NAME         CLASS    HOSTS                      ADDRESS           PORTS     AGE
    my-ingress   <none>   www.rengshengdezheli.xyz   192.168.110.129   80, 443   53m
    
    root@k8scludes1:~/cert-manager# kubectl delete ingress my-ingress 
    ingress.networking.k8s.io "my-ingress" deleted
    root@k8scludes1:~/cert-manager# kubectl get ingress
    No resources found in tls-ingress namespace.
    

    创建ingress规则。

    root@k8scludes1:~/cert-manager# kubectl apply -f ingress-rule.yaml 
    ingress.networking.k8s.io/my-ingress created
    
    root@k8scludes1:~/cert-manager# kubectl get ingress -o wide
    NAME         CLASS    HOSTS                      ADDRESS   PORTS     AGE
    my-ingress   <none>   www.rengshengdezheli.xyz             80, 443   9s
    

    现在创建ingress规则之后,就自动申请了证书了。

    root@k8scludes1:~/cert-manager# kubectl get certificate -o wide
    NAME                 READY   SECRET               ISSUER              STATUS                                          AGE
    cert-zheli-com-tls   True    cert-zheli-com-tls   letsencrypt-dns01   Certificate is up to date and has not expired   21s
    
    root@k8scludes1:~/cert-manager# kubectl get secrets -o wide
    NAME                  TYPE                                  DATA   AGE
    cert-zheli-com-tls    kubernetes.io/tls                     2      47s
    default-token-mxb4r   kubernetes.io/service-account-token   3      7d9h
    test-tls-secret       kubernetes.io/tls                     2      3d10h
    
    
    root@k8scludes1:~/cert-manager# kubectl get clusterissuers.cert-manager.io -o wide
    NAME                READY   STATUS                                                 AGE
    letsencrypt-dns01   True    The ACME account was registered with the ACME server   5h37m
    

    证书到期之后,clusterissuers会自动给我们续约的。

    可以查看我们创建的clusterissuer的yaml文件。

    root@k8scludes1:~/cert-manager# kubectl get clusterissuers.cert-manager.io letsencrypt-dns01 -o yaml >letsencrypt-dns01.yaml
    
    root@k8scludes1:~/cert-manager# cat letsencrypt-dns01.yaml 
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      annotations:
        kubectl.kubernetes.io/last-applied-configuration: |
          {"apiVersion":"cert-manager.io/v1","kind":"ClusterIssuer","metadata":{"annotations":{},"name":"letsencrypt-dns01"},"spec":{"acme":{"privateKeySecretRef":{"name":"letsencrypt-dns01"},"server":"https://acme-v02.api.letsencrypt.org/directory","solvers":[{"dns01":{"cloudflare":{"apiTokenSecretRef":{"key":"api-token","name":"cloudflare-api-token-secret"},"email":"2484990158@qq.com"}}}]}}}
      creationTimestamp: "2022-04-25T12:51:49Z"
      generation: 1
      name: letsencrypt-dns01
      resourceVersion: "389137"
      uid: 61ef0780-8889-486f-8fa7-a68ba0ce72da
    spec:
      acme:
        preferredChain: ""
        privateKeySecretRef:
          name: letsencrypt-dns01
        server: https://acme-v02.api.letsencrypt.org/directory
        solvers:
        - dns01:
            cloudflare:
              apiTokenSecretRef:
                key: api-token
                name: cloudflare-api-token-secret
              email: 2484990158@qq.com
    status:
      acme:
        uri: https://acme-v02.api.letsencrypt.org/acme/acct/515015057
      conditions:
      - lastTransitionTime: "2022-04-25T12:51:52Z"
        message: The ACME account was registered with the ACME server
        observedGeneration: 1
        reason: ACMEAccountRegistered
        status: "True"
        type: Ready
    

    九.没有域名的情况下申请证书

    上面方法需要买一个域名才能进行,当我们没有域名的时候,也可以模拟使用cert-manager申请证书。

    没有域名的情况下申请证书思路:先模拟一个CA(CA是权威机构),创建一个clusterissuer,再创建一个certificate去向CA申请证书。

    删除clusterissuer。

    root@k8scludes1:~# kubectl get clusterissuers.cert-manager.io 
    NAME                READY   AGE
    letsencrypt-dns01   True    14h
    
    root@k8scludes1:~# kubectl delete clusterissuers.cert-manager.io letsencrypt-dns01 
    clusterissuer.cert-manager.io "letsencrypt-dns01" deleted
    

    删除证书。

    root@k8scludes1:~# kubectl get certificate
    NAME                 READY   SECRET               AGE
    cert-zheli-com-tls   True    cert-zheli-com-tls   8h
    
    root@k8scludes1:~# kubectl delete certificate cert-zheli-com-tls 
    certificate.cert-manager.io "cert-zheli-com-tls" deleted
    

    删除secret。

    root@k8scludes1:~# kubectl get secrets 
    NAME                  TYPE                                  DATA   AGE
    cert-zheli-com-tls    kubernetes.io/tls                     2      8h
    default-token-mxb4r   kubernetes.io/service-account-token   3      7d18h
    test-tls-secret       kubernetes.io/tls                     2      3d18h
    
    root@k8scludes1:~# kubectl delete secrets cert-zheli-com-tls 
    secret "cert-zheli-com-tls" deleted
    

    删除ingress。

    root@k8scludes1:~/cert-manager# kubectl get ingress
    NAME         CLASS    HOSTS                      ADDRESS           PORTS     AGE
    my-ingress   <none>   www.rengshengdezheli.xyz   192.168.110.129   80, 443   9h
    
    root@k8scludes1:~/cert-manager# kubectl delete ingress my-ingress 
    ingress.networking.k8s.io "my-ingress" deleted
    

    上一篇博客《Kubernetes集群中配置Ingress支持HTTPS访问(一):cfssl》里,我们已经创建了CA的证书(ca.pem)和ca的私钥(ca-key.pem)。

    root@k8scludes1:~# cd TLS-ingress/tls/
    
    root@k8scludes1:~/TLS-ingress/tls# ls
    ca-config.json  ca.csr  ca-csr.json  ca-key.pem  ca.pem  test.csr  test-csr.json  test-key.pem  test.pem
    

    把CA的证书和密钥写入到 secret里,创建一个tls类型的secret,里面包含CA证书,CA私钥。

    root@k8scludes1:~/TLS-ingress/tls# kubectl create secret tls ca-secret --cert=ca.pem --key=ca-key.pem --namespace=cert-manager 
    secret/ca-secret created
    
    root@k8scludes1:~/TLS-ingress/tls# kubectl get secrets -o wide -n cert-manager 
    NAME                                  TYPE                                  DATA   AGE
    ca-secret                             kubernetes.io/tls                     2      16s
    cert-manager-cainjector-token-ltxpd   kubernetes.io/service-account-token   3      34h
    cert-manager-token-k5s55              kubernetes.io/service-account-token   3      34h
    cert-manager-webhook-ca               Opaque                                3      34h
    cert-manager-webhook-token-x94pp      kubernetes.io/service-account-token   3      34h
    cloudflare-api-token-secret           Opaque                                1      14h
    default-token-wl2sx                   kubernetes.io/service-account-token   3      34h
    letsencrypt-dns01                     Opaque                                1      14h
    

    现在模拟的CA已经创建好了,接下来创建clusterissuer。

    namespace: cert-manager这个可以不写,因为ClusterIssuer是全局的,无所谓命名空间,secretName: ca-secret指定ca证书放在哪个secret里面。

    root@k8scludes1:~/TLS-ingress/tls# cd ~/cert-manager/
    
    root@k8scludes1:~/cert-manager# vim clusterissuer-moni.yaml 
    
    root@k8scludes1:~/cert-manager# cat clusterissuer-moni.yaml 
    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      #ClusterIssuer名字
      name: letsencrypt-ca-moni
      namespace: cert-manager
    spec:
      ca:
        secretName: ca-secret
    

    用自己创建的CA模拟签发机构。

    创建clusterissuer。

    root@k8scludes1:~/cert-manager# kubectl apply -f clusterissuer-moni.yaml 
    clusterissuer.cert-manager.io/letsencrypt-ca-moni created
    
    root@k8scludes1:~/cert-manager# kubectl get clusterissuer -o wide
    NAME                  READY   STATUS                AGE
    letsencrypt-ca-moni   True    Signing CA verified   21s
    

    修改certificate配置文件。

    root@k8scludes1:~/cert-manager# vim certificate-moni.yaml 
    
    root@k8scludes1:~/cert-manager# cat certificate-moni.yaml 
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      #name: cert-zheli-com-moni表示申请到证书命名为cert-zheli-com-moni
      name: cert-zheli-com-moni
    spec:
      dnsNames:
      - www.rengshengdezheli.xyz
      issuerRef:
        kind: ClusterIssuer
        #name: letsencrypt-ca-moni表示使用letsencrypt-ca-moni这个clusterissuer申请证书
        name: letsencrypt-ca-moni 
      #secretName: cert-zheli-com-moni-tls表示申请到的证书放在cert-zheli-com-moni-tls这个secret里
      secretName: cert-zheli-com-moni-tls 
    

    申请证书。

    root@k8scludes1:~/cert-manager# kubectl apply -f certificate-moni.yaml 
    certificate.cert-manager.io/cert-zheli-com-moni created
    

    现在已经向我们自己创建的CA申请到证书了。

    root@k8scludes1:~/cert-manager# kubectl get certificate -o wide
    NAME                  READY   SECRET                    ISSUER                STATUS                                          AGE
    cert-zheli-com-moni   True    cert-zheli-com-moni-tls   letsencrypt-ca-moni   Certificate is up to date and has not expired   18s
    

    证书在cert-zheli-com-moni-tls里面。

    root@k8scludes1:~/cert-manager# kubectl get secrets -o wide
    NAME                      TYPE                                  DATA   AGE
    cert-zheli-com-moni-tls   kubernetes.io/tls                     3      93s
    default-token-mxb4r       kubernetes.io/service-account-token   3      7d18h
    test-tls-secret           kubernetes.io/tls                     2      3d19h
    

    修改ingress规则,- www.rengshengdezheli.xyz表示申请到的证书只能用于www.rengshengdezheli.xyz这个域名,secretName: cert-zheli-com-moni-tls表示证书放在cert-zheli-com-moni-tls这个secret里。

    root@k8scludes1:~/cert-manager# vim ingress-rule-moni.yaml 
    
    root@k8scludes1:~/cert-manager# cat ingress-rule-moni.yaml 
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: my-ingress
      annotations:
        kubernetes.io/ingress.class: "nginx"
    spec:
      tls: 
      - hosts: 
        - www.rengshengdezheli.xyz
        secretName: cert-zheli-com-moni-tls
      rules:
      - host: www.rengshengdezheli.xyz
        http:
          paths:
          #访问网址目录
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx1svc
                port:
                  number: 80
          - path: /ingress
            pathType: Prefix
            backend:
              service:
                name: nginx3svc
                port:
                  number: 80
          - path: /n2
            pathType: Prefix
            backend:
              service:
                name: nginx2svc
                port:
                  number: 80
    

    应用ingress规则。

    root@k8scludes1:~/cert-manager# kubectl get ingress
    No resources found in tls-ingress namespace.
    
    root@k8scludes1:~/cert-manager# kubectl apply -f ingress-rule-moni.yaml 
    ingress.networking.k8s.io/my-ingress created
    
    root@k8scludes1:~/cert-manager# kubectl get ingress -o wide
    NAME         CLASS    HOSTS                      ADDRESS           PORTS     AGE
    my-ingress   <none>   www.rengshengdezheli.xyz   192.168.110.129   80, 443   11s
    

    查看svc,443端口映射为31473。

    root@k8scludes1:~/cert-manager# kubectl get svc -o wide -n ingress-nginx
    NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE     SELECTOR
    ingress-nginx-controller             NodePort    10.98.61.146    <none>        80:31853/TCP,443:31473/TCP   5d18h   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
    ingress-nginx-controller-admission   ClusterIP   10.102.212.60   <none>        443/TCP                      5d18h   app.kubernetes.io/component=controller,app.kubernetes.io/instance=ingress-nginx,app.kubernetes.io/name=ingress-nginx
    

    下面使用Windows客户端访问ingress服务。

    这次我们使用IE浏览器访问:https://www.rengshengdezheli.xyz:31473/ingress/,访问成功。

    image-20230731160542652

    查看证书。

    image-20230731160607809

    可以看到这个证书是我们自定义的证书。

    image-20230731160637879

    十.总结

    通过使用Let's Encrypt和cert-manager工具,我们可以在Kubernetes集群中配置Ingress支持HTTPS访问。这样可以为我们的应用程序提供更高的安全性,保护数据传输的机密性和完整性。

  • 相关阅读:
    Java 多线程共享模型之管程(下)
    云原生Kubernetes:Rancher管理k8s集群
    FPGA之旅设计99例之第十三例-----FPGA在OLED上显示DHT11数据
    uniapp使用H5实现预览pdf文件
    JS——日期字符串yyyymmdd转yyyy-mm-dd的两种方法
    Selenium3.0基础 — 自动化测试概述
    智慧城市的定义是什么?
    【Hack The Box】windows练习-- Silo
    thinkphp在apache、nginx和iis下的URL重写
    471-82(647、5、92、143、148、19)
  • 原文地址:https://www.cnblogs.com/renshengdezheli/p/18211540