# Issue TLS Certificates Using CFSSL > - **Objective:** Generate Certificate for TLS Using cfssl > - **Prerequisite:** > - None > - **Optionality:** Optional > - **Estimated time:** TBD ## Introduction TLS certificates can be issued by multiple methods. This document describes how to use [CFSSL](https://github.com/cloudflare/cfssl) to issue certificates. CFSSL is CloudFlare's PKI/TLS swiss army knife. It is both a command line tool and an HTTP API server for signing, verifying, and bundling TLS certificates. ## Install CFSSL To install 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-amd64 $ chmod +x ~/bin/{cfssl,cfssljson} $ export PATH=$PATH:~/bin ``` Verify the installation: ``` $ cfssl -h ``` ## Issue Certificate ### Create Certificate Directory We create a directory to hold all certificates. ``` $ mkdir -p ~/cfssl $ export certificate_path=~/cfssl $ cd ${certificate_path} ``` **Note that the following operations are performed under `${certificate_path}`.** ### Configure Certificate Authority (CA) A Certificate Authority (CA) is an entity that issues digital certificates. A digital certificate certifies the ownership of a public key by the named subject of the certificate. This allows others (relying parties) to rely upon signatures or on assertions made about the private key that corresponds to the certified public key. A CA acts as a trusted third party—trusted both by the subject (owner) of the certificate and by the party relying upon the certificate. The format of these certificates is specified by the X.509 or EMV standard. We first need to create and customize the `ca-config.json` configuration file to define our CA. ``` $ cfssl print-defaults config > ca-config.json $ vim ca-config.json ``` The changes we need to make are - Change `sigining.default.expiry` to `8760h`. - Change `signing.profiles.server.usage` to add `server auth` and `client auth` ``` { "signing": { "default": { "expiry": "8760h" }, "profiles": { "server": { "expiry": "8760h", "usages": [ "signing", "key encipherment", "server auth", "client auth" ] }, "client": { "expiry": "8760h", "usages": [ "signing", "key encipherment", "client auth" ] } } } } ``` **Note that we need to add Add `client auth` in profiles - server - usages, because this server-side certificate is also used as the client-side certificate.** Next we need to configure the certificate signing request (CSR). ``` $ cfssl print-defaults csr > ca-csr.json ``` We need to make necessary modifications to CSR. The changes we need to make are: - Change the `CN` field to `TIDB`. - Change the `key.algo` filed to `rsa` and `key.size` to `2048`. - Change the names to the values below. ``` { "CN": "TiDB", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "CA", "O": "PingCAP", "ST": "Beijing", "OU": "TiDB" } ] } ``` Now generate the self-signed root CA certificate and private key: ``` $ cfssl gencert -initca ca-csr.json | cfssljson -bare ca - 2020/04/28 11:32:55 [INFO] generating a new CA key and certificate from CSR 2020/04/28 11:32:55 [INFO] generate received request 2020/04/28 11:32:55 [INFO] received CSR 2020/04/28 11:32:55 [INFO] generating key: rsa-2048 2020/04/28 11:32:55 [INFO] encoded CSR 2020/04/28 11:32:55 [INFO] signed certificate with serial number 312652930147915274584885165112010854762084891048 ``` ### 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. - Cluster Client certificate for communicating between components. - Client certificate for communicating between MySQL client and TiDB Cluster. #### Issue PD Server Certificate ``` $ cfssl print-defaults csr > pd-server.json ``` Edit `pd-server.json` to make modifications. The changes we need to make are: - Change the `CN` field to `TiDB`. - Change the `hosts` field to add the following. Note that the entries in hosts assumes the TiDB cluster name to be `basic` and namespace to be `demo`. You need to make corresponding changes. ``` { "CN": "TiDB", "hosts": [ "127.0.0.1", "::1", "basic-pd", "basic-pd.demo", "basic-pd.demo.svc", "basic-pd-peer", "basic-pd-peer.demo", "basic-pd-peer.demo.svc", "*.basic-pd-peer", "*.basic-pd-peer.demo", "*.basic-pd-peer.demo.svc" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "CA", "O": "PingCAP", "ST": "Beijing", "OU": "TiDB" } ] } ``` We can then generate the PD Server certificate with the CA: ``` $ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server pd-server.json | cfssljson -bare pd-server 2020/04/23 22:55:06 [INFO] generate received request 2020/04/23 22:55:06 [INFO] received CSR 2020/04/23 22:55:06 [INFO] generating key: rsa-2048 2020/04/23 22:55:07 [INFO] encoded CSR 2020/04/23 22:55:07 [INFO] signed certificate with serial number 214389999857155365314767437017019726628791998243 ``` We can inspect the certificate using `openssl`: ``` $ openssl x509 -text -in pd-server.pem -noout ertificate: Data: Version: 3 (0x2) Serial Number: 42:a7:a6:4e:32:9a:42:5c:3f:a0:66:da:60:d0:82:d7:5d:ed:54:c7 Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=Beijing, L=CA, O=PingCAP, OU=TiDB, CN=TiDB Validity Not Before: Apr 25 03:27:00 2020 GMT Not After : Apr 25 03:27:00 2021 GMT Subject: C=US, ST=Beijing, L=CA, O=PingCAP, OU=TiDB, CN=TiDB Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:dc:f9:9f:74:ac:eb:2d:66:44:81:b2:ba:e4:f5: 71:a5:3b:b1:ef:0f:f8:d2:0f:26:9a:b8:6e:03:3b: 65:74:73:ea:a2:ae:0f:93:d8:6a:a9:a3:a5:7f:eb: a1:10:76:43:1f:25:dd:2c:1f:f5:23:a1:43:6f:e9: 30:d8:d4:ac:e2:a3:53:08:28:82:dc:d1:bf:e8:59: 96:f8:3c:dd:a4:65:53:02:a6:ed:66:13:7d:16:10: ad:ad:b3:f5:50:fd:fb:fb:74:cb:c3:b3:90:d7:b1: 0f:22:85:6d:13:2f:c0:7d:ee:8b:17:cd:75:82:ea: 16:db:ca:97:4c:6c:00:94:74:c2:da:07:48:6f:db: 90:75:19:58:54:16:de:08:bc:c5:a0:62:e7:f4:69: 4f:57:31:5f:e4:ce:ca:83:6d:84:dd:64:39:d8:1e: 04:e1:64:70:ec:f6:47:b3:22:d1:57:4f:bc:a9:4f: 54:b8:29:c9:8b:64:7a:96:90:3f:98:14:be:26:b1: a3:7c:fa:a1:4d:df:9a:c5:e4:37:2a:2b:41:70:ae: 57:82:7f:89:a3:50:56:5e:80:82:e9:e4:09:7e:d8: 8f:4f:ab:03:87:09:af:f7:31:bc:0a:2a:20:6e:3a: e5:a3:95:4d:f5:19:71:cc:6d:d3:a9:88:29:21:ba: 51:e1 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: 3C:29:6B:01:2D:98:59:D8:E5:A7:F0:10:7E:8F:41:E9:98:F1:F1:ED X509v3 Subject Alternative Name: DNS:basic-pd, DNS:basic-pd.demo, DNS:basic-pd.demo.svc, DNS:basic-pd-peer, DNS:basic-pd-peer.demo, DNS:basic-pd-peer.demo.svc, DNS:*.basic-pd-peer, DNS:*.basic-pd-peer.demo, DNS:*.basic-pd-peer.demo.svc, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1 Signature Algorithm: sha256WithRSAEncryption 94:cf:8f:af:15:b2:4d:de:64:8c:b0:58:dd:b8:ab:8d:99:48: 23:50:29:47:27:59:af:3c:f8:17:06:ba:a8:0b:be:30:03:b0: c0:f2:60:1c:60:4c:cd:0a:bb:9b:3d:35:7c:43:74:87:1d:51: 6e:ed:d8:d4:fe:88:04:d9:95:58:4e:8d:40:92:6e:b8:84:13: b3:c2:83:d7:dc:38:41:7b:ce:8a:99:6f:13:fb:eb:d4:a6:2e: f7:80:75:71:8d:03:56:66:a6:d3:1c:f9:83:3e:76:b7:d3:68: 6b:46:fe:d5:9d:7b:e2:60:f9:d3:f5:40:fd:42:de:ed:b5:02: 3b:4f:15:87:25:fc:90:5d:2d:71:74:0b:b8:56:6b:bd:33:74: 8e:76:ce:54:83:a8:0a:1e:dc:60:f0:73:d0:a1:cf:01:00:c6: 2a:f4:8a:25:c2:d9:50:39:08:f2:8f:fb:21:6e:9a:9d:04:c6: 86:5a:b4:c9:c8:c4:66:a6:9d:5d:0d:66:2e:92:83:c9:62:8f: 21:cb:68:08:2d:8c:bb:bc:7d:39:c5:6c:04:a0:aa:bc:2c:0d: 6c:39:50:12:7d:37:a5:e3:ba:5e:09:2f:a7:07:67:68:3b:67: 6e:db:f6:f8:75:8e:1b:13:94:80:1d:f8:05:8a:2d:94:70:ea: 04:c7:09:8c ``` TODO: explain the meaning of different fields. #### Issue TiKV Server certificate ``` $ cfssl print-defaults csr > tikv-server.json ``` Edit `tikv-server.json` to make modifications. The changes we need to make are: - Change the `CN` field to `TiDB`. - Change the `hosts` field to add the following. Note that the entries in hosts assumes the TiDB cluster name to be `basic` and namespace to be `demo`. You need to make corresponding changes. ``` { "CN": "TiDB", "hosts": [ "127.0.0.1", "::1", "basic-tikv", "basic-tikv.demo", "basic-tikv.demo.svc", "basic-tikv-peer", "basic-tikv-peer.demo", "basic-tikv-peer.demo.svc", "*.basic-tikv-peer", "*.basic-tikv-peer.demo", "*.basic-tikv-peer.demo.svc" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "CA", "O": "PingCAP", "ST": "Beijing", "OU": "TiDB" } ] } ``` We can then generate the TiKV Server certificate with the CA: ``` $ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server tikv-server.json | cfssljson -bare tikv-server 2020/04/28 12:55:42 [INFO] generate received request 2020/04/28 12:55:42 [INFO] received CSR 2020/04/28 12:55:42 [INFO] generating key: rsa-2048 2020/04/28 12:55:42 [INFO] encoded CSR 2020/04/28 12:55:42 [INFO] signed certificate with serial number 425207623158563460200719671690261814210346624866 ``` We can inspect the certificate using `openssl`: ``` $ openssl x509 -text -in tikv-server.pem -noout ``` #### Issue TiDB Server Certificate ``` $ cfssl print-defaults csr > tidb-server.json ``` Edit `tidb-server.json` to make modifications. The changes we need to make are: - Change the `CN` field to `TiDB`. - Change the `hosts` field to add the following. Note that the entries in hosts assumes the TiDB cluster name to be `basic` and namespace to be `demo`. You need to make corresponding changes. ``` { "CN": "TiDB", "hosts": [ "127.0.0.1", "::1", "basic-tidb", "basic-tidb.demo", "basic-tidb.demo.svc", "*.basic-tidb", "*.basic-tidb.demo", "*.basic-tidb.demo.svc" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "CA", "O": "PingCAP", "ST": "Beijing", "OU": "TiDB" } ] } ``` We can then generate the TiDB Server certificate with the CA: ``` $ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=server tidb-server.json | cfssljson -bare tidb-server 2020/04/28 13:02:06 [INFO] generate received request 2020/04/28 13:02:06 [INFO] received CSR 2020/04/28 13:02:06 [INFO] generating key: rsa-2048 2020/04/28 13:02:07 [INFO] encoded CSR 2020/04/28 13:02:07 [INFO] signed certificate with serial number 677609381869553541316763926377530091236235435217 ``` We can inspect the certificate using `openssl`: ``` $ openssl x509 -text -in tidb-server.pem -noout ``` #### Issue Client Certificate ``` $ cfssl print-defaults csr > client.json ``` Edit `client.json` to make modifications. The changes we need to make are: - Change the `CN` field to `TiDB`. - Change the `hosts` field to be empty. ``` { "CN": "TiDB", "hosts": [], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "CA", "O": "PingCAP", "ST": "Beijing", "OU": "TiDB" } ] } ``` ``` $ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=client client.json | cfssljson -bare client 2020/04/28 13:18:12 [INFO] generate received request 2020/04/28 13:18:12 [INFO] received CSR 2020/04/28 13:18:12 [INFO] generating key: rsa-2048 2020/04/28 13:18:12 [INFO] encoded CSR 2020/04/28 13:18:12 [INFO] signed certificate with serial number 18096070442089977328487840082232485650921646783 2020/04/28 13:18:12 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for websites. For more information see the Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org); specifically, section 10.2.3 ("Information Requirements"). ``` We can inspect the certificate using `openssl`: ``` $ openssl x509 -text -in client.pem -noout ``` ### Create Kubernetes Secret Before performing the opertions, please ensure that a Kubernetes cluster is up and running. Also the following environment has been set. ``` $ export cluster_name=basic $ export namespace=demo $ export certificate_path= # Path to the certificate ``` #### Create Secret for TiDB Cluster Components Create PD Server certificate: ``` $ kubectl create secret generic ${cluster_name}-pd-cluster-secret --namespace=${namespace} --from-file=tls.crt=${certificate_path}/pd-server.pem --from-file=tls.key=${certificate_path}/pd-server-key.pem --from-file=ca.crt=${certificate_path}/ca.pem ``` Create TiKV Server certificate: ``` $ kubectl create secret generic ${cluster_name}-tikv-cluster-secret --namespace=${namespace} --from-file=tls.crt=${certificate_path}/tikv-server.pem --from-file=tls.key=${certificate_path}/tikv-server-key.pem --from-file=ca.crt=${certificate_path}/ca.pem ``` Create TiDB Server certificate: ``` $ kubectl create secret generic ${cluster_name}-tidb-cluster-secret --namespace=${namespace} --from-file=tls.crt=${certificate_path}/tidb-server.pem --from-file=tls.key=${certificate_path}/tidb-server-key.pem --from-file=ca.crt=${certificate_path}/ca.pem ``` Create Cluster Client certificate: ``` $ kubectl create secret generic ${cluster_name}-cluster-client-secret --namespace=${namespace} --from-file=tls.crt=${certificate_path}/client.pem --from-file=tls.key=${certificate_path}/client-key.pem --from-file=ca.crt=${certificate_path}/ca.pem ``` #### Create Secret for MySQL Client and TiDB Cluster Create Server certificate ``` $ kubectl create secret generic ${cluster_name}-tidb-server-secret --namespace=${namespace} --from-file=tls.crt=${certificate_path}/tidb-server.pem --from-file=tls.key=${certificate_path}/tidb-server-key.pem --from-file=ca.crt=${certificate_path}/ca.pem ``` Create Client certificate ``` $ kubectl create secret generic ${cluster_name}-tidb-client-secret --namespace=${namespace} --from-file=tls.crt=${certificate_path}/client.pem --from-file=tls.key=${certificate_path}/client-key.pem --from-file=ca.crt=${certificate_path}/ca.pem ``` ### Verify that the secrets are created ``` $ kubectl get secrets -n demo NAME TYPE DATA AGE basic-cluster-client-secret Opaque 3 27s basic-pd-cluster-secret Opaque 3 51s basic-tidb-client-secret Opaque 3 14s basic-tidb-cluster-secret Opaque 3 33s basic-tidb-server-secret Opaque 3 20s basic-tikv-cluster-secret Opaque 3 44s default-token-jwh9v kubernetes.io/service-account-token 3 56s ```