26
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

MySQL 8.0のTLSを使った接続の暗号化について

Posted at

概要

TLSプロトコルを使用したMySQLクライアントとMySQLサーバ間(通信経路)の暗号化と接続方法について確認したメモです。

環境

  • Windows 10 Professional 1909
  • MySQL Community Server 8.0.18

参考

デフォルトの状態について

インストール直後の状態でオプションファイルなどの設定を変えなくても、デフォルトで接続の暗号化は有効になっています。(MySQL Community Server 8.0.18 (Zip Archive)確認)
またMySQL 8.0.16からTLSv1.3をサポートしています。

[6.3.2 Encrypted Connection TLS Protocols and Ciphers] (https://dev.mysql.com/doc/refman/8.0/en/encrypted-connection-protocols-ciphers.html)
Supported Connection TLS Protocols
MySQL supports encrypted connections using the TLSv1, TLSv1.1, TLSv1.2, and TLSv1.3 protocols, listed in order from less secure to more secure.
----------------------------------------------------------------------------------------------
MySQLは、TLSv1、TLSv1.1、TLSv1.2、およびTLSv1.3プロトコルを使用した暗号化接続をサポートします。これらのプロトコルは、安全性の低いものから高いものの順にリストされています。

クライアント側の確認

このコマンドでログインした場合

> mysql -u test_user -p

この接続の暗号化で使用しているTLSプロトコルと暗号スイートの確認は下記のコマンドで行えます。
この結果から使用しているTLSプロトコルはTLSv1.3、暗号スイートはTLS_AES_256_GCM_SHA384であることがわかります。

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
1 row in set (0.01 sec)

> show session status like 'ssl_version';
+---------------+---------+
| Variable_name | Value   |
+---------------+---------+
| Ssl_version   | TLSv1.3 |
+---------------+---------+
1 row in set (0.01 sec)

また、MySQLサーバがサポートしていて利用できる暗号スイートは以下のサーバステータス変数の値で確認できます。(結果が長いので省略しています)

> show session status like 'Ssl_cipher_list';
+-----------------+--------------------------------------------------------------------------------+
| Variable_name   | Value                                                                          |
+-----------------+--------------------------------------------------------------------------------+
| Ssl_cipher_list | TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256: ...|
+-----------------+--------------------------------------------------------------------------------+

次にこのコマンドで暗号化されていない接続でログインすると ([--ssl-mode] (https://dev.mysql.com/doc/refman/8.0/en/connection-options.html#option_general_ssl-mode)オプションについては後述します)

> mysql -u test_user -p --ssl-mode=DISABLED

この結果のようにSsl_cipherとSsl_versionの値はセットされません。(ただしパスワードはRSAキーペアファイルで SHA-256 ハッシュ化されるのでクリアテキストで送信されることはありません)

> show session status like 'ssl_cipher';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Ssl_cipher    |       |
+---------------+-------+
1 row in set (0.00 sec)

> show session status like 'ssl_version';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Ssl_version   |       |
+---------------+-------+
1 row in set (0.00 sec)

> show session status like 'Ssl_cipher_list';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| Ssl_cipher_list |       |
+-----------------+-------+
1 row in set (0.00 sec)

暗号スイートを明示的に選択する

暗号スイートを明示的に選択しなかった場合はTLS_AES_256_GCM_SHA384 が使用されましたが、--tls-ciphersuitesオプションで明示的に選択することができます。

> mysql -u test_user -p --tls-ciphersuites="TLS_AES_128_GCM_SHA256"
> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_128_GCM_SHA256 |
+---------------+------------------------+
1 row in set (0.07 sec)

> show session status like 'ssl_version';
+---------------+---------+
| Variable_name | Value   |
+---------------+---------+
| Ssl_version   | TLSv1.3 |
+---------------+---------+
1 row in set (0.00 sec)

サーバ側の確認

MySQLサーバでSSLがサポートされているかは[have_ssl] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_have_ssl)システム変数の値で確認できます。
(なお[have_openssl] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_have_openssl)というシステム変数もありますが、これはhave_sslの別名です)

  • YES: MySQLサーバでSSL接続がサポートされています。
  • DISABLED: MySQLサーバはSSL接続をサポートしていますがSSL接続の設定がされていません。
> show global variables like 'have_ssl';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_ssl      | YES   |
+---------------+-------+
1 row in set (0.05 sec)

SSL接続に必要な設定がされていない(若しくはMySQLサーバ起動時に[--skip-ssl] (https://dev.mysql.com/doc/refman/8.0/en/connection-options.html#option_general_ssl)オプションを指定した)状態だと、このように`DISABLED`になります。

> show global variables like 'have_ssl';
+---------------+----------+
| Variable_name | Value    |
+---------------+----------+
| have_ssl      | DISABLED |
+---------------+----------+
1 row in set (0.02 sec)

その他の設定は下記のシステム変数で確認できます。

> show global variables like 'ssl%';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| ssl_ca        | ca.pem          |
| ssl_capath    |                 |
| ssl_cert      | server-cert.pem |
| ssl_cipher    |                 |
| ssl_crl       |                 |
| ssl_crlpath   |                 |
| ssl_fips_mode | OFF             |
| ssl_key       | server-key.pem  |
+---------------+-----------------+
8 rows in set (0.00 sec)

> show global variables like 'tls%';
+------------------+-------------------------------+
| Variable_name    | Value                         |
+------------------+-------------------------------+
| tls_ciphersuites |                               |
| tls_version      | TLSv1,TLSv1.1,TLSv1.2,TLSv1.3 |
+------------------+-------------------------------+
2 rows in set (0.00 sec)

証明書と鍵ファイル

デフォルトでは、接続の暗号化で使用される証明書ファイルや秘密鍵ファイル、認証プラグインで使用されるRSAキーペアファイルがdataディレクトリにあります。
dataディレクトリにca.pemserver-cert.pemserver-key.pemがあると自動的に対応するシステム変数がセットされます。

ファイル名 用途 対応するシステム変数 クライアントで利用
ca.pem 自己署名CA証明書ファイル ssl_ca yes
ca-key.pem CA秘密鍵ファイル
client-cert.pem クライアント用の公開鍵証明書ファイル yes
client-key.pem クライアント用の秘密鍵ファイル yes
private_key.pem caching_sha2_password / sha256_password認証プラグインのRSA秘密鍵ファイル
public_key.pem caching_sha2_password / sha256_password認証プラグインのRSA公開鍵ファイル yes
server-cert.pem サーバ用の公開鍵証明書ファイル ssl_cert
server-key.pem サーバ用の秘密鍵ファイル ssl_key

これらのファイルはMySQLサーバ起動時にdataディレクトリに存在しなければ自動的に作成されますが、自動生成を止めたい場合やファイルの配置場所を変えたい場合は、次のオプションで制御できます。

[auto_generate_certs] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_auto_generate_certs)

データディレクトリにSSLキーと証明書ファイルがまだ存在しない場合、それらを自動生成するかどうかを制御します。

  • Command-Line Format: --auto-generate-certs[={OFF|ON}]
  • System Variable: auto_generate_certs

[ssl_ca] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_ssl_ca)

信頼できるSSL認証局のリストを含むファイルへのパス。

  • Command-Line Format: --ssl-ca=file_name
  • System Variable: ssl_ca

[ssl_capath] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_ssl_capath)

PEM形式の信頼できるSSL CA証明書を含むディレクトリへのパス。

  • Command-Line Format: --ssl-capath=dir_name
  • System Variable: ssl_capath

[ssl_cert] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_ssl_cert)

安全な接続の確立に使用するSSL証明書ファイルの名前。

  • Command-Line Format: --ssl-cert=file_name
  • System Variable: ssl_cert

[ssl_key] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_ssl_key)

安全な接続を確立するために使用するSSLキーファイルの名前。

  • Command-Line Format: --ssl-key=file_name
  • System Variable: ssl_key

[caching_sha2_password_auto_generate_rsa_keys] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_caching_sha2_password_auto_generate_rsa_keys)

RSA秘密/公開鍵ペアファイルがdataディレクトリに存在しない場合、自動生成するかどうかを制御します。

  • Command-Line Format: --caching-sha2-password-auto-generate-rsa-keys[={OFF|ON}]
  • System Variable: caching_sha2_password_auto_generate_rsa_keys

[caching_sha2_password_private_key_path] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_caching_sha2_password_private_key_path)

caching_sha2_password認証プラグインのRSA秘密鍵ファイルを指定します。デフォルトはprivate_key.pemです。

  • Command-Line Format: --caching-sha2-password-private-key-path=file_name
  • System Variable: caching_sha2_password_private_key_path

[caching_sha2_password_public_key_path] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_caching_sha2_password_public_key_path)

caching_sha2_password認証プラグインのRSA公開キーファイルを指定します。デフォルトはpublic_key.pemです。

  • Command-Line Format: --caching-sha2-password-public-key-path=file_name
  • System Variable: caching_sha2_password_public_key_path

[sha256_password_auto_generate_rsa_keys] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_sha256_password_auto_generate_rsa_keys)

RSA秘密/公開鍵ペアファイルがdataディレクトリに存在しない場合、自動生成するかどうかを制御します。

  • Command-Line Format: --sha256-password-auto-generate-rsa-keys[={OFF|ON}]
  • System Variable: sha256_password_auto_generate_rsa_keys

[sha256_password_private_key_path] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_sha256_password_private_key_path)

sha256_password認証プラグインのRSA秘密鍵ファイルを指定します。デフォルトはprivate_key.pemです。

  • Command-Line Format: --sha256-password-private-key-path=file_name
  • System Variable: sha256_password_private_key_path

[sha256_password_public_key_path] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_sha256_password_public_key_path)

sha256_password認証プラグインのRSA公開鍵ファイルを指定します。デフォルトはpublic_key.pemです。

  • Command-Line Format: --sha256-password-public-key-path=file_name
  • System Variable: sha256_password_public_key_path

設定例

以下は、作成したファイルをD:\\dev\\mysql-8.0.18-winx64\\secureに配置し、自動生成を行わない設定例です。
ちなみに、これらのファイルはmysql_ssl_rsa_setup.exeというツールで手動作成することができます。

auto_generate_certs = OFF

ssl_ca = D:\\dev\\mysql-8.0.18-winx64\\secure\\ca.pem
ssl_cert = D:\\dev\\mysql-8.0.18-winx64\\secure\\server-cert.pem
ssl_key = D:\\dev\\mysql-8.0.18-winx64\\secure\\server-key.pem

caching_sha2_password_auto_generate_rsa_keys = OFF

caching_sha2_password_private_key_path = D:\\dev\\mysql-8.0.18-winx64\\secure\\private_key.pem
caching_sha2_password_public_key_path = D:\\dev\\mysql-8.0.18-winx64\\secure\\public_key.pem

sha256_password_auto_generate_rsa_keys = OFF

sha256_password_private_key_path = D:\\dev\\mysql-8.0.18-winx64\\secure\\private_key.pem
sha256_password_public_key_path = D:\\dev\\mysql-8.0.18-winx64\\secure\\public_key.pem

証明書の有効期限

サーバの公開鍵証明書の有効期限は以下のサーバステータス変数の値で確認できます。この証明書はMySQLサーバが自動生成したもので期限は10年間 (3650日)です。

> show status like 'Ssl_server_not%';
+-----------------------+--------------------------+
| Variable_name         | Value                    |
+-----------------------+--------------------------+
| Ssl_server_not_after  | Jan 11 06:21:32 2030 GMT |
| Ssl_server_not_before | Jan 14 06:21:32 2020 GMT |
+-----------------------+--------------------------+
2 rows in set (0.02 sec)
  • Ssl_server_not_after: 証明書が有効な最後の日
  • Ssl_server_not_before: 証明書が有効な最初の日

opensslで確認する場合

> openssl x509 -text -noout -in /path/to/server-cert.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 2 (0x2)
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = MySQL_Server_8.0.18_Auto_Generated_CA_Certificate
        Validity
            Not Before: Jan 14 06:21:32 2020 GMT
            Not After : Jan 11 06:21:32 2030 GMT
        Subject: CN = MySQL_Server_8.0.18_Auto_Generated_Server_Certificate
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    <<< 省略 >>>
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
    Signature Algorithm: sha256WithRSAEncryption
         <<< 省略 >>>

認証プラグイン

MySQL 8.0のデフォルトの認証プラグインはcaching_sha2_passwordです。その他の認証プラグインにsha256_password(廃止予定)やmysql_native_passwordなどがあります。

MySQLサーバのSSL接続が無効になっているか、非暗号化接続でログインしようとすると以下のエラーが発生します。

> mysql -u test_user -p
ERROR 2061 (HY000): Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.

この場合は[--get-server-public-key] (https://dev.mysql.com/doc/refman/8.0/en/connection-options.html#option_general_get-server-public-key)でRSA公開鍵ファイルをMySQLサーバから取得するか

> mysql -u test_user -p --get-server-public-key

[--server-public-key-path=file_name] (https://dev.mysql.com/doc/refman/8.0/en/connection-options.html#option_general_server-public-key-path)で任意の場所にあるRSA公開鍵ファイルを指定してログインします。

> mysql -u test_user -p --server-public-key-path=/path/to/public_key.pem

なお、一度認証が成功するとキャッシュされるので、次からは--get-server-public-key--server-public-key-pathは不要になりますが、以下の操作時に全アカウントのキャッシュがクリアされます。

  • FLUSH PRIVILEGESの実行後
  • MySQLサーバのシャットダウン

また、以下の操作ではそのアカウントのキャッシュがクリアされます。

  • アカウント作成後
  • アカウントのパスワード変更後
  • アカウントのリネーム後

暗号化接続の確認

SSL/TLS関連のオプションが異なる5種のテストユーザを作成し、暗号化接続の方法にどのような違いがあるか確認します。

テストユーザ

REQUIRE句

ユーザにSSL/TLS関連のオプションを指定するにはREQUIRE句を使用します。

意味
NONE (default) デフォルトで暗号化された接続を試みる。暗号化接続ができなかった場合は非暗号化の接続を試みる。 非暗号化接続ができなかった場合は接続は失敗する。
SSL デフォルトで暗号化された接続を試みる。暗号化接続ができなかった場合は接続は失敗する。
X509 有効なクライアント証明書を提示する必要がある。そのために--ssl-keyおよび--ssl-certオプションでクライアントの秘密鍵と証明書ファイルを指定する必要がある。
-ssl-caの指定はオプション。
CIPHER 'cipher' 特定の暗号方式でのみ接続を許可する。

テストユーザの作成

CREATE USER 'test_user'@'localhost'  IDENTIFIED BY 'test_user'; /*REQUIRE NONE*/
CREATE USER 'test_user2'@'localhost' IDENTIFIED BY 'test_user2' REQUIRE SSL;
CREATE USER 'test_user3'@'localhost' IDENTIFIED BY 'test_user3' REQUIRE X509;
CREATE USER 'test_user4'@'localhost' IDENTIFIED BY 'test_user4' REQUIRE CIPHER 'TLS_AES_128_GCM_SHA256';     /*TLSv1.3*/
CREATE USER 'test_user5'@'localhost' IDENTIFIED BY 'test_user5' REQUIRE CIPHER 'DHE-RSA-AES128-GCM-SHA256';  /*TLSv1.2*/
> SELECT host,user,ssl_type,ssl_cipher,plugin FROM mysql.user;
+-----------+------------------+-----------+---------------------------+-----------------------+
| host      | user             | ssl_type  | ssl_cipher                | plugin                |
+-----------+------------------+-----------+---------------------------+-----------------------+
| localhost | mysql.infoschema |           |                           | caching_sha2_password |
| localhost | mysql.session    |           |                           | caching_sha2_password |
| localhost | mysql.sys        |           |                           | caching_sha2_password |
| localhost | root             |           |                           | caching_sha2_password |
| localhost | test_user        |           |                           | caching_sha2_password |
| localhost | test_user2       | ANY       |                           | caching_sha2_password |
| localhost | test_user3       | X509      |                           | caching_sha2_password |
| localhost | test_user4       | SPECIFIED | TLS_AES_128_GCM_SHA256    | caching_sha2_password |
| localhost | test_user5       | SPECIFIED | DHE-RSA-AES128-GCM-SHA256 | caching_sha2_password |
+-----------+------------------+-----------+---------------------------+-----------------------+
9 rows in set (0.00 sec)

[--ssl-mode=mode] (https://dev.mysql.com/doc/refman/8.0/en/connection-options.html#option_general_ssl-mode)別の接続確認

暗号化接続のモードを指定します。このオプションはクライアント専用です。

意味 (Google翻訳)
DISABLED 暗号化されていない接続を確立します。
PREFERRED (default) サーバが暗号化された接続をサポートしている場合は暗号化された接続を確立し、暗号化された接続を確立できない場合は暗号化されていない接続にフォールバックします。
REQUIRED サーバが暗号化された接続をサポートしている場合、暗号化された接続を確立します。 暗号化された接続を確立できない場合、接続の試行は失敗します。
VERIFY_CA REQUIREDに似ていますが、構成されたCA証明書に対してサーバー認証局(CA)証明書をさらに検証します。 有効な一致するCA証明書が見つからない場合、接続の試行は失敗します。
VERIFY_IDENTITY VERIFY_CAに似ていますが、サーバーがクライアントに送信する証明書のIDに対してサーバーへの接続にクライアントが使用するホスト名を確認することにより、さらにホスト名のID検証を実行します。
  • --ssl-modeを指定せず且つ--ssl-caまたは--ssl-capathを指定した場合、--ssl-mode=VERIFY_CAを指定したのと同じ挙動になります。
  • --ssl-mode=VERIFY_CAを指定した場合、--ssl-caを指定する必要があります。

--ssl-mode=PREFERRED

PREFERREDはデフォルトなので以下の例では明示的に指定していません。

REQUIRE NONE

デフォルトで暗号化接続を行います。このパターンでは暗号化接続ができなかった(若しくはしなかった)場合、非暗号化接続を行います。

> mysql -u test_user -p
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
1 row in set (0.00 sec)

REQUIRE SSL

デフォルトで暗号化接続を行います。このパターンでは暗号化接続ができなかった場合は接続は失敗します。

> mysql -u test_user2 -p
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
1 row in set (0.00 sec)

REQUIRE X509

X509では少なくとも--ssl-cert--ssl-keyでクライアントの公開鍵証明書ファイルと秘密鍵ファイルを提示する必要があります。--ssl-caはオプションですが指定する方がより安全です。

// --ssl-cert,--ssl-keyの指定が無い場合はエラー
> mysql -u test_user3 -p
ERROR 1045 (28000): Access denied for user 'test_user3'@'localhost' (using password: YES)

> mysql -u test_user3 -p --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
1 row in set (0.00 sec)

REQUIRE CIPHER 'TLS_AES_128_GCM_SHA256' (TLSv1.3)

特定の暗号スイートが必要な場合は--tls-ciphersuitesで指定する必要があります。
なお--tls-ciphersuitesはTLSv1.3の暗号スイートを指定するオプションで、TLSv1.2以前のものは--ssl-cipherで指定します。

// --ssl-cert, --ssl-key, --tls-ciphersuitesの指定が無い場合はエラー
> mysql -u test_user4 -p
ERROR 1045 (28000): Access denied for user 'test_user4'@'localhost' (using password: YES)

// --tls-ciphersuitesの指定が無い場合はエラー
> mysql -u test_user4 -p --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem
ERROR 1045 (28000): Access denied for user 'test_user4'@'localhost' (using password: YES)

// --ssl-cert,--ssl-keyの指定が無い場合はエラー
> mysql -u test_user4 -p --tls-ciphersuites="TLS_AES_128_GCM_SHA256"
ERROR 1045 (28000): Access denied for user 'test_user4'@'localhost' (using password: YES)

> mysql -u test_user4 -p --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem --tls-ciphersuites="TLS_AES_128_GCM_SHA256"
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_128_GCM_SHA256 |
+---------------+------------------------+
1 row in set (0.00 sec)

[tls_ciphersuites] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_tls_ciphersuites)

暗号化接続を許可するTLSv1.3のTLSプロトコルを使用する暗号スイートのリスト。

  • Command-Line Format: --tls-ciphersuites=ciphersuite_list
  • System Variable: tls_ciphersuites

REQUIRE CIPHER 'DHE-RSA-AES128-GCM-SHA256' (TLSv1.2)

暗号スイートがTLSV1.2の場合は--ssl-cipherで指定します。さらに--tls-versionでプロトコルのバージョンを指定する必要があります。

// --ssl-cert, --ssl-key, --ssl-cipher, --tls-versionの指定が無い場合はエラー
> mysql -u test_user5 -p
ERROR 1045 (28000): Access denied for user 'test_user5'@'localhost' (using password: YES)

// --ssl-cipher, --tls-versionの指定が無い場合はエラー
> mysql -u test_user5 -p --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem
ERROR 1045 (28000): Access denied for user 'test_user5'@'localhost' (using password: YES)

// --ssl-cert, --ssl-keyの指定が無い場合はエラー
> mysql -u test_user5 -p --ssl-cipher=DHE-RSA-AES128-GCM-SHA256 --tls-version="TLSv1.2"
ERROR 1045 (28000): Access denied for user 'test_user5'@'localhost' (using password: YES)

// 別の暗号スイートを指定した場合はエラー
> mysql -u test_user5 -p --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem --tls-ciphersuites="TLS_AES_128_GCM_SHA256"
ERROR 1045 (28000): Access denied for user 'test_user5'@'localhost' (using password: YES)

> mysql -u test_user5 -p --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem --ssl-cipher=DHE-RSA-AES128-GCM-SHA256 --tls-version="TLSv1.2"
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+---------------------------+
| Variable_name | Value                     |
+---------------+---------------------------+
| Ssl_cipher    | DHE-RSA-AES128-GCM-SHA256 |
+---------------+---------------------------+
1 row in set (0.00 sec)

> show session status like 'ssl_version';
+---------------+---------+
| Variable_name | Value   |
+---------------+---------+
| Ssl_version   | TLSv1.2 |
+---------------+---------+
1 row in set (0.00 sec)

[ssl_cipher] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_ssl_cipher)

暗号化接続を許可するTLSv1.2までのTLSプロトコルを使用する暗号スイートのリスト。

  • Command-Line Format: --ssl-cipher=name
  • System Variable: ssl_cipher

[tls_version] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_tls_version)

暗号化接続を許可するプロトコルのリスト(カンマ区切り)。

  • Command-Line Format: --tls-version=protocol_list
  • System Variable: tls_version

--ssl-mode=DISABLED

REQUIRE NONE

このパターンは非暗号化接続でもRSAキーペアファイルでパスワード交換ができればログインできます。

> mysql -u test_user -p --ssl-mode=DISABLED --get-server-public-key
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| Ssl_cipher    |       |
+---------------+-------+
1 row in set (0.00 sec)

REQUIRE SSL

このパターンは暗号化接続が必須なので、暗号化接続ができなければ接続は失敗します。

> mysql -u test_user2 -p --ssl-mode=DISABLED --get-server-public-key
ERROR 1045 (28000): Access denied for user 'test_user2'@'localhost' (using password: YES)

REQUIRE X509、REQUIRE CIPHERも同様なので結果は省略します。

--ssl-mode=REQUIRED

REQUIRE NONE

このパターンは暗号化接続が必須です。暗号化接続ができれば下記のようにログインは成功します。

> mysql -u test_user -p --ssl-mode=REQUIRED
// ログイン成功

+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
1 row in set (0.00 sec)

サーバ側が暗号化接続をサポートしていない場合はエラーになります。

> mysql -u test_user -p --ssl-mode=REQUIRED
ERROR 2026 (HY000): SSL connection error: SSL is required but the server doesn't support it

REQUIRE SSL

> mysql -u test_user2 -p --ssl-mode=REQUIRED
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
1 row in set (0.00 sec)

REQUIRE X509

> mysql -u test_user3 -p --ssl-mode=REQUIRED --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
1 row in set (0.00 sec)

REQUIRE CIPHER 'TLS_AES_128_GCM_SHA256' (TLSv1.3)

> mysql -u test_user4 -p --ssl-mode=REQUIRED --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem --tls-ciphersuites="TLS_AES_128_GCM_SHA256"
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_128_GCM_SHA256 |
+---------------+------------------------+
1 row in set (0.00 sec)

REQUIRE CIPHER 'DHE-RSA-AES128-GCM-SHA256' (TLSv1.2)

> mysql -u test_user5 -p --ssl-mode=REQUIRED --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem --ssl-cipher="DHE-RSA-AES128-GCM-SHA256" --tls-version="TLSv1.2"
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+---------------------------+
| Variable_name | Value                     |
+---------------+---------------------------+
| Ssl_cipher    | DHE-RSA-AES128-GCM-SHA256 |
+---------------+---------------------------+
1 row in set (0.00 sec)

> show session status like 'ssl_version';
+---------------+---------+
| Variable_name | Value   |
+---------------+---------+
| Ssl_version   | TLSv1.2 |
+---------------+---------+
1 row in set (0.00 sec) 

--ssl-mode=VERIFY_CA

このモードでは、--ssl-caオプションでCA証明書を指定する必要があります。

REQUIRE NONE

// --ssl-caの指定が無い場合はエラー 
> mysql -u test_user -p --ssl-mode=VERIFY_CA
ERROR 2026 (HY000): SSL connection error: CA certificate is required if ssl-mode is VERIFY_CA or VERIFY_IDENTITY

> mysql -u test_user -p --ssl-mode=VERIFY_CA --ssl-ca=/path/to/ca.pem
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
1 row in set (0.00 sec)

REQUIRE SSL

// --ssl-caの指定が無い場合はエラー
> mysql -u test_user2 -p --ssl-mode=VERIFY_CA
ERROR 2026 (HY000): SSL connection error: CA certificate is required if ssl-mode is VERIFY_CA or VERIFY_IDENTITY

> mysql -u test_user2 -p --ssl-mode=VERIFY_CA --ssl-ca=/path/to/ca.pem
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
1 row in set (0.00 sec)

REQUIRE X509

このパターンではCA証明書に加え、クライアント証明書と秘密鍵が必要です。

// --ssl-cert, --ssl-keyの指定が無い場合はエラー
> mysql -u test_user3 -p --ssl-mode=VERIFY_CA --ssl-ca=/path/to/ca.pem
ERROR 1045 (28000): Access denied for user 'test_user3'@'localhost' (using password: YES)

> mysql -u test_user3 -p --ssl-mode=VERIFY_CA --ssl-ca=/path/to/ca.pem --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_256_GCM_SHA384 |
+---------------+------------------------+
1 row in set (0.00 sec)

REQUIRE CIPHER 'TLS_AES_128_GCM_SHA256' (TLSv1.3)

// --ssl-cert, --ssl-keyの指定が無い場合はエラー
> mysql -u test_user4 -p --ssl-mode=VERIFY_CA --ssl-ca=/path/to/ca.pem --tls-ciphersuites="TLS_AES_128_GCM_SHA256"
ERROR 1045 (28000): Access denied for user 'test_user4'@'localhost' (using password: YES)

> mysql -u test_user4 -p --ssl-mode=VERIFY_CA --ssl-ca=/path/to/ca.pem --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem --tls-ciphersuites="TLS_AES_128_GCM_SHA256"
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+------------------------+
| Variable_name | Value                  |
+---------------+------------------------+
| Ssl_cipher    | TLS_AES_128_GCM_SHA256 |
+---------------+------------------------+
1 row in set (0.00 sec)

REQUIRE CIPHER 'DHE-RSA-AES128-GCM-SHA256' (TLSv1.2)

// --ssl-cert, --ssl-keyの指定が無い場合はエラー
> mysql -u test_user5 -p --ssl-mode=VERIFY_CA --ssl-ca=/path/to/ca.pem --ssl-cipher="DHE-RSA-AES128-GCM-SHA256" --tls-version="TLSv1.2"
ERROR 1045 (28000): Access denied for user 'test_user5'@'localhost' (using password: YES)

> mysql -u test_user5 -p --ssl-mode=VERIFY_CA --ssl-ca=/path/to/ca.pem --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem --ssl-cipher="DHE-RSA-AES128-GCM-SHA256" --tls-version="TLSv1.2"
// ログイン成功

> show session status like 'ssl_cipher';
+---------------+---------------------------+
| Variable_name | Value                     |
+---------------+---------------------------+
| Ssl_cipher    | DHE-RSA-AES128-GCM-SHA256 |
+---------------+---------------------------+
1 row in set (0.00 sec)

> show session status like 'ssl_version';
+---------------+---------+
| Variable_name | Value   |
+---------------+---------+
| Ssl_version   | TLSv1.2 |
+---------------+---------+
1 row in set (0.00 sec)

--ssl-mode=VERIFY_IDENTITY

このモードは、下記に引用した通りサーバが自動生成したか、mysql_ssl_rsa_setupツールで手動生成した自己署名証明書では機能しないので動作検証は省略します。

[--ssl-mode=mode] (https://dev.mysql.com/doc/refman/5.7/en/connection-options.html#option_general_ssl-mode)
Host name identity verification with VERIFY_IDENTITY does not work with self-signed certificates that are created automatically by the server or manually using mysql_ssl_rsa_setup (see Section 6.3.3.1, “Creating SSL and RSA Certificates and Keys using MySQL”). Such self-signed certificates do not contain the server name as the Common Name value.
-------------------------------------------------------------------------------------------
VERIFY_IDENTITYを使用したホスト名ID検証は、サーバーによって自動的に作成されるか、mysql_ssl_rsa_setupを使用して手動で作成される自己署名証明書では機能しません(セクション6.3.3.1「MySQLを使用したSSLおよびRSA証明書とキーの作成」を参照)。 このような自己署名証明書には、共通名の値としてサーバー名が含まれていません。

サーバ側の設定で暗号化接続を必須とする

オプションファイルにrequire_secure_transportを設定すると、ユーザーのSSL/TLS関連のオプションにかからわらず非暗号化接続は許可されません。

require_secure_transport = ON

[require_secure_transport] (https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_require_secure_transport)

この変数を有効にすると、サーバーはSSLを使用するTCP/IP接続、またはソケットファイル(Unix)、または共有メモリ(Windows)を使用する接続のみを許可します。

  • Command-Line Format: --require-secure-transport[={OFF|ON}]
  • System Variable: require_secure_transport

このように非暗号化接続でログインしようとすると接続は失敗します。

> mysql -u test_user -p --ssl-mode=DISABLED --get-server-public-key
ERROR 3159 (HY000): Connections using insecure transport are prohibited while --require_secure_transport=ON.

特定の暗号スイートまたはTLSプロトコルのみを許可する

オプションファイルにtls_ciphersuites (TLSv1.3)ssl_cipher ( ~ TLSv1.2)tls_versionを設定すると、その条件の接続のみを許可します。
以下の設定ではプロトコルバージョンがTLSv1.2か、TLSv1.3かつ暗号スイートがTLS_AES_256_GCM_SHA384の場合のみを許可します。

tls_ciphersuites = TLS_AES_256_GCM_SHA384
tls_version = TLSv1.2,TLSv1.3
> show global variables like 'tls%';
+------------------+------------------------+
| Variable_name    | Value                  |
+------------------+------------------------+
| tls_ciphersuites | TLS_AES_256_GCM_SHA384 |
| tls_version      | TLSv1.2,TLSv1.3        |
+------------------+------------------------+
2 rows in set (0.03 sec)

--ssl-mode=PREFERRED

上記の設定で且つ--ssl-modeがPREFERRED (default)の場合の各テストユーザの接続がどうなるか確認します。

REQUIRE NONE

> mysql -u test_user -p
// ログイン成功

REQUIRE SSL

> mysql -u test_user2 -p
// ログイン成功

REQUIRE X509

> mysql -u test_user3 -p --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem
// ログイン成功

REQUIRE CIPHER 'TLS_AES_128_GCM_SHA256' (TLSv1.3)

暗号スイートが条件を満たしていないので接続は許可されません。

> mysql -u test_user4 -p --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem --tls-ciphersuites="TLS_AES_128_GCM_SHA256"
ERROR 2026 (HY000): SSL connection error: error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

REQUIRE CIPHER 'DHE-RSA-AES128-GCM-SHA256' (TLSv1.2)

TLSプロトコルがTLSv1.2という条件を満たしているので接続は許可されます。

> mysql -u test_user5 -p --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem --ssl-cipher="DHE-RSA-AES128-GCM-SHA256" --tls-version="TLSv1.2"
// ログイン成功

しかし、オプションファイルでtls_versionを下記のようにTLSv1.3とした場合、

tls_version = TLSv1.3

このユーザの接続は許可されなくなります。

> mysql -u test_user5 -p --ssl-cert=/path/to/client-cert.pem --ssl-key=/path/to/client-key.pem --ssl-cipher="DHE-RSA-AES128-GCM-SHA256" --tls-version="TLSv1.2"
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2026 (HY000): SSL connection error: error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version

補足

暗号スイート (Cipher Suite)

TLSv1.3で利用できる暗号スイート

[RFC 8446] (https://tools.ietf.org/html/rfc8446)で定義。

  • TLS_AES_256_GCM_SHA384
  • TLS_AES_128_GCM_SHA256
  • TLS_AES_128_CCM_8_SHA256
  • TLS_AES_128_CCM_SHA256
  • TLS_CHACHA20_POLY1305_SHA256
> openssl version
OpenSSL 1.1.1d  10 Sep 2019
> openssl ciphers -V
          0x13,0x02 - TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
          0x13,0x03 - TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256) Mac=AEAD
          0x13,0x01 - TLS_AES_128_GCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(128) Mac=AEAD

//... 省略...

先頭の2つの16進数は、暗号スイートセレクターコード(The cryptographic suite selector code)という、暗号スイートを識別するコード。

[Command Options for Encrypted Connections] (https://dev.mysql.com/doc/refman/8.0/en/connection-options.html#encrypted-connection-options)

Option Name System Variable Scope Type
--get-server-public-key
have_openssl
have_ssl Global String
--server-public-key-path
--skip-ssl
--ssl
--ssl-ca ssl_ca Global File name
--ssl-capath ssl_capath Global Directory name
--ssl-cert ssl_cert Global File name
--ssl-cipher ssl_cipher Global String
--ssl-crl ssl_crl Global File name
--ssl-crlpath ssl_crlpath Global Directory name
--ssl-fips-mode ssl_fips_mode Global Enumeration
--ssl-key ssl_key Global File name
--ssl-mode
--tls-ciphersuites tls_ciphersuites Global String
--tls-version tls_version Global String

mysql_ssl_rsa_setup.exe

> mysql_ssl_rsa_setup.exe -v --datadir=D:\dev\mysql-8.0.18-winx64\secure
2020-01-14 00:28:26 [NOTE]    Destination directory: D:\dev\mysql-8.0.18-winx64\secure
2020-01-14 00:28:26 [NOTE]    Executing : openssl version
OpenSSL 1.1.1d  10 Sep 2019
2020-01-14 00:28:26 [NOTE]    Executing : openssl req -newkey rsa:2048 -days 3650 -nodes -keyout ca-key.pem -subj /CN=MySQL_Server_8.0.18_Auto_Generated_CA_Certificate -out ca-req.pem && openssl rsa -in ca-key.pem -out ca-key.pem
Ignoring -days; not generating a certificate
Generating a RSA private key
......................................................................................+++++
..........+++++
writing new private key to 'ca-key.pem'
-----
writing RSA key
2020-01-14 00:28:27 [NOTE]    Executing : openssl x509 -sha256 -days 3650 -extfile cav3.ext -set_serial 1 -req -in ca-req.pem -signkey ca-key.pem -out ca.pem
Signature ok
subject=CN = MySQL_Server_8.0.18_Auto_Generated_CA_Certificate
Getting Private key
2020-01-14 00:28:27 [NOTE]    Executing : openssl req -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -subj /CN=MySQL_Server_8.0.18_Auto_Generated_Server_Certificate -out server-req.pem && openssl rsa -in server-key.pem -out server-key.pem
Ignoring -days; not generating a certificate
Generating a RSA private key
......................+++++
........................................................................................+++++
writing new private key to 'server-key.pem'
-----
writing RSA key
2020-01-14 00:28:27 [NOTE]    Executing : openssl x509 -sha256 -days 3650 -extfile certv3.ext -set_serial 2 -req -in server-req.pem -CA ca.pem -CAkey ca-key.pem -out server-cert.pem
Signature ok
subject=CN = MySQL_Server_8.0.18_Auto_Generated_Server_Certificate
Getting CA Private Key
2020-01-14 00:28:27 [NOTE]    Executing : openssl req -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem -subj /CN=MySQL_Server_8.0.18_Auto_Generated_Client_Certificate -out client-req.pem && openssl rsa -in client-key.pem -out client-key.pem
Ignoring -days; not generating a certificate
Generating a RSA private key
.............................................+++++
....+++++
writing new private key to 'client-key.pem'
-----
writing RSA key
2020-01-14 00:28:27 [NOTE]    Executing : openssl x509 -sha256 -days 3650 -extfile certv3.ext -set_serial 3 -req -in client-req.pem -CA ca.pem -CAkey ca-key.pem -out client-cert.pem
Signature ok
subject=CN = MySQL_Server_8.0.18_Auto_Generated_Client_Certificate
Getting CA Private Key
2020-01-14 00:28:27 [NOTE]    Executing : openssl verify -CAfile ca.pem server-cert.pem client-cert.pem
server-cert.pem: OK
client-cert.pem: OK
2020-01-14 00:28:28 [NOTE]    Executing : openssl genrsa  -out private_key.pem 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
..................................................................................................................................+++++
.................................................................................+++++
e is 65537 (0x010001)
2020-01-14 00:28:28 [NOTE]    Executing : openssl rsa -in private_key.pem -pubout -out public_key.pem
writing RSA key
2020-01-14 00:28:28 [NOTE]    Success!

mysql_ssl_rsa_setup.exeを実行すると、実際には下記のopensslコマンドが実行されています。

# version check
> openssl version
OpenSSL 1.1.1d  10 Sep 2019
# Create CA certificate
> openssl req -newkey rsa:2048 -days 3650 -nodes -keyout ca-key.pem -subj /CN=MySQL_Server_8.0.18_Auto_Generated_CA_Certificate -out ca-req.pem && openssl rsa -in ca-key.pem -out ca-key.pem

> openssl x509 -sha256 -days 3650 -extfile cav3.ext -set_serial 1 -req -in ca-req.pem -signkey ca-key.pem -out ca.pem
  • ca-key.pem
  • ca.pem
# Create server certificate
> openssl req -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem -subj /CN=MySQL_Server_8.0.18_Auto_Generated_Server_Certificate -out server-req.pem && openssl rsa -in server-key.pem -out server-key.pem

> openssl x509 -sha256 -days 3650 -extfile certv3.ext -set_serial 2 -req -in server-req.pem -CA ca.pem -CAkey ca-key.pem -out server-cert.pem
  • server-key.pem (private key)
  • server-cert.pem (public key)
# Create client certificate
> openssl req -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem -subj /CN=MySQL_Server_8.0.18_Auto_Generated_Client_Certificate -out client-req.pem && openssl rsa -in client-key.pem -out client-key.pem

# client-cert.pem = public key, client-key.pem = private key
> openssl x509 -sha256 -days 3650 -extfile certv3.ext -set_serial 3 -req -in client-req.pem -CA ca.pem -CAkey ca-key.pem -out client-cert.pem
  • client-key.pem (private key)
  • client-cert.pem (public key)
# Verify certificates
> openssl verify -CAfile ca.pem server-cert.pem client-cert.pem
# Create private RSA key pair
> openssl genrsa -out private_key.pem 2048

# Create public RSA key pair
> openssl rsa -in private_key.pem -pubout -out public_key.pem
  • private_key.pem
  • public_key.pem

クラウドサービス

26
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?