# TLS > - **Objective:** Configure TLS in a TiDB Cluster > - **Prerequisites:** > - background knowledge of TiDB components > - AWS account > - **Optionality:** Optional > - **Estimated time:** TBD ## TLS Support in TiDB TiDB Operator 1.1.0 supports Transport Layer Security (TLS) between cluster components and between client and the cluster. This document describes how to enable TLS in TiDB including: - TLS between cluster components. - TLS between MySQL client and TiDB cluster. This document is organized as the follows, we first create secrets in Kubenetes and if the certificates is not already in Kubernetes. Note that this document assumes the following TiDB cluster name and namespace are used. Please make necessary changes to match the cluster name and namespace of the TiDB cluster. ``` $ export cluster_name=basic $ export namespace=demo ``` ## Issue Certificates We need to generate certificates for inter and intra component communication. In summary, we need to generate the following certificates: - PD Server certificate for communicating between PD instances. - TiKV Server certificate for communicating between TiKV instances. - TiDB Server certificate for communicating between MySQL client and TiDB Cluster. - Client certificate for communicating between components and between MySQL client and TiDB Cluster. TLS certificates can be issued by multiple methods. Please consult your organization on how you can obtain them. For testing purposes, you can follow the steps in [Issue TLS Certificates Using cfssl](https://hackmd.io/gL-13LYlTA2vPRzzMrA22w?both) to issue and verify certificates. ## TLS Configuration There are two configurations to enable TLS. To enable TLS between clusters, set `spec.tlsCluster.enabled` to `true`. To enable TLS between MySQL client and TiDB cluster, set `spect.tidb.tlsClient.enabled` to `true`. To enable mutual TLS, for each compoment, we need to config the `config.security.cert-allowed-cn`. **Note that as the configuration `cert-allowed-cn` is stored PD, we can only set one value. This means that when generating the certificates for cluster components, we need to make sure that the CN field is correctly set and is the same between different certificates. This can be verified by using the openssl tool.** ### Enable TLS #### Deploy a TiDB Cluster with TLS enabled One example configuration for TiDB cluster with TLS enabled is as follows: ``` apiVersion: pingcap.com/v1alpha1 kind: TidbCluster metadata: name: basic spec: tlsCluster: enabled: true version: v4.0.0-rc timezone: UTC pvReclaimPolicy: Delete pd: baseImage: pingcap/pd replicas: 1 requests: storage: "1Gi" config: security: cert-allowed-cn: - TiDB tikv: baseImage: pingcap/tikv replicas: 1 requests: storage: "1Gi" config: security: cert-allowed-cn: - TiDB tidb: baseImage: pingcap/tidb replicas: 1 service: type: ClusterIP tlsClient: enabled: true config: security: cert-allowed-cn: - TiDB ``` **Note that the value `spec.pd.config.security.cert-allowed-cn`,`spec.tikv.config.security.cert-allowed-cn` and `spec.tikv.config.security.cert-allowed-cn` needs to be the same and match the CN field in the corresponding certificates.** Assuming that the yaml file is stored in the following path (TODO: put the configuration file in the tidb operator repo). Please also set the environment variable to point to the path of the configuration. Deploy a TiDB cluster with TLS enabled: ``` $ kubectl apply -f ${tidb_cluster_conf} -n ${namespace} ``` #### Enable TLS on an Existing TiDB Cluster We can edit the TiDB cluster configuration to enable TLS configuraitons using the following command: ``` $ kubectl edit tc ${cluster_name} -n ${namespace} ``` After the prompt, peforming the following changes: - Set `spec.tlsCluster.enabled` to `true`. - Set `spec.pd.config.security.cert-allowed-cn`, `spec.tikv.config.security.cert-allowed-cn` and `spec.tikv.config.security.cert-allowed-cn` to be the same and match the CN field in the corresponding certificates. - Set `spect.tidb.tlsClient.enabled` to `true`. After the saving the configuration, if there's no issues, TiDB Operator will perform a rolling restart of the TiDB cluster and apply the configuration changes. ### Verify Cluster is Successfully Deployed ``` $ kubectl get po -n ${namespace} NAME READY STATUS RESTARTS AGE basic-discovery-69879c5b85-jvz2f 1/1 Running 0 103s basic-pd-0 1/1 Running 0 103s basic-tidb-0 1/2 Running 0 22s basic-tikv-0 1/1 Running 0 82s ``` ``` $ kubectl get svc -n ${namespace} NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE basic-discovery ClusterIP 10.101.136.222 <none> 10261/TCP 2m33s basic-pd ClusterIP 10.100.120.45 <none> 2379/TCP 2m33s basic-pd-peer ClusterIP None <none> 2380/TCP 2m33s basic-tidb ClusterIP 10.102.77.101 <none> 4000/TCP,10080/TCP 72s basic-tidb-peer ClusterIP None <none> 10080/TCP 72s basic-tikv-peer ClusterIP None <none> 20160/TCP 2m12s ``` ``` $ kubectl logs ${cluster_name}-pd-0 -n ${namespace} [2020/04/29 00:46:13.045 +00:00] [INFO] [etcd.go:576] ["serving peer traffic"] [address="[::]:2380"] [2020/04/29 00:46:13.045 +00:00] [INFO] [etcd.go:241] ["now serving peer/client/metrics"] [local-member-id=5d5d47e6e68a829f] [initial-advertise-peer-urls="[https://basic-pd-0.basic-pd-peer.demo.svc:2380]"] [listen-peer-urls="[https://0.0.0.0:2380]"] [advertise-client-urls="[https://basic-pd-0.basic-pd-peer.demo.svc:2379]"] [listen-client-urls="[https://0.0.0.0:2379]"] [listen-metrics-urls="[]"] ``` ``` $ kubectl logs ${cluster_name}-tikv-0 -n ${namespace} [2020/04/29 00:46:42.230 +00:00] [INFO] [mod.rs:335] ["starting working thread"] [worker=addr-resolver] [2020/04/29 00:46:42.230 +00:00] [INFO] [mod.rs:335] ["starting working thread"] [worker=region-collector-worker] [2020/04/29 00:46:46.912 +00:00] [INFO] [future.rs:136] ["starting working thread"] [worker=gc-worker] [2020/04/29 00:46:46.912 +00:00] [INFO] [mod.rs:335] ["starting working thread"] [worker=lock-collector] [2020/04/29 00:46:46.945 +00:00] [INFO] [mod.rs:181] ["Storage started."] [2020/04/29 00:46:46.948 +00:00] [INFO] [mod.rs:335] ["starting working thread"] [worker=split-check] [2020/04/29 00:46:46.989 +00:00] [INFO] [node.rs:145] ["trying to bootstrap cluster"] [region="id: 2 region_epoch { conf_ver: 1 version: 1 } peers { id: 3 store_id: 1 }"] [store_id=1] [2020/04/29 00:46:46.994 +00:00] [INFO] [node.rs:281] ["bootstrap cluster ok"] [cluster_id=6820928503865373278] [2020/04/29 00:46:46.994 +00:00] [INFO] [node.rs:348] ["start raft store thread"] [store_id=1] [2020/04/29 00:46:46.994 +00:00] [INFO] [peer.rs:148] ["create peer"] [peer_id=3] [region_id=2] ``` ``` $ kubectl logs ${cluster_name}-tidb-0 -c tidb -n ${namespace} [2020/04/29 00:47:31.029 +00:00] [INFO] [server.go:235] ["server is running MySQL protocol"] [addr=0.0.0.0:4000] [2020/04/29 00:47:31.030 +00:00] [INFO] [http_status.go:80] ["for status and metrics report"] ["listening on addr"=0.0.0.0:10080] ``` ### Verify Security Configuraiton There are a couple of ways to verify security is correctly configured. #### Using pd-ctl ``` $ pd-ctl --cacert=${certificate_path}/ca.pem --cert=${certificate_path}/client.pem --key=${certificate_path}/client-key.pem -u https://${cluster_name}-pd.${namespace}.svc:2379 member ``` **Note that you may need to do a port forwarding to access pd.** The output is: ``` { "header": { "cluster_id": 6820928503865373278 }, "members": [ { "name": "basic-pd-0", "member_id": 6727612475397276319, "peer_urls": [ "https://basic-pd-0.basic-pd-peer.demo.svc:2380" ], "client_urls": [ "https://basic-pd-0.basic-pd-peer.demo.svc:2379" ], "deploy_path": "/", "binary_version": "v4.0.0-rc" } ], "leader": { "name": "basic-pd-0", "member_id": 6727612475397276319, "peer_urls": [ "https://basic-pd-0.basic-pd-peer.demo.svc:2380" ], "client_urls": [ "https://basic-pd-0.basic-pd-peer.demo.svc:2379" ] }, "etcd_leader": { "name": "basic-pd-0", "member_id": 6727612475397276319, "peer_urls": [ "https://basic-pd-0.basic-pd-peer.demo.svc:2380" ], "client_urls": [ "https://basic-pd-0.basic-pd-peer.demo.svc:2379" ], "deploy_path": "/", "binary_version": "v4.0.0-rc" } } ``` Note that `https` is used for `client_urls` and `peer_urls`. #### Using MySQL Client ``` $ mysql -u root -P 4000 -h ${tidb_host} --ssl-cert=${certificate_path}/client.pem --ssl-key=${certificate_path}/client-key.pem --ssl-ca=${certificate_path}/ca.pem --ssl-mode=VERIFY_IDENTITY ``` ``` mysql> \s -------------- mysql Ver 8.0.19 for osx10.15 on x86_64 (Homebrew) Connection id: 29 Current database: Current user: root@127.0.0.1 SSL: Cipher in use is TLS_AES_256_GCM_SHA384 Current pager: stdout Using outfile: '' Using delimiter: ; Server version: 5.7.25-TiDB-v4.0.0-rc TiDB Server (Apache License 2.0), MySQL 5.7 compatible Protocol version: 10 Connection: 127.0.0.1 via TCP/IP Server characterset: utf8mb4 Db characterset: utf8mb4 Client characterset: utf8mb4 Conn. characterset: utf8mb4 TCP port: 4000 Binary data as: Hexadecimal -------------- ``` ``` mysql> SHOW STATUS LIKE "%Ssl%"; +-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Variable_name | Value | +-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Ssl_cipher | TLS_AES_256_GCM_SHA384 | | Ssl_cipher_list | RC4-SHA:DES-CBC3-SHA:AES128-SHA:AES256-SHA:AES128-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-ECDSA-RC4-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-RC4-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-CHACHA20-POLY1305:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256: | | Ssl_verify_mode | 5 | | Ssl_version | TLSv1.3 | +-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 4 rows in set (0.01 sec) ```