在 TKE 中使用動態准入控制器
原理概述
動態准入控制器 Webhook 在訪問鑑權過程中可以更改請求物件或完全拒絕該請求,其呼叫 Webhook 服務的方式使其獨立於叢集元件,具有非常大的靈活性,可以方便的做很多自定義准入控制,下圖為動態准入控制在 API 請求呼叫鏈的位置(來源於 Kubernetes 官網):
從上圖可以看出,動態准入控制過程分為兩個階段:首先執行 Mutating 階段,可以對到達請求進行修改,然後執行 Validating 階段來驗證到達的請求是否被允許,兩個階段可以單獨使用也可以組合使用,本文將在 TKE 中實現一個簡單的動態准入控制呼叫示例。
檢視驗證外掛
在 TKE 現有叢集版本中(1.10.5 及以上)已經預設開啟了 validating admission webhook 和 mutating admission webhook API,如果是更低版本的叢集,可以在 Apiserver Pod 中執行 kube-apiserver -h | grep enable-admission-plugins
驗證當前叢集是否開啟,輸出外掛列表中如果有 MutatingAdmissionWebhook
和 ValidatingAdmissionWebhook
就說明當前叢集開啟了動態准入的控制器外掛,如下圖所示:
簽發證書
為了確保動態准入控制器呼叫的是可信任的 Webhook 服務端,必須通過 HTTPS 來呼叫 Webhook 服務(TLS認證), 所以需要為 Webhook 服務端頒發證書,並且在註冊動態准入控制 Webhook 時為 caBundle
欄位( ValidatingWebhookConfiguration
和 MutatingAdmissionWebhook
資源清單中的 caBundle
欄位)繫結受信任的頒發機構證書(CA)來核驗 Webhook 服務端的證書是否可信任, 這裡分別介紹兩種推薦的頒發證書方法:
注意:當
ValidatingWebhookConfiguration
和MutatingAdmissionWebhook
使用clientConfig.service
配置時(Webhook 服務在叢集內),為伺服器端頒發的證書域名必須為<svc_name>.<svc_namespace>.svc
。
方法一: 製作自簽證書
製作自簽證書的方法比較獨立,不依賴於 K8s 叢集,類似於為一個網站做一個自簽證書,有很多工具可以製作自簽證書,本示例使用 Openssl 製作自簽證書,操作步驟如下所示:
-
生成金鑰位數為 2048 的 ca.key:
openssl genrsa -out ca.key 2048
-
依據 ca.key 生成 ca.crt,"webserver.default.svc" 為 Webhook 服務端在叢集中的域名,使用
-days
引數來設定證書有效時間:openssl req -x509 -new -nodes -key ca.key -subj "/CN=webserver.default.svc" -days 10000 -out ca.crt
-
生成金鑰位數為 2048 的 server.key:
openssl genrsa -out server.key 2048
i. 建立用於生成證書籤名請求(CSR)的配置檔案 csr.conf 示例如下:
[ req ] default_bits = 2048 prompt = no default_md = sha256 distinguished_name = dn [ dn ] C = cn ST = shaanxi L = xi'an O = default OU = websever CN = webserver.default.svc [ v3_ext ] authorityKeyIdentifier=keyid,issuer:always basicConstraints=CA:FALSE keyUsage=keyEncipherment,dataEncipherment extendedKeyUsage=serverAuth,clientAuth
-
基於配置檔案 csr.conf 生成證書籤名請求:
openssl req -new -key server.key -out server.csr -config csr.conf
-
使用 ca.key、ca.crt 和 server.csr 頒發生成伺服器證書(x509簽名):
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \ -CAcreateserial -out server.crt -days 10000 \ -extensions v3_ext -extfile csr.conf
-
檢視 Webhook server 端證書:
openssl x509 -noout -text -in ./server.crt
其中,生成的證書、金鑰檔案說明如下:
ca.crt 為頒發機構證書,ca.key 為頒發機構證書金鑰,用於服務端證書頒發。
server.crt 為 頒發的服務端證書,server.key 為頒發的服務端證書金鑰.
方法二:使用 K8S CSR API 簽發
除了使用方案一加密工具製作自簽證書,還可以使用 k8s 的證書頒發機構系統來下發證書,執行下面指令碼可使用 K8s 叢集根證書和根金鑰簽發一個可信任的證書使用者,需要注意的是使用者名稱應該為 Webhook 服務在叢集中的域名:
USERNAME='webserver.default.svc' # 設定需要建立的使用者名稱為 Webhook 服務在叢集中的域名
# 使用 Openssl 生成自簽證書 key
openssl genrsa -out ${USERNAME}.key 2048
# 使用 Openssl 生成自簽證書 CSR 檔案, CN 代表使用者名稱,O 代表組名
openssl req -new -key ${USERNAME}.key -out ${USERNAME}.csr -subj "/CN=${USERNAME}/O=${USERNAME}"
# 建立 Kubernetes 證書籤名請求(CSR)
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
name: ${USERNAME}
spec:
request: $(cat ${USERNAME}.csr | base64 | tr -d '\n')
usages:
- digital signature
- key encipherment
- server auth
EOF
# 證書審批允許信任
kubectl certificate approve ${USERNAME}
# 獲取自簽證書 CRT
kubectl get csr ${USERNAME} -o jsonpath={.status.certificate} > ${USERNAME}.crt
其中, ${USERNAME}
.crt 為服務端證書, ${USERNAME}
.key 為 Webhook 服務端證書金鑰。
操作示例
下面將使用 ValidatingWebhookConfiguration
資源在 TKE 中實現一個動態准入 Webhook 呼叫示例,本示例程式碼可在 示例程式碼 中獲取(為了確保可訪問性,示例程式碼 Fork 自 原始碼庫,作者實現了一個簡單的動態准入 Webhook 請求和響應的介面,具體介面格式請參考 Webhook 請求和響應 。為了方便,我將使用它作為我們的 Webhook 服務端程式碼。
-
準備
caBundle
內容-
若頒發證書方法是方案一, 使用
base64
編碼 ca.crt 生成caBundle
欄位內容:cat ca.crt | base64 --wrap=0
-
若頒發證書方法是方案二,叢集的根證書即為
caBundle
欄位內容,可以通過 TKE 叢集控制檯【基本資訊】-> 【叢集APIServer資訊】Kubeconfig 內容中的clusters.cluster[].certificate-authority-data
欄位獲取,該欄位已經base64
編碼過了,無需再做處理。
-
-
複製生成的 ca.crt (頒發機構證書),server.crt(HTTPS 證書)), server.key(HTTPS 金鑰) 到專案主目錄:
-
修改專案中的 Dockerfile ,新增三個證書檔案到容器工作目錄:
然後使用 docker 命令構建 Webhook 服務端映象:
docker build -t webserver .
-
部署一個域名為 "weserver.default.svc" 的 Webhook 後端服務,修改適配後的 controller.yaml 如下:
-
註冊建立型別為
ValidatingWebhookConfiguration
的資源,本示例配置的 Webhook 觸發規則是當建立pods
型別,API 版本 "v1" 時觸發呼叫,clientConfig
配置對應上述在叢集中建立的的 Webhook 後端服務,caBundle
欄位內容為證書頒發方法一獲取的ca.crt 內容,修改適配專案中的 admission.yaml 檔案如下圖: -
註冊好後建立一個 Pod 型別, API 版本為 "v1" 的測試資源如下:
-
測試程式碼有列印請求日誌, 檢視 Webhook 服務端日誌可以看到動態准入控制器觸發了 webhook 呼叫,如下圖:
-
此時檢視建立的測試pod 是成功建立的,是因為測試 Webhook 服務端程式碼寫死的
allowed: true
,所以是可以建立成功的,如下圖:
-
為了進一步驗證,我們把 "allowed" 改成 "false" ,然後重複上述步驟重新打 Webserver 服務端映象,並重新部署 controller.yaml 和 admission.yaml 資源,當再次嘗試建立 "pods" 資源時請求被動態准入攔截,說明配置的動態准入策略是生效的,如下圖所示:
總結
本文主要介紹了動態准入控制器 Webhook 的概念和作用、如何在 TKE 叢集中籤發動態准入控制器所需的證書,並使用簡單示例演示如何配置和使用動態准入 Webhook 功能。
參考
Kubernetes Dynamic Admission Control by Example
【騰訊雲原生】雲說新品、雲研新術、雲遊新活、雲賞資訊,掃碼關注同名公眾號,及時獲取更多幹貨!!