配置Ingress支援HTTPS訪問(二):使用cert-manager申請證書

人生的哲理發表於2024-05-24

目錄
  • 一.系統環境
  • 二.前言
  • 三.Let's Encrypt和cert-manager簡介
  • 四.部署cert-manager
    • 4.1 安裝cert-manager
    • 4.2 建立clusterissuer
    • 4.3 申請域名
    • 4.4 Cloudflare新增站點
    • 4.5 修改阿里雲的名稱伺服器為cloudflare名稱伺服器
    • 4.6 獲取API Tokens
    • 4.7 建立secret儲存API token
    • 4.8 配置clusterissuer
  • 五.申請證書
  • 六.配置ingress使用證書
  • 七.客戶端訪問ingress服務
    • 7.1 Windows客戶端訪問ingress服務
    • 7.2 Linux客戶端訪問ingress服務
  • 八.配置clusterissuer自動申請證書
  • 九.沒有域名的情況下申請證書
  • 十.總結

一.系統環境

伺服器版本 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: <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: 4月 25 16:11:21 2022 GMT
* 	expire date: 7月 24 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訪問。這樣可以為我們的應用程式提供更高的安全性,保護資料傳輸的機密性和完整性。

相關文章