Ubuntu18.04でMySQLのSSL/TLSを構成する方法
序章
MySQLは、最も人気のあるオープンソースのリレーショナルデータベース管理システムです。 最新のパッケージマネージャーは、MySQLを起動して実行する際の摩擦を軽減しましたが、インストール後に実行する必要のある構成がさらにいくつかあります。 余分な時間を費やす最も重要な側面の1つは、セキュリティです。
デフォルトでは、MySQLはローカル接続、またはMySQLがインストールされているのと同じマシンから発信された接続のみを受け入れるように構成されています。 リモートの場所からMySQLデータベースにアクセスする必要がある場合は、安全にアクセスすることが重要です。 このガイドでは、SSL/TLS暗号化を使用したリモート接続を受け入れるようにUbuntu18.04でMySQLを構成する方法を示します。
前提条件
このガイドを完了するには、次のものが必要です。
- 2台のUbuntu18.04サーバー。 これらのサーバーの1つをMySQLサーバーとして使用し、もう1つをクライアントマシンとして使用します。
sudo
権限を持つ非rootユーザーを作成し、これらの各サーバーでufw
を使用してファイアウォールを有効にします。 Ubuntu 18.04初期サーバーセットアップガイドに従って、両方のサーバーを適切な初期状態にします。 - マシンの1つに、MySQLサーバーをインストールして構成します。 これを行うには、Ubuntu18.04用のMySQLインストールガイドのステップ1から3に従ってください。 このガイドに従うときは、ガイドのステップ3 で説明されているように、 root MySQLユーザーをパスワードで認証するように構成してください。これは、を使用してMySQLに接続するために必要です。ローカルUnixソケットではなくTCP。
このガイド全体を通して、MySQLをインストールしたサーバーは MySQLサーバーと呼ばれ、このマシンで実行する必要のあるコマンドは次のように青い背景で表示されることに注意してください。
-
同様に、このガイドでは他のサーバーを MySQLクライアントと呼び、そのマシンで実行する必要のあるコマンドはすべて赤い背景で表示されます。
-
混乱を避けるために、このチュートリアルに従うときは、これらを覚えておいてください。
ステップ1—MySQLの現在のSSL/TLSステータスを確認する
構成を変更する前に、MySQLサーバーインスタンスの現在のSSL/TLSステータスを確認できます。
次のコマンドを使用して、 rootMySQLユーザーとしてMySQLセッションを開始します。 このコマンドには、-p
オプションが含まれています。このオプションは、mysql
に、ログインするためにパスワードの入力を求めるように指示します。 また、接続するホストを指定するために使用される-h
オプションも含まれています。 この場合は、127.0.0.1
を指します。これは、localhostとも呼ばれるIPv4ループバックインターフェイスです。 これにより、クライアントはローカルソケットファイルを使用する代わりにTCPに接続するように強制されます。 MySQLは、デフォルトでUnixソケットファイルを介して接続を試みます。 これらの接続はローカルでのみ行うことができ、TCP接続が実行する必要のあるすべてのチェックとルーティング操作を実行する必要がないため、これは一般的に高速で安全です。 ただし、TCPで接続すると、接続のSSLステータスを確認できます。
- mysql -u root -p -h 127.0.0.1
MySQLのインストールおよび構成時に選択したMySQLrootパスワードの入力を求められます。 入力すると、インタラクティブなMySQLセッションに移動します。
次のコマンドを発行してSSL/TLS変数の状態を表示します。
- SHOW VARIABLES LIKE '%ssl%';
Output+---------------+----------+
| Variable_name | Value |
+---------------+----------+
| have_openssl | DISABLED |
| have_ssl | DISABLED |
| ssl_ca | |
| ssl_capath | |
| ssl_cert | |
| ssl_cipher | |
| ssl_crl | |
| ssl_crlpath | |
| ssl_key | |
+---------------+----------+
9 rows in set (0.01 sec)
have_openssl
変数とhave_ssl
変数は、どちらもDISABLED
としてマークされています。 これは、SSL機能がサーバーにコンパイルされているが、まだ有効になっていないことを意味します。
これを確認するには、現在の接続のステータスを確認してください。
- \s
Output--------------
mysql Ver 14.14 Distrib 5.7.26, for Linux (x86_64) using EditLine wrapper
Connection id: 9
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.7.26-0ubuntu0.18.04.1 (Ubuntu)
Protocol version: 10
Connection: 127.0.0.1 via TCP/IP
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
TCP port: 3306
Uptime: 40 min 11 sec
Threads: 1 Questions: 33 Slow queries: 0 Opens: 113 Flush tables: 1 Open tables: 106 Queries per second avg: 0.013
--------------
上記の出力が示すように、TCPを介して接続している場合でも、SSLは現在この接続に使用されていません。
終了したら、現在のMySQLセッションを閉じます。
- exit
MySQLサーバーがSSLを使用していないことを確認したので、次のステップに進み、いくつかの証明書とキーを生成してSSLを有効にするプロセスを開始します。 これらにより、サーバーとクライアントが互いに安全に通信できるようになります。
ステップ2— SSL/TLS証明書とキーの生成
MySQLへのSSL接続を有効にするには、最初に適切な証明書とキーファイルを生成する必要があります。 MySQLバージョン5.7以降は、このプロセスを簡素化するのに役立つmysql_ssl_rsa_setup
と呼ばれるユーティリティを提供します。 前提条件のMySQLチュートリアルに従ってインストールしたMySQLのバージョンにはこのユーティリティが含まれているため、ここではこれを使用して必要なファイルを生成します。
MySQLプロセスは生成されたファイルを読み取ることができる必要があるため、--uid
オプションを使用して、生成されたファイルを所有する必要があるシステムユーザーとしてmysql
を宣言します。
- sudo mysql_ssl_rsa_setup --uid=mysql
これにより、次のような出力が生成されます。
OutputGenerating a 2048 bit RSA private key
.+++
..........+++
writing new private key to 'ca-key.pem'
-----
Generating a 2048 bit RSA private key
........................................+++
............+++
writing new private key to 'server-key.pem'
-----
Generating a 2048 bit RSA private key
.................................+++
............................................................+++
writing new private key to 'client-key.pem'
-----
これらの新しいファイルは、デフォルトで/var/lib/mysql
にあるMySQLのデータディレクトリに保存されます。 次のように入力して、生成されたファイルを確認します。
- sudo find /var/lib/mysql -name '*.pem' -ls
Output 258930 4 -rw-r--r-- 1 mysql mysql 1107 May 3 16:43 /var/lib/mysql/client-cert.pem
258919 4 -rw-r--r-- 1 mysql mysql 451 May 3 16:43 /var/lib/mysql/public_key.pem
258925 4 -rw------- 1 mysql mysql 1675 May 3 16:43 /var/lib/mysql/server-key.pem
258927 4 -rw-r--r-- 1 mysql mysql 1107 May 3 16:43 /var/lib/mysql/server-cert.pem
258922 4 -rw------- 1 mysql mysql 1675 May 3 16:43 /var/lib/mysql/ca-key.pem
258928 4 -rw------- 1 mysql mysql 1675 May 3 16:43 /var/lib/mysql/client-key.pem
258924 4 -rw-r--r-- 1 mysql mysql 1107 May 3 16:43 /var/lib/mysql/ca.pem
258918 4 -rw------- 1 mysql mysql 1679 May 3 16:43 /var/lib/mysql/private_key.pem
これらのファイルは、認証局(「ca」で始まる)、MySQLサーバープロセス(「server」で始まる)、およびMySQLクライアント(「client」で始まる)のキーと証明書のペアです。 さらに、private_key.pem
およびpublic_key.pem
ファイルは、SSLを使用していないときにパスワードを安全に転送するためにMySQLによって使用されます。
必要な証明書とキーファイルが揃ったので、引き続きMySQLインスタンスでSSLの使用を有効にします。
ステップ3—MySQLサーバーでSSL接続を有効にする
最新バージョンのMySQLは、サーバーが起動するたびにMySQLデータディレクトリ内で適切な証明書ファイルを探します。 このため、SSLを有効にするためにMySQLの構成を変更する必要はありません。
代わりに、MySQLサービスを再起動してSSLを有効にします。
- sudo systemctl restart mysql
再起動後、前と同じコマンドを使用して新しいMySQLセッションを開きます。 サーバーでサポートされている場合、MySQLクライアントはSSLを使用して自動的に接続を試みます。
- mysql -u root -p -h 127.0.0.1
前回リクエストしたのと同じ情報をもう一度見てみましょう。 SSL関連の変数の値を確認してください。
- SHOW VARIABLES LIKE '%ssl%';
Output+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| have_openssl | YES |
| have_ssl | YES |
| ssl_ca | ca.pem |
| ssl_capath | |
| ssl_cert | server-cert.pem |
| ssl_cipher | |
| ssl_crl | |
| ssl_crlpath | |
| ssl_key | server-key.pem |
+---------------+-----------------+
9 rows in set (0.00 sec)
have_openssl
およびhave_ssl
変数は、DISABLED
ではなくYES
を読み取るようになりました。 さらに、ssl_ca
、ssl_cert
、およびssl_key
変数には、生成したばかりのそれぞれのファイルの名前が入力されています。
次に、接続の詳細をもう一度確認します。
- \s
Output--------------
. . .
SSL: Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection: 127.0.0.1 via TCP/IP
. . .
--------------
今回は、SSLが接続の保護に使用されていることを示す特定のSSL暗号が表示されます。
終了してシェルに戻ります。
- exit
サーバーで暗号化を使用できるようになりましたが、リモートアクセスを許可し、安全な接続の使用を義務付けるには、いくつかの追加構成が必要です。
手順4—リモートクライアントの安全な接続を構成する
MySQLサーバーでSSLを有効にしたので、安全なリモートアクセスの構成を開始できます。 これを行うには、SSLを介してリモート接続を確立するようにMySQLサーバーを構成し、MySQLをバインドしてパブリックインターフェイスでリッスンし、システムのファイアウォールルールを調整して外部接続を許可します。
現在、MySQLサーバーはクライアントからのSSL接続を受け入れるように構成されています。 ただし、クライアントから要求された場合でも、暗号化されていない接続は許可されます。 require_secure_transport
オプションをオンにすることでこれを変更できます。 これには、SSLまたはローカルUnixソケットのいずれかを使用してすべての接続を確立する必要があります。 Unixソケットはサーバー自体からのみアクセスできるため、リモートユーザーが利用できる接続オプションはSSLのみです。
この設定を有効にするには、お好みのテキストエディタでMySQL構成ファイルを開きます。 ここでは、nano
を使用します。
- sudo nano /etc/mysql/my.cnf
内部には、追加の構成ファイルを調達するために使用される2つの!includedir
ディレクティブがあります。 これらの行の下に独自の構成
MySQLサーバープロセスを対象とする[mysqld]
セクションを作成することから始めます。 そのセクションヘッダーの下で、require_secure_transport
をON
に設定します。これにより、MySQLは安全な接続のみを許可します。
. . .
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
[mysqld]
# Require clients to connect either using SSL
# or through a local socket file
require_secure_transport = ON
デフォルトでは、MySQLは、localhostを表すループバックIPアドレスである127.0.0.1
から発信された接続のみをリッスンするように構成されています。 これは、MySQLが、MySQLサーバーがインストールされているマシンから発信された接続のみをリッスンするように構成されていることを意味します。
MySQLが外部接続をリッスンできるようにするには、外部IPアドレスで接続をリッスンするようにMySQLを構成する必要があります。 これを行うには、bind-address
設定を追加し、すべてのIPアドレスを表すワイルドカードIPアドレスである0.0.0.0
を指すようにします。 基本的に、これによりMySQLはすべてのインターフェースで接続をリッスンするようになります。
. . .
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
[mysqld]
# Require clients to connect either using SSL
# or through a local socket file
require_secure_transport = ON
bind-address = 0.0.0.0
注:または、bind-address
をMySQLサーバーのパブリックIPアドレスに設定することもできます。 ただし、データベースを別のマシンに移行する場合は、my.cnf
ファイルを更新することを忘れないでください。
これらの行を追加したら、ファイルを保存して閉じます。 nano
を使用してファイルを編集した場合は、CTRL+X
、Y
、ENTER
の順に押すと編集できます。
次に、MySQLを再起動して、新しい設定を適用します。
- sudo systemctl restart mysql
次のように入力して、MySQLが127.0.0.1
ではなく0.0.0.0
をリッスンしていることを確認します。
- sudo netstat -plunt
このコマンドの出力は次のようになります。
OutputActive Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 13317/mysqld
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1293/sshd
tcp6 0 0 :::22 :::* LISTEN 1293/sshd
上記の出力で強調表示されている0.0.0.0
は、MySQLが使用可能なすべてのインターフェースで接続をリッスンしていることを示しています。
次に、サーバーのファイアウォールを介したMySQL接続を許可します。 次のように入力して、ufw
ルールに例外を追加します。
- sudo ufw allow mysql
OutputRule added
Rule added (v6)
これにより、リモート接続の試行がMySQLサーバーに到達できるようになります。 ただし、現在、リモートマシンから接続できるユーザーは構成されていません。 次のステップでは、クライアントマシンから接続できるMySQLユーザーを作成して構成します。
ステップ5—専用のMySQLユーザーを作成する
この時点で、MySQLサーバーはリモートクライアントマシンからの接続の試行を拒否します。 これは、既存のMySQLユーザーがすべてMySQLサーバーからローカルに接続するように構成されているためです。 これを解決するには、クライアントマシンからのみ接続できる専用ユーザーを作成します。
このようなユーザーを作成するには、rootユーザーとしてMySQLに再度ログインします。
- mysql -u root -p
プロンプトから、CREATE USER
コマンドを使用して新しいリモートユーザーを作成します。 このユーザーには任意の名前を付けることができますが、このガイドではmysql_userという名前を付けています。 ユーザー指定のホスト部分でクライアントマシンのIPアドレスを指定して、そのマシンへの接続を制限し、password
を選択した安全なパスワードに置き換えてください。 また、require_secure_transport
オプションが将来オフになる場合の冗長性のために、次に示すように、REQUIRE SSL
句を含めて、このユーザーがSSLを必要とすることを指定します。
- CREATE USER 'mysql_user'@'your_mysql_client_IP' IDENTIFIED BY 'password' REQUIRE SSL;
次に、アクセスする必要のあるデータベースまたはテーブルに対する新しいユーザー権限を付与します。 実例を示すために、example
データベースを作成します。
- CREATE DATABASE example;
次に、新しいユーザーにこのデータベースとそのすべてのテーブルへのアクセスを許可します。
- GRANT ALL ON example.* TO 'mysql_user'@'your_mysql_client_IP';
次に、特権をフラッシュして、これらの設定をすぐに適用します。
- FLUSH PRIVILEGES;
次に、完了したらシェルに戻ります。
- exit
これで、MySQLサーバーがリモートユーザーからの接続を許可するように設定されました。 MySQLに正常に接続できることをテストするには、mysql-client
パッケージをMySQLクライアントにインストールする必要があります。
ssh
を使用してクライアントマシンにログインします
- ssh sammy@your_mysql_client_ip
次に、クライアントマシンのパッケージインデックスを更新します。
- sudo apt update
そして、次のコマンドでmysql-client
をインストールします。
- sudo apt install mysql-client
プロンプトが表示されたら、ENTER
を押してインストールを確認します。
APTがパッケージのインストールを完了したら、次のコマンドを実行して、サーバーに正常に接続できるかどうかをテストします。 このコマンドには、 mysql_userを指定する-u
ユーザーオプションと、MySQLサーバーのIPアドレスを指定する-h
オプションが含まれています。
- mysql -u mysql_user -p -h your_mysql_server_IP
パスワードを送信すると、リモートサーバーにログインします。 \s
を使用してサーバーのステータスを確認し、接続が安全であることを確認します。
- \s
Output--------------
. . .
SSL: Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection: your_mysql_server_IP via TCP/IP
. . .
--------------
終了してシェルに戻ります。
- exit
SSL経由でMySQLに接続できることを確認しました。 ただし、MySQLサーバーが安全でない接続を拒否していることをまだ確認していません。 これをテストするには、もう一度接続してみますが、今回はログインコマンドに--ssl-mode=disabled
を追加します。 これにより、mysql-client
に暗号化されていない接続を試行するように指示されます。
- mysql -u mysql_user -p -h mysql_server_IP --ssl-mode=disabled
プロンプトが表示されたらパスワードを入力すると、接続が拒否されます。
OutputERROR 1045 (28000): Access denied for user 'mysql_user'@'mysql_server_IP' (using password: YES)
これは、暗号化されていない接続が拒否されている間、SSL接続が許可されていることを示しています。
この時点で、MySQLサーバーは安全なリモート接続を受け入れるように構成されています。 これがセキュリティ要件を満たしている場合は、ここで停止できますが、2つのサーバー間のセキュリティと信頼を強化するために配置できる追加の要素がいくつかあります。
ステップ6—(オプション)MySQL接続の検証を構成する
現在、MySQLサーバーは、ローカルで生成された認証局(CA)によって署名されたSSL証明書で構成されています。 サーバーの証明書とキーのペアは、着信接続の暗号化を提供するのに十分です。
ただし、認証局が提供できる信頼関係をまだ十分に活用していません。 CA証明書、およびクライアント証明書とキーをクライアントに配布することにより、両方の当事者は、相互に信頼できる認証局によって証明書が署名されたことを証明できます。 これは、悪意のあるサーバーからのなりすまし接続を防ぐのに役立ちます。
この追加のオプションのセーフガードを実装するために、適切なSSLファイルをクライアントマシンに転送し、クライアント構成ファイルを作成し、信頼できる証明書を要求するようにリモートMySQLユーザーを変更します。
注: CA証明書、クライアント証明書、およびクライアントキーを次の段落で概説するMySQLクライアントに転送するプロセスでは、各ファイルの内容をcat
で表示し、それらの内容をクリップボードにコピーします。 、およびそれらをクライアントマシン上の新しいファイルに貼り付けます。 scp
やsftp
などのプログラムを使用してこれらのファイルを直接コピーすることは可能ですが、両方のサーバーに SSHキーを設定して、それらを許可する必要もあります。 SSH経由で通信します。
ここでの私たちの目標は、MySQLサーバーに接続するための潜在的な手段の数を最小限に抑えることです。 このプロセスは、ファイルを直接転送するよりも少し手間がかかりますが、同様に安全であり、2台のマシン間でSSH接続を開く必要はありません。
root以外のユーザーのホームディレクトリにあるMySQLクライアントにディレクトリを作成することから始めます。 このディレクトリをclient-ssl
と呼びます。
- mkdir ~/client-ssl
証明書キーは機密情報であるため、このディレクトリへのアクセスをロックダウンして、現在のユーザーのみがアクセスできるようにします。
- chmod 700 ~/client-ssl
MySQLサーバーで、次のように入力してCA証明書の内容を表示します。
- sudo cat /var/lib/mysql/ca.pem
Output-----BEGIN CERTIFICATE-----
. . .
-----END CERTIFICATE-----
BEGIN CERTIFICATE
およびEND CERTIFICATE
行を含む出力全体をクリップボードにコピーします。
MySQLクライアントで、新しいディレクトリ内に同じ名前のファイルを作成します。
- nano ~/client-ssl/ca.pem
内部に、コピーした証明書の内容をクリップボードから貼り付けます。 終了したら、ファイルを保存して閉じます。
次に、MySQLサーバーにクライアント証明書を表示します。
- sudo cat /var/lib/mysql/client-cert.pem
Output-----BEGIN CERTIFICATE-----
. . .
-----END CERTIFICATE-----
ファイルの内容をクリップボードにコピーします。 繰り返しますが、最初と最後の行を含めることを忘れないでください。
[X31X]