通过加密连接连接到 Azure Database for MySQL - 灵活服务器

适用于: Azure Database for MySQL - 灵活服务器

在这篇文章中,你将学会如何:

  • 配置 Azure Database for MySQL 灵活服务器实例
    • 禁用 SSL
    • 强制使用 SSL 和 TLS 版本
  • 使用 mysql 命令行连接到 Azure Database for MySQL 灵活服务器实例
    • 禁用加密连接
    • 启用加密连接
  • 验证连接的加密状态
  • 使用各种应用程序框架通过加密连接连接到 Azure Database for MySQL 灵活服务器实例

Azure Database for MySQL 灵活服务器中的 TLS/SSL 支持概述

Azure Database for MySQL 灵活服务器支持使用安全套接字层 (SSL) 和传输层安全性 (TLS) 加密将客户端应用程序连接到 Azure Database for MySQL 灵活服务器实例。 TLS 是一种行业标准协议,可确保在数据库服务器与客户端应用程序之间实现加密的网络连接,使你能够满足合规性要求。

默认情况下,Azure Database for MySQL 灵活服务器支持使用传输层安全性 (TLS 1.2) 的加密连接,并且拒绝所有使用 TLS 1.0 和 TLS 1.1 的传入连接。 你的灵活服务器上的加密连接强制要求或 TLS 版本配置可以按照本文中的说明进行更改。

下面是适用于 Azure Database for MySQL 灵活服务器实例的 SSL 和 TLS 设置的不同配置:

重要

根据 删除对 TLS 1.0 和 TLS 1.1 协议的支持,我们以前计划到 2024 年 9 月完全弃用 TLS 1.0 和 1.1。 但是,由于某些客户发现的依赖,我们决定延长时间表。

从 2025 年 8 月 31 日开始,我们开始对所有仍在使用 TLS 1.0 或 1.1 的服务器强制升级。 在此日期之后,任何依赖于 TLS 1.0 或 1.1 的连接随时都可能会停止工作。 为了避免潜在的服务中断,我们强烈建议客户在 2025 年 8 月 31 日之前完成迁移到 TLS 1.2。

Scenario 服务器参数设置 Description
禁用 TLS 强制执行 require_secure_transport = OFF 如果旧应用程序不支持加密连接,则可以禁用加密连接的强制实施。
使用 TLS 版本 < 1.2 强制实施 TLS(将于 2024 年 9 月弃用) require_secure_transport = ONtls_version = TLS 1.0TLS 1.1 不再可用!
强制实施 TLS,TLS 版本 = 1.2(默认配置) require_secure_transport = ONtls_version = TLS 1.2 默认配置。
强制使用 TLS,并设置 TLS 版本为 1.3 require_secure_transport = ONtls_version = TLS 1.3 建议的配置;仅支持 Azure Database for MySQL 灵活服务器版本 v8.0 及更高版本。

注释

不支持更改 TLS 密码。 默认情况下,当 tls_version 设置为 TLS 1.2TLS 1.3 时,将强制实施符合 FIPS 的密码套件。

在 Azure Database for MySQL 灵活服务器实例上禁用 TLS 强制

如果客户端应用程序不支持加密连接,则需要在 Azure Database for MySQL 灵活服务器实例上禁用加密连接强制。 若要禁用加密连接强制要求,需要将 require_secure_transport 服务器参数设置为“OFF”(如屏幕截图所示),并保存服务器参数配置,以使其生效。 require_secure_transport 是一个动态服务器参数,它会立即生效,无需重启服务器。

屏幕截图显示如何禁用 Azure Database for MySQL 灵活服务器的 SSL。

使用禁用 TLS 的 mysql 命令行客户端进行连接

以下示例演示如何使用 mysql 命令行界面连接到服务器。 使用 --ssl-mode=DISABLED 连接字符串设置来禁用来自 mysql 客户端的 TLS/SSL 连接。 将值替换为实际的服务器名称和密码。

 mysql.exe -h mydemoserver.mysql.database.chinacloudapi.cn -u myadmin -p --ssl-mode=DISABLED

重要

如果你在 Azure Database for MySQL 灵活服务器实例上将 require_secure_transport 设置为 OFF,即便客户端通过加密连接进行连接,连接仍将被接受。

 mysql.exe -h mydemoserver.mysql.database.chinacloudapi.cn -u myadmin -p --ssl-mode=REQUIRED
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 17
Server version: 5.7.29-log MySQL Community Server (GPL)

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show global variables like '%require_secure_transport%';
+--------------------------+-------+
| Variable_name | Value |
| +--------------------------+-------+ |
| require_secure_transport | OFF |
| +--------------------------+-------+ |
| 1 row in set (0.02 sec) |

总之, require_secure_transport=OFF 设置会放宽加密连接的强制实施;因此,除了加密连接之外,服务器还接受未加密的连接。

强制实施 TLS 版本

若要在 Azure Database for MySQL 灵活服务器实例上设置 TLS 版本,需要设置 tls_version 服务器参数。 TLS 协议的默认设置是 TLS 1.2。 如果应用程序支持使用 TLS 连接到 MySQL 服务器,但需要 TLS 1.2 以外的任何协议,请在 服务器参数中设置 TLS 版本。

tls_version 是一个 静态服务器参数 ,它要求服务器重启才能使参数生效。

使用 mysql 命令行客户端通过 TLS/SSL 进行连接

下载公共 SSL 证书

若要与客户端应用程序建立加密连接,请下载 DigiCert 全局根 G2 证书Microsoft RSA 根证书颁发机构 2017 证书。 在启动与服务器的连接之前合并这两个证书。 有关详细步骤,请参阅 如何更新客户端上的根证书存储

注释

必须在 Azure Mooncake 中为服务器下载 DigiCert 全局根证书

将证书文件保存到首选位置。 例如,本教程在本地环境或托管应用程序的客户端环境中使用 c:\ssl\var\www\html\bin

如果使用“专用访问(VNet 集成)”创建了 Azure Database for MySQL 灵活服务器实例,需要从与服务器位于同一 VNet 中的资源连接到服务器。 可以创建虚拟机并将其添加到使用 Azure Database for MySQL 灵活服务器实例创建的 VNet 中。

如果使用“公共访问(允许的 IP 地址)”创建了 Azure Database for MySQL 灵活服务器实例,可以将本地 IP 地址添加到服务器上的防火墙规则列表中

可以选择 mysql.exe将 MySQL Workbench 与 Azure Database for MySQL - 灵活服务器配合使用--> 以从本地环境连接到服务器。

以下示例演示如何使用 mysql 命令行界面连接到服务器。 使用 --ssl-mode=REQUIRED 连接字符串设置强制实施 TLS/SSL 证书验证。 将本地证书文件路径传递给 --ssl-ca 参数。 将值替换为实际的服务器名称和密码。

sudo apt-get install mysql-client
wget --no-check-certificate https://cacerts.digicert.com/DigiCertGlobalRootG2.crt.pem
mysql -h mydemoserver.mysql.database.chinacloudapi.cn -u mydemouser -p --ssl-mode=REQUIRED --ssl-ca=DigiCertGlobalRootG2.crt.pem

注释

确认传递给 --ssl-ca 的值与你保存的证书的文件路径匹配。 如果要使用完全验证进行连接(sslmode=VERTIFY_IDENTITY),请在连接字符串中使用 \<servername\>.mysql.database.chinacloudapi.cn

如果尝试使用未加密的连接连接到服务器,则会看到错误,指出禁止使用不安全传输的连接:

ERROR 3159 (HY000): Connections using insecure transport are prohibited while --require_secure_transport=ON.

验证 TLS 连接

执行 mysql status 命令,验证是否已使用 TLS 进行连接:

mysql> status

查看输出,确认连接是否已加密,如果已加密,输出应显示为:“SSL: 使用的密码为”。 此密码套件显示了一个示例。你可能会看到不同的密码套件,具体取决于客户端。

如何标识服务器上配置的 TLS 协议?

你可以运行命令 SHOW GLOBAL VARIABLES LIKE 'tls_version';然后查看该值以了解所有协议的配置。

mysql> SHOW GLOBAL VARIABLES LIKE 'tls_version';

如何查找客户端正在使用哪个 TLS 协议连接到服务器?

若要验证此连接中使用的 TLS 版本,请执行 SQL 查询:

SELECT sbt.variable_value AS tls_version,  t2.variable_value AS cipher,
processlist_user AS user, processlist_host AS host
FROM performance_schema.status_by_thread  AS sbt
JOIN performance_schema.threads AS t ON t.thread_id = sbt.thread_id
JOIN performance_schema.status_by_thread AS t2 ON t2.thread_id = t.thread_id
WHERE sbt.variable_name = 'Ssl_version' and t2.variable_name = 'Ssl_cipher' ORDER BY tls_version;

使用各种应用程序框架通过加密连接连接到 Azure Database for MySQL 灵活服务器实例

Azure 门户中服务器可用的“连接字符串”页中预定义的连接字符串包括公共语言使用 TLS/SSL 连接到数据库服务器所需的参数。 TLS/SSL 参数因连接器而异。 例如,“useSSL=true”、“sslmode=required”或“ssl_verify_cert=true”以及其他变体。

若要从应用程序通过 TLS/SSL 与 Azure Database for MySQL 灵活服务器实例建立加密连接,请参阅以下代码示例:

WordPress

下载 SSL 公共证书,并在 wp-config.php 中的 // **MySQL settings - You can get this info from your web host** // 行后添加以下行。

//** Connect with SSL ** //
define('MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_SSL);
//** SSL CERT **//
define('MYSQL_SSL_CERT','/FULLPATH/on-client/to/DigiCertGlobalRootG2.crt.pem');

PHP

$conn = mysqli_init();
mysqli_ssl_set($conn,NULL,NULL, "/var/www/html/DigiCertGlobalRootG2.crt.pem", NULL, NULL);
mysqli_real_connect($conn, 'mydemoserver.mysql.database.chinacloudapi.cn', 'myadmin', 'yourpassword', 'quickstartdb', 3306, MYSQLI_CLIENT_SSL);
if (mysqli_connect_errno()) {
die('Failed to connect to MySQL: '.mysqli_connect_error());
}

PHP(使用 PDO)

$options = array(
    PDO::MYSQL_ATTR_SSL_CA => '/var/www/html/DigiCertGlobalRootG2.crt.pem'
);
$db = new PDO('mysql:host=mydemoserver.mysql.database.chinacloudapi.cn;port=3306;dbname=databasename', 'myadmin', 'yourpassword', $options);

Python (MySQLConnector Python)

try:
    conn = mysql.connector.connect(user='myadmin',
                                   password='<password>',
                                   database='quickstartdb',
                                   host='mydemoserver.mysql.database.chinacloudapi.cn',
                                   ssl_ca='/var/www/html/DigiCertGlobalRootG2.crt.pem')
except mysql.connector.Error as err:
    print(err)

Python (PyMySQL)

conn = pymysql.connect(user='myadmin',
                       password='<password>',
                       database='quickstartdb',
                       host='mydemoserver.mysql.database.chinacloudapi.cn',
                       ssl={'ca': '/var/www/html/DigiCertGlobalRootG2.crt.pem'})

Django (PyMySQL)

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'quickstartdb',
        'USER': 'myadmin',
        'PASSWORD': 'yourpassword',
        'HOST': 'mydemoserver.mysql.database.chinacloudapi.cn',
        'PORT': '3306',
        'OPTIONS': {
            'ssl': {'ca': '/var/www/html/DigiCertGlobalRootG2.crt.pem'}
        }
    }
}

Ruby

client = Mysql2::Client.new(
        :host     => 'mydemoserver.mysql.database.chinacloudapi.cn',
        :username => 'myadmin',
        :password => 'yourpassword',
        :database => 'quickstartdb',
        :sslca => '/var/www/html/DigiCertGlobalRootG2.crt.pem'
    )

Golang

rootCertPool := x509.NewCertPool()
pem, _ := ioutil.ReadFile("/var/www/html/DigiCertGlobalRootG2.crt.pem")
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
    log.Fatal("Failed to append PEM.")
}
mysql.RegisterTLSConfig("custom", &tls.Config{RootCAs: rootCertPool})
var connectionString string
connectionString = fmt.Sprintf("%s:%s@tcp(%s:3306)/%s?allowNativePasswords=true&tls=custom",'myadmin' , 'yourpassword', 'mydemoserver.mysql.database.chinacloudapi.cn', 'quickstartdb')
db, _ := sql.Open("mysql", connectionString)

Java(适用于 Java 的 MySQL 连接器)

# generate truststore and keystore in code

String importCert = " -import "+
    " -alias mysqlServerCACert "+
    " -file " + ssl_ca +
    " -keystore truststore "+
    " -trustcacerts " +
    " -storepass password -noprompt ";
String genKey = " -genkey -keyalg rsa " +
    " -alias mysqlClientCertificate -keystore keystore " +
    " -storepass password123 -keypass password " +
    " -dname CN=MS ";
sun.security.tools.keytool.Main.main(importCert.trim().split("\\s+"));
sun.security.tools.keytool.Main.main(genKey.trim().split("\\s+"));

# use the generated keystore and truststore

System.setProperty("javax.net.ssl.keyStore","path_to_keystore_file");
System.setProperty("javax.net.ssl.keyStorePassword","password");
System.setProperty("javax.net.ssl.trustStore","path_to_truststore_file");
System.setProperty("javax.net.ssl.trustStorePassword","password");

url = String.format("jdbc:mysql://%s/%s?serverTimezone=UTC&useSSL=true", 'mydemoserver.mysql.database.chinacloudapi.cn', 'quickstartdb');
properties.setProperty("user", 'myadmin');
properties.setProperty("password", 'yourpassword');
conn = DriverManager.getConnection(url, properties);

Java(适用于 Java 的 MariaDB 连接器)

# generate truststore and keystore in code

String importCert = " -import "+
    " -alias mysqlServerCACert "+
    " -file " + ssl_ca +
    " -keystore truststore "+
    " -trustcacerts " +
    " -storepass password -noprompt ";
String genKey = " -genkey -keyalg rsa " +
    " -alias mysqlClientCertificate -keystore keystore " +
    " -storepass password123 -keypass password " +
    " -dname CN=MS ";
sun.security.tools.keytool.Main.main(importCert.trim().split("\\s+"));
sun.security.tools.keytool.Main.main(genKey.trim().split("\\s+"));

# use the generated keystore and truststore

System.setProperty("javax.net.ssl.keyStore","path_to_keystore_file");
System.setProperty("javax.net.ssl.keyStorePassword","password");
System.setProperty("javax.net.ssl.trustStore","path_to_truststore_file");
System.setProperty("javax.net.ssl.trustStorePassword","password");

url = String.format("jdbc:mariadb://%s/%s?useSSL=true&trustServerCertificate=true", 'mydemoserver.mysql.database.chinacloudapi.cn', 'quickstartdb');
properties.setProperty("user", 'myadmin');
properties.setProperty("password", 'yourpassword');
conn = DriverManager.getConnection(url, properties);

.NET (MySqlConnector)

var builder = new MySqlConnectionStringBuilder
{
    Server = "mydemoserver.mysql.database.chinacloudapi.cn",
    UserID = "myadmin",
    Password = "yourpassword",
    Database = "quickstartdb",
    SslMode = MySqlSslMode.VerifyCA,
    SslCa = "DigiCertGlobalRootG2.crt.pem",
};
using (var connection = new MySqlConnection(builder.ConnectionString))
{
    connection.Open();
}

Node.js

var fs = require('fs');
var mysql = require('mysql');
const serverCa = [fs.readFileSync("/var/www/html/DigiCertGlobalRootG2.crt.pem", "utf8")];
var conn=mysql.createConnection({
    host:"mydemoserver.mysql.database.chinacloudapi.cn",
    user:"myadmin",
    password:"yourpassword",
    database:"quickstartdb",
    port:3306,
    ssl: {
        rejectUnauthorized: true,
        ca: serverCa
    }
});
conn.connect(function(err) {
  if (err) throw err;
});