0 專輯概述
etcd 是雲原生架構中重要的基礎組件,由 CNCF 孵化托管。etcd 在微服務和 Kubernates 集群中不僅可以作為服務注冊與發現,還可以作為 key-value 存儲的中間件。
《徹底搞懂 etcd 系列文章》將會從 etcd 的基本功能實踐、API 接口、實現原理、源碼分析,以及實現中的踩坑經驗等幾方面具體展開介紹 etcd。預計會有 20 篇左右的文章,筆者將會每周持續更新,歡迎關注。
1 etcd 安全
在上一篇文章介紹了 etcd 集群的運維部署之后,本文將會重點講解 etcd 的安全通信實踐。 etcd 支持通過 TLS 協議進行的加密通信。TLS 通道可用於對等體之間的加密內部群集通信以及加密的客戶端流量。本文提供了使用對等和客戶端 TLS 設置群集的示例。
2 TLS 與 SSL
互聯網的通信安全,建立在 SSL/TLS 協議之上。不使用 SSL/TLS 的 HTTP 通信,就是不加密的通信。所有信息明文傳播,帶來了三大風險:
- 竊聽風險(eavesdropping):第三方可以獲知通信內容。
- 篡改風險(tampering):第三方可以修改通信內容。
- 冒充風險(pretending):第三方可以冒充他人身份參與通信。
SSL/TLS 協議是為了解決這三大風險而設計的,希望達到:
- 所有信息都是加密傳播,第三方無法竊聽。
- 具有校驗機制,一旦被篡改,通信雙方會立刻發現。
- 配備身份證書,防止身份被冒充。
下面具體介紹下 SSL 與 TLS 的相關概念:
- SSL (Secure Socket Layer):為Netscape所研發,用以保障在Internet上數據傳輸之安全,利用數據加密(Encryption)技術,可確保數據在網絡上之傳輸過程中不會被截取。目前一般通用之規格為40 bit之安全標准,美國則已推出128 bit之更高安全標准,但限制出境。只要3.0版本以上之I.E.或Netscape瀏覽器即可支持SSL。
- 安全傳輸層協議(TLS)用於在兩個通信應用程序之間提供保密性和數據完整性。該協議由兩層組成: TLS 記錄協議(TLS Record)和 TLS 握手協議(TLS Handshake)。較低的層為 TLS 記錄協議,位於某個可靠的傳輸協議(例如 TCP)上面。
想要實現數據 HTTPS 加密協議訪問,保障數據的安全,就需要 SSL 證書,TLS 是 SSL 與 HTTPS 安全傳輸層協議名稱。
3 進行 TLS 加密實踐
為了進行實踐,我們將會安裝一些實用的命令行工具,其中包括 cfssl、cfssljson。
cfssl 是 CloudFlare 的 PKI/TLS 利器。 它既是命令行工具,又可以用於簽名,驗證和捆綁 TLS 證書的 HTTP API 服務器,環境構建方面需要 Go 1.12+。
cfssljson 程序,從 cfssl 獲取 JSON 輸出,並將證書、密鑰、CSR和 bundle 寫入指定位置。
環境配置
HostName | ip | 客戶端交互端口 | peer 通信端口
:-: | :-: | :-: | :-:
infra0 | 192.168.202.128 | 2379 | 2380 |
infra1 | 192.168.202.129 | 2379 | 2380 |
infra2 | 192.168.202.130| 2379 | 2380 |
3.1 安裝 cfssl
$ ls ~/Downloads/cfssl
cfssl-certinfo_1.4.1_linux_amd64 cfssl_1.4.1_linux_amd64 cfssljson_1.4.1_linux_amd64
chmod +x cfssl_1.4.1_linux_amd64 cfssljson_1.4.1_linux_amd64 cfssl-certinfo_1.4.1_linux_amd64
mv cfssl_1.4.1_linux_amd64 /usr/local/bin/cfssl
mv cfssljson_1.4.1_linux_amd64 /usr/local/bin/cfssljson
mv cfssl-certinfo_1.4.1_linux_amd64 /usr/bin/cfssl-certinfo
安裝完成之后,查看版本信息的結果:
$ cfssl version
Version: 1.4.1
Runtime: go1.12.12
3.2 配置 CA 並創建 TLS 證書
我們將使用 CloudFlare's PKI 工具 cfssl 來配置 PKI Infrastructure,然后使用它去創建 Certificate Authority(CA), 並為 etcd 創建 TLS 證書。
首先創建 ssl 配置目錄:
mkdir /opt/etcd/{bin,cfg,ssl} -p
cd /opt/etcd/ssl/
etcd ca 配置:
cat << EOF | tee ca-config.json
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"etcd": {
"expiry": "87600h",
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
]
}
}
}
}
EOF
etcd ca證書:
cat << EOF | tee ca-csr.json
{
"CN": "etcd CA",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Shanghai",
"ST": "Shanghai"
}
]
}
EOF
生成 CA 憑證和私鑰:
$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2020/04/30 20:36:58 [INFO] generating a new CA key and certificate from CSR
2020/04/30 20:36:58 [INFO] generate received request
2020/04/30 20:36:58 [INFO] received CSR
2020/04/30 20:36:58 [INFO] generating key: rsa-2048
2020/04/30 20:36:58 [INFO] encoded CSR
2020/04/30 20:36:58 [INFO] signed certificate with serial number 252821789025044258332210471232130931231440888312
$ ls
ca-config.json ca-csr.json ca-key.pem ca.csr ca.pem
etcd server證書:
cat << EOF | tee server-csr.json
{
"CN": "etcd",
"hosts": [
"192.168.202.128",
"192.168.202.129",
"192.168.202.130"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"L": "Beijing",
"ST": "Beijing"
}
]
}
EOF
生成 server 證書:
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd server-csr.json | cfssljson -bare server
2020/04/30 20:44:37 [INFO] generate received request
2020/04/30 20:44:37 [INFO] received CSR
2020/04/30 20:44:37 [INFO] generating key: rsa-2048
2020/04/30 20:44:37 [INFO] encoded CSR
2020/04/30 20:44:37 [INFO] signed certificate with serial number 73061688633166283265484923779818839258466531108
ls
ca-config.json ca-csr.json ca-key.pem ca.csr ca.pem server-csr.json server-key.pem server.csr server.pem
啟動 etcd 集群,配置如下:
#etcd1 啟動
$ /opt/etcd/bin/etcd --name etcd1 --initial-advertise-peer-urls https://192.168.202.128:2380 \
--listen-peer-urls https://192.168.202.128:2380 \
--listen-client-urls https://192.168.202.128:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://192.168.202.128:2379 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster etcd1=https://192.168.202.128:2380, etcd2=https://192.168.202.129:2380, etcd3=https://192.168.202.130:2380 \
--initial-cluster-state new \
--client-cert-auth --trusted-ca-file=/opt/etcd/ssl/ca.pem \
--cert-file=/opt/etcd/ssl/server.pem --key-file=/opt/etcd/ssl/server-key.pem \
--peer-client-cert-auth --peer-trusted-ca-file=/opt/etcd/ssl/ca.pem \
--peer-cert-file=/opt/etcd/ssl/server.pem --peer-key-file=/opt/etcd/ssl/server-key.pem
#etcd2 啟動
/opt/etcd/bin/etcd --name etcd2 --initial-advertise-peer-urls https://192.168.202.129:2380 \
--listen-peer-urls https://192.168.202.129:2380 \
--listen-client-urls https://192.168.202.129:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://192.168.202.129:2379 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster etcd1=https://192.168.202.128:2380, etcd2=https://192.168.202.129:2380, etcd3=https://192.168.202.130:2380 \
--initial-cluster-state new \
--client-cert-auth --trusted-ca-file=/opt/etcd/ssl/ca.pem \
--cert-file=/opt/etcd/ssl/server.pem --key-file=/opt/etcd/ssl/server-key.pem \
--peer-client-cert-auth --peer-trusted-ca-file=/opt/etcd/ssl/ca.pem \
--peer-cert-file=/opt/etcd/ssl/server.pem --peer-key-file=/opt/etcd/ssl/server-key.pem
#etcd3 啟動
/opt/etcd/bin/etcd --name etcd3 --initial-advertise-peer-urls https://192.168.202.130:2380 \
--listen-peer-urls https://192.168.202.130:2380 \
--listen-client-urls https://192.168.202.130:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://192.168.202.130:2379 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster etcd1=https://192.168.202.128:2380, etcd2=https://192.168.202.129:2380, etcd3=https://192.168.202.130:2380 \
--initial-cluster-state new \
--client-cert-auth --trusted-ca-file=/opt/etcd/ssl/ca.pem \
--cert-file=/opt/etcd/ssl/server.pem --key-file=/opt/etcd/ssl/server-key.pem \
--peer-client-cert-auth --peer-trusted-ca-file=/opt/etcd/ssl/ca.pem \
--peer-cert-file=/opt/etcd/ssl/server.pem --peer-key-file=/opt/etcd/ssl/server-key.pem
通過三台服務器的控制台可以知道,集群已經成功建立,我們進行驗證:
$ /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.202.128:2379,https://192.168.202.129:2379,https://192.168.202.130:2379" endpoint health
# 輸出如下:
https://192.168.202.129:2379 is healthy: successfully committed proposal: took = 9.492956ms
https://192.168.202.130:2379 is healthy: successfully committed proposal: took = 12.805109ms
https://192.168.202.128:2379 is healthy: successfully committed proposal: took = 13.036091ms
查看三個節點的健康狀況,endpoint health
,輸出的結果符合我們的預期。其次,查看集群的成員列表:
$ /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.202.128:2379,https://192.168.202.129:2379,https://192.168.202.130:2379" member list
# 輸出如下:
48e15f7612b3de1, started, etcd2, https://192.168.202.129:2380, https://192.168.202.129:2379, false
6b57a3c3b8a54873, started, etcd3, https://192.168.202.130:2380, https://192.168.202.130:2379, false
c1ba2629c5bc62ac, started, etcd1, https://192.168.202.128:2380, https://192.168.202.128:2379, false
輸出三個成員,完全符合我們的預期。經過 TLS 加密的 etcd 集群,在進行操作時,需要加上認證相關的信息,我們嘗試先寫再讀的操作:
$ /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.202.128:2379,https://192.168.202.129:2379,https://192.168.202.130:2379" put hello world
OK
$ /opt/etcd/bin/etcdctl --cacert=/opt/etcd/ssl/ca.pem --cert=/opt/etcd/ssl/server.pem --key=/opt/etcd/ssl/server-key.pem --endpoints="https://192.168.202.128:2379,https://192.168.202.129:2379,https://192.168.202.130:2379" get hello
hello
world
寫入 hello->wold 的鍵值對,讀取的時候,控制台正常輸出了鍵值。至此,我們成功將 etcd 的通信加密。
3.3 自動證書
如果集群需要加密的通信但不需要經過身份驗證的連接,則可以將 etcd 配置為自動生成其密鑰。 在初始化時,每個成員都基於其通告的 IP 地址和主機創建自己的密鑰集。
在每台機器上,etcd 將使用以下標志啟動:
$ etcd --name etcd1 --initial-advertise-peer-urls https://192.168.202.128:2380 \
--listen-peer-urls https://192.168.202.128:2380 \
--listen-client-urls https://192.168.202.128:2379,https://127.0.0.1:2379 \
--advertise-client-urls https://10.0.1.10:2379 \
--initial-cluster-token etcd-cluster-1 \
--initial-cluster infra0=https://192.168.202.128:2380,infra1=https://192.168.202.129:2380,infra2=https://192.168.202.130:2380 \
--initial-cluster-state new \
--auto-tls \
--peer-auto-tls
注意,由於自動簽發證書並不認證身份,因此直接 curl 會返回錯誤。需要使用 curl 的 -k
命令屏蔽對證書鏈的校驗。
4 小結
本文重點講解了 etcd 集群的 TLS 安全認證配置,數據通信明文傳播存在篡改、竊聽、冒充等風險。互聯網的通信安全,建立在 SSL/TLS 協議之上。基於 cfssl 工具,驗證並且捆綁 TLS 證書,為 etcd 集群成員之間的通信保駕護航。
訂閱最新文章,歡迎關注我的公眾號
推薦閱讀
- etcd 與 Zookeeper、Consul 等其它 k-v 組件的對比
- 徹底搞懂 etcd 系列文章(一):初識 etcd
- 徹底搞懂 etcd 系列文章(二):etcd 的多種安裝姿勢
- 徹底搞懂 etcd 系列文章(三):etcd 集群運維部署