Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various TLS related updates (#16982) #18022

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 25 additions & 38 deletions certificate-authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ ssl-ca="path/to/ca-cert.pem"
启动 TiDB 日志。如果日志中有以下内容,即代表配置生效:

```
[INFO] [server.go:264] ["secure connection is enabled"] ["client verification enabled"=true]
[INFO] [server.go:286] ["mysql protocol server secure connection is enabled"] ["client verification enabled"=true]
```

### 配置客户端程序
Expand All @@ -257,9 +257,9 @@ mysql -utest -h0.0.0.0 -P4000 --ssl-cert /path/to/client-cert.new.pem --ssl-key

### 获取用户证书信息

用户证书信息可由 `require subject`、`require issuer`、`require san` 和 `require cipher` 来指定,用于检查 X.509 certificate attributes。
用户证书信息可由 `REQUIRE SUBJECT`、`REQUIRE ISSUER`、`REQUIRE SAN` 和 `REQUIRE CIPHER` 来指定,用于检查 X.509 certificate attributes。

+ `require subject`:指定用户在连接时需要提供客户端证书的 `subject` 内容。指定该选项后,不需要再配置 `require ssl` 或 x509。配置内容对应[生成客户端密钥和证书](#生成客户端密钥和证书)中的录入信息。
+ `REQUIRE SUBJECT`:指定用户在连接时需要提供客户端证书的 `subject` 内容。指定该选项后,不需要再配置 `require ssl` 或 x509。配置内容对应[生成客户端密钥和证书](#生成客户端密钥和证书)中的录入信息。

可以执行以下命令来获取该项的信息:

Expand All @@ -269,7 +269,7 @@ mysql -utest -h0.0.0.0 -P4000 --ssl-cert /path/to/client-cert.new.pem --ssl-key
openssl x509 -noout -subject -in client-cert.pem | sed 's/.\{8\}//' | sed 's/, /\//g' | sed 's/ = /=/g' | sed 's/^/\//'
```

+ `require issuer`:指定签发用户证书的 CA 证书的 `subject` 内容。配置内容对应[生成 CA 密钥和证书](#生成-ca-密钥和证书)中的录入信息。
+ `REQUIRE ISSUER`:指定签发用户证书的 CA 证书的 `subject` 内容。配置内容对应[生成 CA 密钥和证书](#生成-ca-密钥和证书)中的录入信息。

可以执行以下命令来获取该项的信息:

Expand All @@ -279,17 +279,17 @@ mysql -utest -h0.0.0.0 -P4000 --ssl-cert /path/to/client-cert.new.pem --ssl-key
openssl x509 -noout -subject -in ca-cert.pem | sed 's/.\{8\}//' | sed 's/, /\//g' | sed 's/ = /=/g' | sed 's/^/\//'
```

+ `require san`:指定签发用户证书的 CA 证书的 `Subject Alternative Name` 内容。配置内容对应生成客户端证书使用的 [openssl.cnf 配置文件的 `alt_names` 信息](/generate-self-signed-certificates.md)。
+ `REQUIRE SAN`:指定签发用户证书的 CA 证书的 `Subject Alternative Name` 内容。配置内容对应生成客户端证书使用的 [openssl.cnf 配置文件的 `alt_names` 信息](/generate-self-signed-certificates.md)。

+ 可以执行以下命令来获取已生成证书中的 `require san` 项的信息:
+ 可以执行以下命令来获取已生成证书中的 `REQUIRE SAN` 项的信息:

{{< copyable "shell-regular" >}}

```shell
openssl x509 -noout -extensions subjectAltName -in client.crt
```

+ `require san` 目前支持以下 `Subject Alternative Name` 检查项:
+ `REQUIRE SAN` 目前支持以下 `Subject Alternative Name` 检查项:

- URI
- IP
Expand All @@ -300,60 +300,48 @@ mysql -utest -h0.0.0.0 -P4000 --ssl-cert /path/to/client-cert.new.pem --ssl-key
{{< copyable "sql" >}}

```sql
create user 'u1'@'%' require san 'DNS:d1,URI:spiffe://example.org/myservice1,URI:spiffe://example.org/myservice2'
CREATE USER 'u1'@'%' REQUIRE SAN 'DNS:d1,URI:spiffe://example.org/myservice1,URI:spiffe://example.org/myservice2';
```

以上配置只允许用户 `u1` 使用 URI 项为 `spiffe://example.org/myservice1` 或 `spiffe://example.org/myservice2`、DNS 项为 `d1` 的证书登录 TiDB。

+ `require cipher`:配置该项检查客户端支持的 `cipher method`。可以使用以下语句来查看支持的列表:

{{< copyable "sql" >}}
+ `REQUIRE CIPHER`:配置该项检查客户端支持的 `cipher method`。可以使用以下语句来查看支持的列表:

```sql
SHOW SESSION STATUS LIKE 'Ssl_cipher_list';
```

### 配置用户证书信息

获取用户证书信息(`require subject`, `require issuer`、`require san` 和 `require cipher`)后,可在创建用户、赋予权限或更改用户时配置用户证书信息。将以下命令中的 `<replaceable>` 替换为对应的信息。可以选择配置其中一项或多项,使用空格或 `and` 分隔。

+ 可以在创建用户 (`create user`) 时配置登录时需要校验的证书信息:

{{< copyable "sql" >}}

```sql
create user 'u1'@'%' require issuer '<replaceable>' subject '<replaceable>' san '<replaceable>' cipher '<replaceable>';
```
获取用户证书信息(`REQUIRE SUBJECT`、`REQUIRE ISSUER`、`REQUIRE SAN` 和 `REQUIRE CIPHER`)后,可在创建用户、赋予权限或更改用户时配置用户证书信息。将以下命令中的 `<replaceable>` 替换为对应的信息。可以选择配置其中一项或多项,使用空格或 `and` 分隔。

+ 可以在赋予权限 (`grant`) 时配置登录时需要校验的证书信息:
+ 可以在创建用户 (`CREATE USER`) 时配置登录时需要校验的证书信息:

{{< copyable "sql" >}}

```sql
grant all on *.* to 'u1'@'%' require issuer '<replaceable>' subject '<replaceable>' san '<replaceable>' cipher '<replaceable>';
CREATE USER 'u1'@'%' REQUIRE ISSUER '<replaceable>' SUBJECT '<replaceable>' SAN '<replaceable>' CIPHER '<replaceable>';
```

+ 还可以在修改已有用户 (alter user) 时配置登录时需要校验的证书信息:
+ 可以在修改已有用户 (`ALTER USER`) 时配置登录时需要校验的证书信息:

{{< copyable "sql" >}}

```sql
alter user 'u1'@'%' require issuer '<replaceable>' subject '<replaceable>' san '<replaceable>' cipher '<replaceable>';
ALTER USER 'u1'@'%' REQUIRE ISSUER '<replaceable>' SUBJECT '<replaceable>' SAN '<replaceable>' CIPHER '<replaceable>';
```

配置完成后,用户在登录时 TiDB 会验证以下内容:

+ 使用 SSL 登录,且证书为服务器配置的 CA 证书所签发
+ 证书的 `Issuer` 信息和权限配置里的信息相匹配
+ 证书的 `Subject` 信息和权限配置里的信息相匹配
+ 证书的 `Subject Alternative Name` 信息和权限配置里的信息相匹配
+ 证书的 `issuer` 信息和权限配置里的 `REQUIRE ISSUER` 信息相匹配
+ 证书的 `subject` 信息和权限配置里的 `REQUIRE CIPHER` 信息相匹配
+ 证书的 `Subject Alternative Name` 信息和权限配置里的 `REQUIRE SAN` 信息相匹配

全部验证通过后用户才能登录,否则会报 `ERROR 1045 (28000): Access denied` 错误。登录后,可以通过以下命令来查看当前链接是否使用证书登录、TLS 版本和 Cipher 算法。

连接 MySQL 客户端并执行:

{{< copyable "sql" >}}

```sql
\s
```
Expand All @@ -362,20 +350,18 @@ mysql -utest -h0.0.0.0 -P4000 --ssl-cert /path/to/client-cert.new.pem --ssl-key

```
--------------
mysql Ver 15.1 Distrib 10.4.10-MariaDB, for Linux (x86_64) using readline 5.1
mysql Ver 8.3.0 for Linux on x86_64 (MySQL Community Server - GPL)

Connection id: 1
Current database: test
Current user: [email protected]
SSL: Cipher in use is TLS_AES_256_GCM_SHA384
SSL: Cipher in use is TLS_AES_128_GCM_SHA256
```

然后执行:

{{< copyable "sql" >}}

```sql
show variables like '%ssl%';
SHOW VARIABLES LIKE '%ssl%';
```

返回结果如下:
Expand All @@ -384,13 +370,14 @@ show variables like '%ssl%';
+---------------+----------------------------------+
| Variable_name | Value |
+---------------+----------------------------------+
| ssl_cert | /path/to/server-cert.pem |
| ssl_ca | /path/to/ca-cert.pem |
| have_ssl | YES |
| have_openssl | YES |
| have_ssl | YES |
| ssl_ca | /path/to/ca-cert.pem |
| ssl_cert | /path/to/server-cert.pem |
| ssl_cipher | |
| ssl_key | /path/to/server-key.pem |
+---------------+----------------------------------+
6 rows in set (0.067 sec)
6 rows in set (0.06 sec)
```

## 更新和替换证书
Expand Down
58 changes: 31 additions & 27 deletions enable-tls-between-clients-and-servers.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ title: 为 TiDB 客户端服务端间通信开启加密传输

# 为 TiDB 客户端服务端间通信开启加密传输

TiDB 服务端与客户端之间默认采用非加密连接,因而具备监视信道流量能力的第三方可以知悉 TiDB 服务端与客户端之间发送和接受的数据,包括但不限于查询语句内容、查询结果等。若信道是不可信的,例如客户端是通过公网连接到 TiDB 服务端的,则非加密连接容易造成信息泄露,建议使用加密连接确保安全性
默认情况下,TiDB 允许服务端与客户端之间的不安全连接,因而具备监视信道流量能力的第三方可以知悉 TiDB 服务端与客户端之间发送和接受的数据,包括但不限于查询语句内容、查询结果等。若信道是不可信的,例如客户端是通过公网连接到 TiDB 服务端的,则不安全连接容易造成信息泄露,建议使用 TLS 连接确保安全性

TiDB 服务端支持启用基于 TLS(传输层安全)协议的加密连接,协议与 MySQL 加密连接一致,现有 MySQL Client 如 MySQL Shell 和 MySQL 驱动等能直接支持。TLS 的前身是 SSL,因而 TLS 有时也被称为 SSL,但由于 SSL 协议有已知安全漏洞,TiDB 实际上并未支持。TiDB 支持的 TLS/SSL 协议版本为 TLSv1.2 和 TLSv1.3。
TiDB 服务端支持启用基于 TLS(传输层安全)协议的安全连接,协议与 MySQL 安全连接一致,现有 MySQL Client 如 MySQL Shell 和 MySQL 驱动等能直接支持。TLS 的前身是 SSL,因而 TLS 有时也被称为 SSL,但由于 SSL 协议有已知安全漏洞,TiDB 实际上并未支持。TiDB 支持的 TLS/SSL 协议版本为 TLSv1.2 和 TLSv1.3。

使用加密连接后,连接将具有以下安全性质:
使用 TLS 安全连接后,连接将具有以下安全性质:

- 保密性:流量明文被加密,无法被窃听;
- 完整性:流量明文无法被篡改;
- 身份验证(可选):客户端和服务端能验证双方身份,避免中间人攻击。

要为 TiDB 客户端与服务端间的通信开启 TLS 加密传输,首先需要在 TiDB 服务端通过配置开启 TLS 加密连接的支持,然后通过配置客户端应用程序使用 TLS 加密连接。一般情况下,如果服务端正确配置了 TLS 加密连接支持,客户端库都会自动启用 TLS 加密传输
要为 TiDB 客户端与服务端间的通信开启 TLS 安全传输,首先需要在 TiDB 服务端通过配置开启 TLS 加密连接的支持,然后通过配置客户端应用程序使用 TLS 加密连接。一般情况下,如果服务端正确配置了 TLS 加密连接支持,客户端库都会自动启用 TLS 安全传输

另外,与 MySQL 相同,TiDB 也支持在同一 TCP 端口上开启 TLS 连接或非 TLS 连接。对于开启了 TLS 连接支持的 TiDB 服务端,客户端既可以选择通过加密连接安全地连接到该 TiDB 服务端,也可以选择使用普通的非加密连接。如需使用加密连接,你可以通过以下方式进行配置:

+ 通过配置系统变量 `require_secure_transport` 要求所有用户必须使用加密连接来连接到 TiDB。
+ 通过在创建用户 (`create user`),或修改已有用户 (`alter user`) 时指定 `REQUIRE SSL` 要求指定用户必须使用加密连接来连接 TiDB。以创建用户为例:
+ 通过配置系统变量 [`require_secure_transport`](/system-variables.md#require_secure_transport-从-v610-版本开始引入) 要求所有用户必须使用加密连接来连接到 TiDB。
+ 通过在创建用户 (`create user`),或修改已有用户 (`alter user`) 时指定 `REQUIRE SSL` 要求指定用户必须使用 TLS 连接来连接 TiDB。以创建用户为例:

```sql
CREATE USER 'u1'@'%' IDENTIFIED BY 'my_random_password' REQUIRE SSL;
Expand All @@ -39,31 +39,29 @@ TiDB 服务端支持启用基于 TLS(传输层安全)协议的加密连接
- [`ssl-ca`](/tidb-configuration-file.md#ssl-ca):可选,指定受信任的 CA 证书文件路径
- [`tls-version`](/tidb-configuration-file.md#tls-version):可选,指定最低 TLS 版本,例如 `TLSv1.2`

`auto-tls` 支持安全连接,但不提供客户端证书验证。有关证书验证和控制证书生成方式的说明,请参考下面配置 `ssl-cert``ssl-key` 和 `ssl-ca` 变量的建议:
`auto-tls` 支持安全连接,但不提供客户端证书验证。有关证书验证和控制证书生成方式的说明,请参考下面配置 `ssl-cert``ssl-key` 和 `ssl-ca` 变量的建议:

- 在启动 TiDB 时,至少需要在配置文件中同时指定 `ssl-cert` 和 `ssl-key` 参数,才能在 TiDB 服务端开启安全连接。还可以指定 `ssl-ca` 参数进行客户端身份验证(请参见[配置启用身份验证](#配置启用身份验证)章节)。
- 参数指定的文件都为 PEM 格式。另外目前 TiDB 尚不支持加载有密码保护的私钥,因此必须提供一个没有密码的私钥文件。若提供的证书或私钥无效,则 TiDB 服务端将照常启动,但并不支持客户端加密连接到 TiDB 服务端。
- 若证书参数无误,则 TiDB 在启动时将会输出 `secure connection is enabled`,否则 TiDB 会输出 `secure connection is NOT ENABLED`
- 参数指定的文件都为 PEM 格式。另外目前 TiDB 尚不支持加载有密码保护的私钥,因此必须提供一个没有密码的私钥文件。若提供的证书或私钥无效,则 TiDB 服务端将照常启动,但并不支持客户端 TLS 连接到 TiDB 服务端。
- 若证书参数无误,则 TiDB 在启动时将会输出 `mysql protocol server secure connection is enabled` 到 `"INFO"` 级别日志中

> **注意:**
>
> v5.2.0 版本之前,你可以使用 `mysql_ssl_rsa_setup --datadir=./certs` 生成证书。`mysql_ssl_rsa_setup` 工具是 MySQL Server 的一部分。
## 配置 MySQL Client 使用 TLS 连接

## 配置 MySQL Client 使用安全连接

MySQL 5.7 及以上版本自带的客户端默认尝试使用安全连接,若服务端不支持安全连接则自动退回到使用非安全连接;MySQL 5.7 以下版本自带的客户端默认采用非安全连接。
MySQL 5.7 及以上版本自带的客户端默认尝试使用 TLS 连接,若服务端不支持安全连接则自动退回到使用非安全连接;MySQL 5.7 以下版本自带的客户端默认采用非 TLS 连接。

可以通过命令行参数修改客户端的连接行为,包括:

- 强制使用安全连接,若服务端不支持安全连接则连接失败 (`--ssl-mode=REQUIRED`)
- 尝试使用安全连接,若服务端不支持安全连接则退回使用不安全连接
- 使用不安全连接 (`--ssl-mode=DISABLED`)

除此参数外,MySQL 8.0 客户端有两种 SSL 模式:
除此参数外,MySQL 8.x 客户端有两种 SSL 模式:

- `--ssl-mode=VERIFY_CA`:根据 `--ssl-ca` 签发的 CA 验证来自服务器的证书。
- `--ssl-mode=VERIFY_IDENTITY`:与 `VERIFY_CA` 相同,但也验证所连接的主机名是否与证书匹配。

对于 MySQL 5.7 和 MariaDB 客户端及之前版本,可以使用 `--ssl-verify-server-cert` 参数启用对服务端证书的验证。

详细信息请参阅 MySQL 文档中关于[客户端配置安全连接](https://dev.mysql.com/doc/refman/8.0/en/using-encrypted-connections.html#using-encrypted-connections-client-side-configuration)的部分。

## 配置启用身份验证
Expand All @@ -74,10 +72,10 @@ MySQL 5.7 及以上版本自带的客户端默认尝试使用安全连接,若
- 若要使 TiDB 服务端验证 MySQL Client 身份,TiDB 服务端需配置 `ssl-cert`、`ssl-key`、`ssl-ca` 参数,客户端需至少指定 `--ssl-cert`、`--ssl-key` 参数。必须确保服务端配置的证书和客户端配置的证书都是由服务端配置指定的 `ssl-ca` 签发的。
- 若要进行双向身份验证,请同时满足上述要求。

默认情况,服务端对客户端的身份验证是可选的。若客户端在 TLS 握手时未出示自己的身份证书,也能正常建立 TLS 连接。但也可以通过在创建用户 (`create user`),赋予权限 (`grant`) 或修改已有用户 (`alter user`) 时指定 `require x509` 要求客户端需进行身份验证,以创建用户为例:
默认情况,服务端对客户端的身份验证是可选的。若客户端在 TLS 握手时未出示自己的身份证书,也能正常建立 TLS 连接。但也可以通过在创建用户 (`CREATE USER`) 或修改已有用户 (`ALTER USER`) 时指定 `REQUIRE x509` 要求客户端需进行身份验证,以创建用户为例:

```sql
create user 'u1'@'%' require x509;
CREATE USER 'u1'@'%' REQUIRE X509;
```

> **注意:**
Expand All @@ -93,15 +91,21 @@ create user 'u1'@'%' require x509;
{{< copyable "sql" >}}

```sql
SHOW STATUS LIKE "%Ssl%";
SHOW STATUS LIKE "Ssl%";
```

```
......
| Ssl_verify_mode | 5 |
| Ssl_version | TLSv1.2 |
| Ssl_cipher | ECDHE-RSA-AES128-GCM-SHA256 |
......
+-----------------------+------------------------------------------------------->
| Variable_name | Value >
+-----------------------+------------------------------------------------------->
| Ssl_cipher | TLS_AES_128_GCM_SHA256 >
| Ssl_cipher_list | RC4-SHA:DES-CBC3-SHA:AES128-SHA:AES256-SHA:AES128-SHA2>
| Ssl_server_not_after | Apr 23 07:59:47 2024 UTC >
| Ssl_server_not_before | Jan 24 07:59:47 2024 UTC >
| Ssl_verify_mode | 5 >
| Ssl_version | TLSv1.3 >
+-----------------------+------------------------------------------------------->
6 rows in set (0.0062 sec)
```

除此以外,对于 MySQL 自带客户端,还可以使用 `STATUS` 或 `\s` 语句查看连接情况:
Expand All @@ -114,13 +118,13 @@ SHOW STATUS LIKE "%Ssl%";

```
...
SSL: Cipher in use is ECDHE-RSA-AES128-GCM-SHA256
SSL: Cipher in use is TLS_AES_128_GCM_SHA256
...
```

## 支持的 TLS 版本及密钥交换协议和加密算法

TiDB 支持的 TLS 版本及密钥交换协议和加密算法由 Golang 官方库决定。
TiDB 支持的 TLS 版本及密钥交换协议和加密算法由 Go 官方库决定。

你使用的客户端库和操作系统加密策略也可能会影响到支持的协议版本和密码套件。

Expand All @@ -129,7 +133,7 @@ TiDB 支持的 TLS 版本及密钥交换协议和加密算法由 Golang 官方
- TLSv1.2
- TLSv1.3

可以使用配置项 `tls-version` 来限制 TLS 版本。
可以使用配置项 [`tls-version`](/tidb-configuration-file.md#tls-version) 来限制 TLS 版本。

实际可用的 TLS 版本取决于操作系统的加密策略、MySQL 客户端版本和客户端的 SSL/TLS 库。

Expand Down
4 changes: 4 additions & 0 deletions sql-statements/sql-statement-alter-user.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ LockOption ::= ( 'ACCOUNT' 'LOCK' | 'ACCOUNT' 'UNLOCK' )?
AttributeOption ::= ( 'COMMENT' CommentString | 'ATTRIBUTE' AttributeString )?

ResourceGroupNameOption::= ( 'RESOURCE' 'GROUP' Identifier)?

RequireClauseOpt ::= ('REQUIRE' ('NONE' | 'SSL' | 'X509' | RequireListElement ('AND'? RequireListElement)*))?

RequireListElement ::= 'ISSUER' Issuer | 'SUBJECT' Subject | 'CIPHER' Cipher | 'SAN' SAN | 'TOKEN_ISSUER' TokenIssuer
```

## 示例
Expand Down
Loading
Loading