作者 主題: K8S 之 Cert-Manager 建置  (閱讀 5030 次)

0 會員 與 1 訪客 正在閱讀本文。

netman

  • 管理員
  • 俺是博士!
  • *****
  • 文章數: 17484
    • 檢視個人資料
    • http://www.study-area.org
K8S 之 Cert-Manager 建置
« 於: 2020-03-16 22:05 »
K8S 之 Cert-Manager 建置
netman <netman@study-area.org>
2020.03

一,前言
當 K8S 玩到一個階段的時候,自然會遇到 cert-manager 的需求。別問我爲什麼,反正有很多機會遇到就是了。然而,很多朋友都跟我一樣發現 cert-manager 似乎沒那麼好上手。因爲還需要扯上一些基本的 PKI 概念,但這裏先不展開 certificate 相關的基礎了,有興趣的朋友可以另外學習。

此外,這裏也不對 cert-manager 的基本概念多做闡述,請大家到官網瞭解吧:
   https://cert-manager.io/docs/

本篇的要旨主要是以實作的方式來示範 k8s 上的 cert-manager 建置過程。因爲 cert-manager 也有不同的方式搭建,這裏也只就本人偏好的其中一種來示範而已。

二,先讓我們 Let's Encrypt 吧!
基本上,k8s 的 cert-manager 可以使用不同的憑證來源發佈憑證,例如 Let’s Encrypt、HashiCorp Vault、Venafi,甚至是簡單的金鑰組或自簽憑證。爲求實用性,這裏就以當今最熱門且又是免費的 Let's Encrypt 來做示範。

Let's Encrypt 本身就是一個憑證發行機構(CA),主要透過 ACME 協定來確認 domain 擁有者身份並進行憑證的後續處理任務。其配置方式也有很多種,例如使用 Certbot 或是透過網站空間服務商內建支援等等。不過,這篇的目的是用 k8s 的 cert-manager 來處理憑證問題,所以一開始我們只需要一種簡單的方式來驗證 Let's Encrypt 是否成功即可。這裏,我選擇了acme.sh 這隻純 shell 的腳本來幫忙驗證。

Let's Encrypt 一般是透過連線您的 web server 來驗證身份,但這方式必須要提供一個可供外部連線的網站服務。有時對於純內部的使用環境來說卻是一件麻煩的事情。但 Let's Encrypt 也同時提供另外一種驗證方式,就是透過 DNS 查詢來確定您的合法性。

目前有不少主流 DNS 服務商都有提供 Let's Encrypt 的支援,例如 CloudFlare,允許我們透過 API 的方式修改 DNS Record 從而通過 Let's Encrypt 的驗證。這裏,我將使用 CloudFlare 作爲 Let's Encrypt 的 DNS 驗證。

2.1 取得 CloudFlare API Token
首先,請登入 ClouldFlare 的 dashbord,然後從右上角的 My Profile 那邊選擇 API Tokens:


然後按下 Create Token 按鈕,根據自己喜好輸入 Token Name,將 Permissions 設定如下:
  • Zone, Zone, Read
  • Zone, DNS, Edit


然後按 Continue to summary,確認權限後再按 Create Token ,最後跳出的視窗會列出 Token 的內容,請 Copy 下來保存。(網頁也有顯示測試 token 的方法,不妨也複製下來測試驗證。)

此外還有一件事情:您必須確定 CloudFlare 帳號中所留的 Email 已經完成驗證。

2.2 使用 acme.sh
操作者不一定需要 root 的權限(有則更好),直接線上安裝就行:
curl https://get.acme.sh | sh

然後登出再重新登入即可操作 acme.sh 。

首先,將 CloudFlare 那邊的 API Token 與 Email 設定爲環境變數:
export CF_Token="1txxxxqP-xxxxxxxxxxxxxxTp5JIxxxxxnf"
export CF_Email="xxx@xxxx.xxxx.com"

我這裏打算建立 wildcard 憑證,所以直接輸入如下命令:
acme.sh --issue -d k8slab.exmaple.com  -d '*.k8slab.example.com'  --dns dns_cf
(注意:example.com 只是個舉例,請修改爲真正的 domain 名稱。)

如果沒有 error,最終會生出如下內容:
Your cert
Your cert key
The intermediate CA cert
The full chain certs

日後要 renew 憑證的話,只需執行如下命令即可:
acme.sh --renew --force -d k8slab.exmaple.com  -d '*.k8slab.example.com'  --dns dns_cf

當 acme.sh 測試成功之後,然後我們再轉移到 k8s 中設定 cert-manager 。

三,在 K8S 配置 cert-manager
在 cert-manager 的官網文件(https://cert-manager.io/docs/)中我們可以獲得很多配置資訊。然而,關於 ACME 底下的 CloudFlare 部份卻沒有很完整的範例。建議交叉參考網路上其他文章來獲得適當的設定。下面的過程我會將建置流程中特別需要注意的地方強調出來,減少大家的試誤時間。

3.1 安裝 cert-manager
基本上按照官網的 Installation 就可以了,以下是我整理的步驟:
mkdir cert-manager
cd cert-manager
kubectl create namespace cert-manager
wget https://github.com/jetstack/cert-manager/releases/download/v0.13.1/cert-manager.yaml
kubectl apply -f cert-manager.yaml
kubectl get pods --namespace cert-manager

最後的驗證結果請確定所有的 pod 都處於 Running 狀態:


其中要留意的地方是 cert-manager-webhook 需要比較久一些時間才能從 ContainerCreating 變成 Running 狀態,請耐心等候就是了。

3.2 配置 secret
接下來,我們要將 CloudFlare 的 API Token 以 secret 的方式進行配置。請建立一份 secret.yaml:
代碼: [選擇]
apiVersion: v1
kind: Secret
metadata:
  name: cloudflare-api-token-secret
  namespace: cert-manager
type: Opaque
stringData:
  api-token: 1txxxxqP-xxxxxxxxxxxxxxTp5JIxxxxxnf

這裏要特別留意的地方在於 namespace :如果採用 Issuer 而非 ClusterIssuer 的話,就不需要設定。但我這裏要示範的 issuer 是用 ClusterIssuer,因此必需要將 namespace 設定爲 cert-namager,也就與 cert-manager pod 相同的 namespace 就是了。如果這裏設定不對的話,在產生 Challenge 的時候,會遇到找不到 secret 的錯誤。這個細節花了我相當多的時間才搞懂,希望可以節省大家寶貴的時間!

3.3 配置 ClusterIssue
在 K8S 的 cert-manager 中,可以使用的 issuer 有兩種:
Issuer: 只能讓相同 namespace 裏面的憑證使用
ClusterIssuer: 不分 namespace,整個 cluster 內的憑證都可以使用

由於 ClusterIssuer 的通用性比較高,因此我採用這一方式來發行後續的憑證。這裏請建立一份 cluster-issuer.yaml:
代碼: [選擇]
apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
  name: k8slab-issuer
  namespace: cert-manager
spec:
  acme:
    server: https://acme-staging-v02.api.letsencrypt.org/directory
    privateKeySecretRef:
      name: cert-k8slab
    solvers:
    - dns01:
        cloudflare:
          email: xxx@xxxx.xxxx.com
          apiTokenSecretRef:
            name: cloudflare-api-token-secret
            key: api-token

與 secret 一樣,因爲 ClusterIssuer 的關係,這裏也是要設定 namespace。另外一個要注意的地方是 email 要與 CloudFlare 驗證的郵件信箱一致。而 apiTokenSecretRef 所用的 name 必須與  secret 的名字一致才行。

3.4 配置 Certificate
這裏是最後要設定的憑證了,請建立一份 cert.yaml :
代碼: [選擇]
apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: k8slab-cert
  namespace: default
spec:
  secretName: k8slab-cert-tls
  issuerRef:
    name: k8slab-issuer
    kind: ClusterIssuer
  commonName: '*.k8slab.example.com'
  dnsNames:
  - k8slab.example.com
  - "*.k8slab.example.com"

請留意 spec 底下的 secretName 並不是指前面建立的 secret 名稱,而是給憑證暫用的參考名稱而已,因此兩個名字是不一樣的。這裏只需要確定 issuerRef 的正確性就好。因爲我要配置通配型(wildcard)憑證,因此我的 dnsName有兩個:一個帶星號(*)、另一個沒有。

3.5 套用配置
當上述三個 yaml 檔案配置完成後,接下來當熱就是套用並測試了:
kubectl apply -f secret.yaml
kubectl apply -f cluster-issuer.yaml
kubectl apply -f cert.yaml

如果 yaml 沒有打錯字的話,一般來說上面的資源都會順利 created 。稍等幾分鍾(我建議等個3分鐘左右),然後就可以驗證憑證是否有配置成功:
kubectl describe Certificate

如果最後看的 Status 顯示爲 Ready/True 的話:


恭喜您!您的 Cert-Manager 已經配置成功了!

3.6 除錯
有實務經營的朋友通常都會發現事情一般來說都不會那麼順利的!

那麼,當有問題時要如何除錯呢?這才是重點中的重點啊。假如我們套用 yaml 之後發現憑證狀態一直都卡在 InProgress 的狀態:


以根據上面的 Message 可得到 Waiting 的對象是 CertificateRequest,並且 Events 中也看到 CertificateRequest 被創建出來了,那麼接下來我們就可以查詢 CertificateRequest:
kubectl describe CertificateRequest

然後,我們或許會看到如下的訊息:


從上面的訊息中,我們又發現 Order 被創建出來並且在等待中,因此我們就接下來查詢 Order 就是了:
kubectl describe Order

從結果中我們可以看到:


其中有兩個 Challenge 被創建出來,於是我們就繼續查 Challenge:
kubectl describe Challenge

仔細檢查裏面的資訊,可能會發現類似這樣的內容:


這裏很明顯看到錯誤原因是 secret "cloudflare-api-token-secret" not found 嘛!我就是根據這個資訊去 google 才發現是 namespace 的問題!

如果 Challenge 沒問題的話,一般我們會看到這樣的資訊:


而另外一個 Challenge 則顯示爲 Waiting for dns-01 challenge propagation 的狀態... 這時候只需要耐心等候幾分鍾就好。最後會從 Order 中看到 successfully 的結果:


從 CertificateRequest 的查詢結果也會看到成功才對:


四,結語
希望以上的分享能夠幫助大家順利完成 K8S 的 cert-manager 建置。遇到問題時,請多看官方的文件,按部就班設定一般都能成功的。請記住 google 大神永遠都在,有拜有包庇哦!

--- END ---