云原生技巧 :在本地 K8s 中輕松部署自簽 TLS 證書
隨著互聯(lián)網(wǎng)的飛速發(fā)展,安全性日益成為我們關(guān)注的焦點。HTTPS 已從一項奢侈的技術(shù)逐漸成為現(xiàn)代網(wǎng)絡交互的標準。它不僅僅是保護信息的重要工具,更是實現(xiàn)信任和品質(zhì)的象征???。當你在本地的 K8s 開發(fā)環(huán)境中遇到需要使用 HTTPS 來進行訪問,又該如何為其配置 TLS/SSL 證書呢?
今天,讓我們一起揭秘如何在 K8s 環(huán)境中輕松自簽證書,為你的本地開發(fā)環(huán)境帶來安全性的提升!
一、Preparation
1. Install Kind
在生成 Kind 的配置文件時,我利用 Kind 的 extraPortMapping 配置選項將端口從主機轉(zhuǎn)發(fā)到節(jié)點上運行的入口控制器。
它的作用是允許本地主機通過端口 80/443 向 Ingress 控制器發(fā)出請求。
cat << EOF > cluster.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: local
nodes:
- role: control-plane
image: kindest/node:v1.25.3
extraPortMappings:
- containerPort: 80
hostPort: 80
listenAddress: 127.0.0.1
- containerPort: 443
hostPort: 443
listenAddress: 127.0.0.1
EOF
使用生成的配置,在本地安裝 K8s 集群。
kind create cluster --config cluster.yaml
?? 因為配置了 extraPortMappings 的原因,如果需要在本地部署多套 K8s 集群,必須調(diào)整端口,又或者是去除 extraPortMappings 這個配置項。
2. Install Traefik
將 Traefik Labs 的圖表倉庫添加到 Helm。
helm repo add traefik https://traefik.github.io/charts
helm repo update
這里我們給 websecure 設置主機端口為 443,這是為了確保傳入的 HTTPS 流量可以被正確地路由到 Traefik。
helm upgrade -i traefik \
--set ports.traefik.expose=true \
--set ports.websecure.hostPort=443 \
--set-string service.type=ClusterIP \
--namespace traefik \
--create-namespace \
traefik/traefik
3. Install Dnsmasq
雖然 /etc/hosts 對于簡單的域名到 IP 地址的映射是很有用的,但它是靜態(tài)的,而且不支持通配符或模式匹配,因此你不能為一個域名的所有子域設置相同的 IP 地址。
Dnsmasq[1] 它是一個輕量級的 DNS 正向和反向緩存服務器,同時也可以為 DHCP 功能提供服務。它被設計為易于配置和使用,并且它通常用于小型網(wǎng)絡環(huán)境,特別是那些需要簡單的 DHCP 和 DNS 服務的地方。
可以說 Dnsmasq 提供了一個更強大、靈活且集中的解決方案,以下是安裝方法。
brew install dnsmasq
4. Install CFSSL/mkcert
為本地生成自簽名的 SSL/TLS 證書有很多的工具,我在這里就分享兩種,每種工具都有其特點和最佳用途,大家可以根據(jù)自己的需求和偏好來選擇。
第一種:CFSSL[2],以下是安裝方法。
brew install cfssl
第二種:mkcert[3],以下是安裝方法。
brew install mkcert
小結(jié)
至此,我們已經(jīng)完成了在本地 K8s 開發(fā)環(huán)境中準備的基礎(chǔ)設施工作。通過 Kind,我們成功地搭建了一個本地的 Kubernetes 集群;通過 Helm 和 Traefik,我們?yōu)榧号渲昧藦姶蟮穆酚珊头聪虼砉δ?;最后,通過 Dnsmasq,我們提供了一個靈活的本地 DNS 解決方案,替代了傳統(tǒng)的 /etc/hosts 方法。這些都為我們接下來進行 TLS/SSL 證書配置打下了堅實的基礎(chǔ)。
現(xiàn)在,我們將進入下一個階段,真正探討如何在 K8s 開發(fā)環(huán)境中配置自簽證書,以實現(xiàn) HTTPS 的安全訪問。帶上你的好奇心,和我一起探索這片云原生的奧秘之地!??
二、 創(chuàng)建自簽名證書
首先,我們得創(chuàng)造一個自簽證書。這里,我選擇使用 CFSSL 來完成這一流程。
初始化配置
輕輕敲入以下命令,生成一個閃亮的配置文件 config.json?
cfssl print-defaults config > config.json
配置內(nèi)容,我們可以根據(jù)自己的需求稍作調(diào)整
{
"signing": {
"default": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
生成證書
將以下內(nèi)容寫入到 create-selfsign-cert.sh 腳本
#!/usr/bin/env bash
cn=$1
if [[ -z "$cn" ]]; then
read -p "Common name: " cn
fi
extfile=$(mktemp)
cat >"$extfile" <<INNER_EOF
{
"CN": "$cn",
"hosts": [
"$cn"
],
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "CN",
"L": "Shanghai",
"O": "BaseBit",
"OU": "XDP",
"ST": "Shanghai"
}
]
}
INNER_EOF
function finish {
rm "$extfile"
}
trap finish EXIT
cfssl selfsign -config=config.json selfsign "$extfile" | cfssljson -bare "$cn"
mv ${cn}-key.pem ${cn}.key
mv ${cn}.pem ${cn}.crt
接著,執(zhí)行以下命令生成泛域名證書:
$(pwd)/create-selfsign-cert.sh "*.kind.cluster"
?? 小貼士:執(zhí)行后,以下三個文件將被創(chuàng)建:
? ls |grep kind
*.kind.cluster.crt # 自簽名證書
*.kind.cluster.csr # 證書簽名請求(CSR)文件
*.kind.cluster.key # 私鑰文件
關(guān)于 CFSSL 的更多魔法 ??,請前往官網(wǎng)自行探索!
三、創(chuàng)建 Kubernetes TLS Secret
接下來,我們將自簽名證書和私鑰存儲在 Kubernetes 中作為 TLS Secret:
# 創(chuàng)建一個 TLS Secret
kubectl create secret tls tls-secret \
--key *.kind.cluster.key \
--cert *.kind.cluster.crt
四、 配置 Kubernetes Ingress 使用 TLS Secret
Nice,現(xiàn)在準備工作都完成啦 ??,接下來,讓我們召喚一個服務,試試效果吧!
# 創(chuàng)建一個 Nginx Deployment
kubectl create deployment nginx-deployment --image=nginx:1.25.3
# 暴露 Deployment 作為一個 Service
kubectl expose deployment nginx-deployment --port=80
我們引用 TLS Secret 在 K8s Ingress 資源中啟用 HTTPS,對應域名為 nginx.kind.cluster
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx
spec:
tls: # 以下 4 行是為了支持 TLS
- hosts: #
- nginx.kind.cluster #
secretName: tls-secret #
rules:
- host: nginx.kind.cluster
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-deployment
port:
number: 80
EOF
五、配置 Dnsmasq
因為我們的域名是自定義的,所以還需要在本地畫上一道符咒。
將以下信息添加到 Dnsmasq 配置中,它可以從本地 IP 提供通配符[子]域。
echo 'address=/kind.cluster/127.0.0.1' >> $(brew --prefix)/etc/dnsmasq.conf
正如上面提到的,我將 Kind 集群內(nèi)的端口映射到了主機上,所以這里只需配置 127.0.0.1 就好,不用再配置集群 host 的實際 IP。Dnsmasq 也會嘗試解析子域名記錄,例如 foo.kind.cluster 、 bar.kind.cluster ,這非常的方便。
配置完成,使用 brew 來重啟 Dnsmasq
sudo brew services restart dnsmasq
我們再為 .kind.cluster 結(jié)尾的域名配置了一個專用的 DNS 解析器。
cat <<EOF | sudo tee /etc/resolver/kind.cluster
nameserver 127.0.0.1
EOF
最后,使用 dig 命令確認域名解析正確指向了 127.0.0.1:
? dig kind.cluster @127.0.0.1
; <<>> DiG 9.10.6 <<>> kind.cluster @127.0.0.1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 54402
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;kind.cluster. IN A
;; ANSWER SECTION:
kind.cluster. 0 IN A 127.0.0.1
;; Query time: 4 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Oct 29 07:31:11 CST 2023
;; MSG SIZE rcvd: 57
?? 下面我們來做個驗證吧。
圖片
六、信任自簽名證書
使用自簽名證書的缺點是,當用戶訪問通過此 Ingress 暴露的服務時,瀏覽器會顯示一個警告,因為該證書不是由受信任的證書頒發(fā)機構(gòu)頒發(fā)的,怎么解決呢?
其實很簡單,在你的計算機上,將這個自簽名證書添加到受信任的根證書存儲中,這樣你的瀏覽器就不會每次警告你連接不安全。
下面我們以 macOS 舉例
步驟 1: 雙擊 .crt 文件,這會打開“鑰匙串訪問”應用。在“鑰匙串訪問”中,你會看到證書已經(jīng)被導入。如果沒看到,你也可以手動拖拽.crt 文件到“鑰匙串訪問”窗口中。
步驟 2: 然后右鍵點擊你導入的證書,選擇“獲取信息”
圖片
步驟 3: 展開“信任”部分,在“使用此證書時”選擇“始終信任”
圖片
步驟 4: 最后,讓我們再來做下驗證 ??
圖片
我們也可以通過 CURL 來驗證,它也不再報任何的錯誤,效果如下所示
? curl -v https://nginx.kind.cluster
* Trying 127.0.0.1:443...
* Connected to nginx.kind.cluster (127.0.0.1) port 443 (#0)
* ALPN: offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (IN), TLS handshake, Server hello (2):
* (304) (IN), TLS handshake, Unknown (8):
* (304) (IN), TLS handshake, Certificate (11):
* (304) (IN), TLS handshake, CERT verify (15):
* (304) (IN), TLS handshake, Finished (20):
* (304) (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / AEAD-AES128-GCM-SHA256
* ALPN: server accepted h2
* Server certificate:
* subject: C=CN; ST=Shanghai; L=Shanghai; O=BaseBit; OU=XDP; CN=*.kind.cluster
* start date: Oct 29 13:54:45 2023 GMT
* expire date: Oct 29 13:59:45 2033 GMT
* subjectAltName: host "nginx.kind.cluster" matched cert's "*.kind.cluster"
* issuer: C=CN; ST=Shanghai; L=Shanghai; O=BaseBit; OU=XDP; CN=*.kind.cluster
* SSL certificate verify ok.
* using HTTP/2
...
< HTTP/2 200
...
通過以上步驟,我們的本地開發(fā)環(huán)境將能夠信任并正確使用自簽名證書。
但還有一種更簡單的替代方案 — mkcert,它可以幫助你在本地開發(fā)環(huán)境直接創(chuàng)建受信任的證書,不需要繁瑣的配置,大大簡化了本地環(huán)境配置
mkcert -install
mkcert '*.kind.cluster'
大家不妨試下,這玩意完全可以替代 CFSSL,它對于本地開發(fā)和測試來說是足夠的。
寫在后面
在這篇文章中,我們采用了相對傳統(tǒng)的方法來創(chuàng)建自簽證書,可能對某些場景來說并不算是真正的“云原生”。在接下來的文章中,我會為大家?guī)?nbsp;Cert-Manager[4] 的詳細介紹,它是一種真正云原生的自簽證書方法,可以自動化證書的請求和續(xù)訂,旨在更好地融合并適應現(xiàn)代的 Kubernetes 生態(tài)系統(tǒng)。??
參考資料
[1]Dnsmasq: https://en.wikipedia.org/wiki/Dnsmasq
[2]CFSSL: https://github.com/cloudflare/cfssl
[3]mkcert: https://github.com/FiloSottile/mkcert
[4]Cert-Manager: https://cert-manager.io/