本文主要描述了在 Kubernetes 上如何為 TiDB 叢集的 MySQL 用戶端開啟 TLS。TiDB Operator 從 v1.1 開始已經支援為 Kubernetes 上 TiDB 叢集開啟 MySQL 用戶端 TLS。開啟步驟為:
為 TiDB Server 頒發一套 Server 端證書,為 MySQL Client 頒發一套 Client 端證書。并建立兩個 Secret 對象,Secret 名字分别為:${cluster_name}-tidb-server-secret 和 ${cluster_name}-tidb-client-secret,分别包含前面建立的兩套證書;
部署叢集,設定 .spec.tidb.tlsClient.enabled 屬性為 true;
配置 MySQL 用戶端使用加密連接配接。
其中,頒發證書的方式有多種,本文檔提供兩種方式,使用者也可以根據需要為 TiDB 叢集頒發證書,這兩種方式分别為:
使用 cfssl 系統頒發證書;
使用 cert-manager 系統頒發證書;
第一步:為 TiDB 叢集頒發兩套證書
使用 cfssl 系統頒發證書
首先下載下傳 cfssl 軟體并初始化證書頒發機構:
mkdir -p ~/bin
curl -s -L -o ~/bin/cfssl
https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 curl -s -L -o ~/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64chmod +x ~/bin/{cfssl,cfssljson}
export PATH=$PATH:~/bin
mkdir -p cfssl
cd cfssl
cfssl print-defaults config > ca-config.json
cfssl print-defaults csr > ca-csr.json
在 ca-config.json 配置檔案中配置 CA 選項:
{
"signing": {
"default": {
"expiry": "8760h"
},
"profiles": {
"server": {
"expiry": "8760h",
"usages": [
"signing",
"key encipherment",
"server auth"
]
},
"client": {
"expiry": "8760h",
"usages": [
"signing",
"key encipherment",
"client auth"
]
}
}
}
}
您還可以修改 ca-csr.json 證書簽名請求 (CSR):
"CN": "TiDB Server",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "US",
"L": "CA",
"O": "PingCAP",
"ST": "Beijing",
"OU": "TiDB"
}
]
使用定義的選項生成 CA:
cfssl gencert -initca ca-csr.json | cfssljson -bare ca -
生成 Server 端證書。
首先生成預設的 server.json 檔案:
cfssl print-defaults csr > server.json
然後編輯這個檔案,修改 CN,hosts 屬性:
...
"CN": "TiDB Server",
"hosts": [
"127.0.0.1",
"::1",
"${cluster_name}-tidb",
"${cluster_name}-tidb.${namespace}",
"${cluster_name}-tidb.${namespace}.svc",
"*.${cluster_name}-tidb",
"*.${cluster_name}-tidb.${namespace}",
"*.${cluster_name}-tidb.${namespace}.svc",
"*.${cluster_name}-tidb-peer",
"*.${cluster_name}-tidb-peer.${namespace}",
"*.${cluster_name}-tidb-peer.${namespace}.svc"
],
其中 ${cluster_name} 為叢集的名字,${namespace} 為 TiDB 叢集部署的命名空間,使用者也可以添加自定義 hosts。
最後生成 Server 端證書:
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server server.json | cfssljson -bare server
生成 Client 端證書。
首先生成預設的 client.json 檔案:
cfssl print-defaults csr > client.json
然後編輯這個檔案,修改 CN,hosts 屬性,hosts 可以留白:
"CN": "TiDB Client",
"hosts": [],
最後生成 Client 端證書:
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client.json | cfssljson -bare client
建立 Kubernetes Secret 對象。
到這裡假設你已經按照上述文檔把兩套證書都建立好了。通過下面的指令為 TiDB 叢集建立 Secret 對象:
kubectl create secret generic ${cluster_name}-tidb-server-secret --namespace=${namespace} --from-file=tls.crt=server.pem --from-file=tls.key=server-key.pem --from-file=ca.crt=ca.pem
kubectl create secret generic ${cluster_name}-tidb-client-secret --namespace=${namespace} --from-file=tls.crt=client.pem --from-file=tls.key=client-key.pem --from-file=ca.crt=ca.pem
這樣就給 Server/Client 端證書分别建立了:
一個 Secret 供 TiDB Server 啟動時加載使用;
另一個 Secret 供 MySQL 用戶端連接配接 TiDB 叢集時候使用。
使用者可以生成多套 Client 端證書,并且至少要生成一套 Client 證書供 TiDB Operator 内部元件通路 TiDB Server(目前有 TidbInitializer 會通路 TiDB Server 來設定密碼或者一些初始化操作)。
使用 cert-manager 頒發證書
安裝 cert-manager。
請參考官網安裝:cert-manager installation in Kubernetes。
建立一個 Issuer 用于給 TiDB 叢集頒發證書。
為了配置 cert-manager 頒發證書,必須先建立 Issuer 資源。
首先建立一個目錄儲存 cert-manager 建立證書所需檔案:
mkdir -p cert-manager
cd cert-manager
然後建立一個 tidb-server-issuer.yaml 檔案,輸入以下内容:
apiVersion: cert-manager.io/v1alpha2
kind: Issuer
metadata:
name: ${cluster_name}-selfsigned-ca-issuer
namespace: ${namespace}
spec:
selfSigned: {}
kind: Certificate
name: ${cluster_name}-ca
secretName: ${cluster_name}-ca-secret
commonName: "TiDB CA"
isCA: true
issuerRef:
name: ${cluster_name}-selfsigned-ca-issuer
kind: Issuer
name: ${cluster_name}-tidb-issuer
ca:
secretName: ${cluster_name}-ca-secret
上面的檔案建立三個對象:
一個 SelfSigned 類型的 Isser 對象(用于生成 CA 類型 Issuer 所需要的 CA 證書);
一個 Certificate 對象,isCa 屬性設定為 true;
一個可以用于頒發 TiDB Server TLS 證書的 Issuer。
最後執行下面的指令進行建立:
kubectl apply -f tidb-server-issuer.yaml
建立 Server 端證書。
在 cert-manager 中,Certificate 資源表示證書接口,該證書将由上面建立的 Issuer 頒發并保持更新。
首先來建立 Server 端證書,建立一個 tidb-server-cert.yaml 檔案,并輸入以下内容:
name: ${cluster_name}-tidb-server-secret
secretName: ${cluster_name}-tidb-server-secret
duration: 8760h # 365d
renewBefore: 360h # 15d
organization:
- PingCAP
commonName: "TiDB Server"
usages:
- server auth
dnsNames:
- "${cluster_name}-tidb"
- "${cluster_name}-tidb.${namespace}"
- "${cluster_name}-tidb.${namespace}.svc"
- "*.${cluster_name}-tidb"
- "*.${cluster_name}-tidb.${namespace}"
- "*.${cluster_name}-tidb.${namespace}.svc"
- "*.${cluster_name}-tidb-peer"
- "*.${cluster_name}-tidb-peer.${namespace}"
- "*.${cluster_name}-tidb-peer.${namespace}.svc"
ipAddresses:
- 127.0.0.1
- ::1
issuerRef:
name: ${cluster_name}-tidb-issuer
kind: Issuer
group: cert-manager.io
其中 ${cluster_name} 為叢集的名字:
spec.secretName 請設定為 ${cluster_name}-tidb-server-secret;
usages 請添加上 server auth;
dnsNames 需要填寫這 6 個 DNS,根據需要可以填寫其他 DNS:
${cluster_name}-tidb
${cluster_name}-tidb.${namespace}
${cluster_name}-tidb.${namespace}.svc
*.${cluster_name}-tidb
*.${cluster_name}-tidb.${namespace}
*.${cluster_name}-tidb.${namespace}.svc
*.${cluster_name}-tidb-peer
*.${cluster_name}-tidb-peer.${namespace}
*.${cluster_name}-tidb-peer.${namespace}.svc
ipAddresses 需要填寫這兩個 IP ,根據需要可以填寫其他 IP:
127.0.0.1
::1
issuerRef 請填寫上面建立的 Issuer;
其他屬性請參考 cert-manager API。
通過執行下面的指令來建立證書:
kubectl apply -f tidb-server-cert.yaml
建立這個對象以後,cert-manager 會生成一個名字為 ${cluster_name}-tidb-server-secret 的 Secret 對象供 TiDB Server 使用。
建立 Client 端證書。
建立一個 tidb-client-cert.yaml 檔案,并輸入以下内容:
name: ${cluster_name}-tidb-client-secret
secretName: ${cluster_name}-tidb-client-secret
- PingCAP
commonName: "TiDB Client"
- client auth
name: ${cluster_name}-tidb-issuer
kind: Issuer
group: cert-manager.io
spec.secretName 請設定為 ${cluster_name}-tidb-client-secret;
usages 請添加上 client auth;
dnsNames 和 ipAddresses 不需要填寫;
kubectl apply -f tidb-client-cert.yaml
建立這個對象以後,cert-manager 會生成一個名字為 ${cluster_name}-tidb-client-secret 的 Secret 對象供 TiDB Client 使用。
注意:
TiDB Server 的 TLS 相容 MySQL 協定。當
QQ靓号買賣證書内容發生改變後,需要管理者手動執行 SQL 語句 alter instance reload tls 進行重新整理。
第二步:部署 TiDB 叢集
接下來将會通過兩個 CR 對象來建立一個 TiDB 叢集,并且執行以下步驟:
開啟 MySQL 用戶端 TLS;
對叢集進行初始化(這裡建立了一個資料庫 app)。
apiVersion: pingcap.com/v1alpha1
kind: TidbCluster
name: ${cluster_name}
namespace: ${namespace}
version: v3.1.0
timezone: UTC
pvReclaimPolicy: Retain
pd:
baseImage: pingcap/pd
replicas: 1
requests:
storage: "1Gi"
config: {}
tikv:
baseImage: pingcap/tikv
storage: "1Gi"
tidb:
baseImage: pingcap/tidb
service:
type: ClusterIP
tlsClient:
enabled: true
kind: TidbInitializer
name: ${cluster_name}-init
image: tnir/mysqlclient
cluster:
namespace: ${namespace}
name: ${cluster_name}
initSql: |-
create database app;
其中 ${cluster_name} 為叢集的名字,${namespace} 為 TiDB 叢集部署的命名空間。通過設定 spec.tidb.tlsClient.enabled 屬性為 true 來開啟 MySQL 用戶端 TLS。
将上面檔案儲存為 cr.yaml,然後使用 kubectl apply -f cr.yaml 來建立 TiDB 叢集。
第三步:配置 MySQL 用戶端使用加密連接配接
可以根據官網文檔提示,使用上面建立的 Client 證書,通過下面的方法連接配接 TiDB 叢集:
擷取 Client 證書的方式并連接配接 TiDB Server 的方法是:
kubectl get secret -n ${namespace} ${cluster_name}-tidb-client-secret -ojsonpath='{.data.tls.crt}' | base64 --decode > client-tls.crt
kubectl get secret -n ${namespace} ${cluster_name}-tidb-client-secret -ojsonpath='{.data.tls.key}' | base64 --decode > client-tls.key
kubectl get secret -n ${namespace} ${cluster_name}-tidb-client-secret -ojsonpath='{.data.ca.crt}' | base64 --decode > client-ca.crt
mysql -uroot -p -P 4000 -h ${tidb_host} --ssl-cert=client-tls.crt --ssl-key=client-tls.key --ssl-ca=client-ca.crt
最後請參考 官網文檔 來驗證是否正确開啟了 TLS。