Ubuntu16.04でMySQLのSSL/TLSを構成する方法
序章
MySQLは、世界で最も人気のあるオープンソースのリレーショナルデータベース管理システムです。 最新のパッケージマネージャーは、MySQLを起動して実行する際の摩擦を軽減しましたが、インストール後に実行する必要のある構成がいくつかあります。 余分な時間を費やす最も重要な領域の1つは、セキュリティです。
デフォルトでは、MySQLはローカル接続のみを受け入れるように構成されています。 リモート接続を許可する必要がある場合は、安全に許可することが重要です。 このガイドでは、SSL/TLS暗号化を使用したリモート接続を受け入れるようにUbuntu16.04でMySQLを構成する方法を示します。
前提条件
このガイドに従うには、2台のUbuntu16.04サーバーが必要です。 1つをMySQLサーバーとして使用し、もう1つをクライアントとして使用します。 これらの各サーバーでsudo
権限を持つ非rootユーザーを作成します。 Ubuntu 16.04初期サーバーセットアップガイドに従って、サーバーを適切な初期状態にします。
最初のマシンでは、MySQLサーバーがインストールおよび構成されている必要があります。 Ubuntu 16.04のMySQLインストールガイドに従って、ソフトウェアをインストールおよび構成します。
2番目のマシンに、MySQLクライアントパッケージをインストールします。 apt
パッケージインデックスを更新し、次のように入力して必要なソフトウェアをインストールできます。
- sudo apt-get update
- sudo apt-get install mysql-client
サーバーとクライアントの準備ができたら、以下に進みます。
現在のSSL/TLSステータスを確認する
始める前に、MySQLサーバーインスタンスでSSL/TLSの現在のステータスを確認できます。
root
MySQLユーザーを使用してMySQLセッションにログインします。 ローカルソケットファイルを使用する代わりに、クライアントにTCPとの接続を強制するために、-h
を使用してIPv4ローカルループバックインターフェイスを指定します。 これにより、TCP接続のSSLステータスを確認できます。
- mysql -u root -p -h 127.0.0.1
インストールプロセス中に選択したMySQLroot
パスワードの入力を求められます。 その後、インタラクティブなMySQLセッションに移動します。
次のように入力して、SSL/TLS変数の状態を表示します。
- SHOW VARIABLES LIKE '%ssl%';
- [environment second]
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.17, for Linux (x86_64) using EditLine wrapper
Connection id: 30
Current database:
Current user: root@localhost
SSL: Not in use
Current pager: stdout
Using outfile: ''
Using delimiter: ;
Server version: 5.7.17-0ubuntu0.16.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: 3 hours 38 min 44 sec
Threads: 1 Questions: 70 Slow queries: 0 Opens: 121 Flush tables: 1 Open tables: 40 Queries per second avg: 0.005
--------------
上記の出力が示すように、TCPを介して接続されているにもかかわらず、SSLは現在接続に使用されていません。
終了したら、現在のMySQLセッションを閉じます。
- exit
これで、接続を保護するためにSSL用のMySQLの構成を開始できます。
SSL/TLS証明書とキーを生成する
MySQLへのSSL接続を有効にするには、最初に適切な証明書とキーファイルを生成する必要があります。 このプロセスを簡素化するために、mysql_ssl_rsa_setup
と呼ばれるユーティリティがMySQL5.7以降で提供されています。 Ubuntu 16.04には互換性のあるバージョンのMySQLがあるため、このコマンドを使用して必要なファイルを生成できます。
ファイルは、/var/lib/mysql
にあるMySQLのデータディレクトリに作成されます。 生成されたファイルを読み取ることができるようにMySQLプロセスが必要なので、生成されたファイルを所有する必要があるユーザーとして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'
-----
次のように入力して、生成されたファイルを確認します。
- sudo find /var/lib/mysql -name '*.pem' -ls
Output 256740 4 -rw-r--r-- 1 mysql mysql 1078 Mar 17 17:24 /var/lib/mysql/server-cert.pem
256735 4 -rw------- 1 mysql mysql 1675 Mar 17 17:24 /var/lib/mysqlsql/ca-key.pem
256739 4 -rw-r--r-- 1 mysql mysql 451 Mar 17 17:24 /var/lib/mysqlsql/public_key.pem
256741 4 -rw------- 1 mysql mysql 1679 Mar 17 17:24 /var/lib/mysqlsql/client-key.pem
256737 4 -rw-r--r-- 1 mysql mysql 1074 Mar 17 17:24 /var/lib/mysqlsql/ca.pem
256743 4 -rw-r--r-- 1 mysql mysql 1078 Mar 17 17:24 /var/lib/mysqlsql/client-cert.pem
256736 4 -rw------- 1 mysql mysql 1675 Mar 17 17:24 /var/lib/mysqlsql/private_key.pem
256738 4 -rw------- 1 mysql mysql 1675 Mar 17 17:24 /var/lib/mysqlsql/server-key.pem
最後の列は、生成されたファイル名を示しています。 「mysql」を示す中央の列は、生成されたファイルが正しいユーザーとグループの所有権を持っていることを示しています。
これらのファイルは、認証局(「ca」で始まる)、MySQLサーバープロセス(「server」で始まる)、およびMySQLクライアント(「client」で始まる)のキーと証明書のペアです。 さらに、private_key.pem
およびpublic_key.pem
ファイルは、SSLを使用しない場合にパスワードを安全に転送するためにMySQLによって使用されます。
MySQLサーバーでSSL接続を有効にする
最新のMySQLバージョンは、サーバーの起動時にMySQLデータディレクトリ内で適切な証明書ファイルを検索します。 このため、SSLを有効にするためにMySQL構成を実際に変更する必要はありません。
代わりにMySQLサービスを再起動できます。
- 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
サーバーは暗号化を使用できるようになりましたが、リモートアクセスを許可し、安全な接続の使用を義務付けるには、いくつかの追加構成が必要です。
リモートクライアントの安全な接続の構成
サーバーでSSLを使用できるようになったので、安全なリモートアクセスの構成を開始できます。 これを行うには、次のことを行う必要があります。
- リモート接続にSSLが必要
- パブリックインターフェイスにバインドする
- リモート接続用のMySQLユーザーを作成する
- 外部接続を許可するようにファイアウォールルールを調整します
必須SSLを使用したリモートアクセスの構成
現在、MySQLサーバーはクライアントからのSSL接続を受け入れるように構成されています。 ただし、クライアントから要求された場合でも、暗号化されていない接続は許可されます。
require_secure_transport
オプションをオンにすることで、これを修正できます。 これには、SSLまたはローカルUnixソケットのいずれかを使用してすべての接続を確立する必要があります。 Unixソケットにはサーバー自体からのみアクセスできるため、リモートユーザーが利用できる接続オプションはSSLのみです。
この設定を有効にするには、テキストエディタで/etc/mysql/my.cnf
ファイルを開きます。
- sudo nano /etc/mysql/my.cnf
内部には、追加の構成ファイルを調達するために使用される2つの!includedir
ディレクティブがあります。 これらの行の下に独自の構成
MySQLサーバープロセスを対象とする[mysqld]
セクションを作成することから始めます。 そのセクションヘッダーの下で、require_secure_transport
をON
に設定します。
. . .
!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はローカルコンピューターから発信された接続のみをリッスンするように構成されています。 リモート接続をリッスンするように構成するには、bind-address
を別のインターフェイスに設定します。
MySQLがそのインターフェイスのいずれかで接続を受け入れることができるようにするには、bind-address
を「0.0.0.0」に設定できます。
. . .
!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
終了したら、ファイルを保存して閉じます。
次に、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 4330/mysqld
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1874/sshd
tcp6 0 0 :::22 :::* LISTEN 1874/sshd
上記の出力の「0.0.0.0」は、MySQLが使用可能なすべてのインターフェースで接続をリッスンしていることを示します。
次に、ファイアウォールを介したMySQL接続を許可する必要があります。 次のように入力して例外を作成します。
- sudo ufw allow mysql
OutputRule added
Rule added (v6)
これで、リモート接続の試行がMySQLサーバーに到達できるようになります。
リモートMySQLユーザーを構成する
MySQLサーバーは現在リモート接続をリッスンしていますが、現在、外部コンピューターから接続できるユーザーは構成されていません。
開始するには、root
ユーザーとしてMySQLにログインします。
- mysql -u root -p
内部では、CREATE USER
コマンドを使用して新しいリモートユーザーを作成できます。 ユーザー指定のホスト部分でクライアントマシンのIPアドレスを使用して、そのマシンへの接続を制限します。
将来require_secure_transport
オプションがオフになった場合の冗長性のために、アカウントの作成時に、REQUIRE SSL
句を含めて、このユーザーがSSLを必要とすることも指定します。
- CREATE USER 'remote_user'@'mysql_client_IP' IDENTIFIED BY 'password' REQUIRE SSL;
次に、アクセスする必要のあるデータベースまたはテーブルに対する新しいユーザー権限を付与します。 実例を示すために、example
データベースを作成し、新しいユーザーに所有権を与えます。
- CREATE DATABASE example;
- GRANT ALL ON example.* TO 'remote_user'@'mysql_client_IP';
次に、特権をフラッシュして、これらの設定をすぐに適用します。
- FLUSH PRIVILEGES;
完了したら、シェルに戻ります。
- exit
サーバーは、リモートユーザーへの接続を許可するように設定されています。
リモート接続のテスト
MySQLクライアントマシンで、サーバーに正常に接続できることを確認するためにテストします。 -u
オプションを使用してリモートユーザーを指定し、-h
オプションを使用してMySQLサーバーのIPアドレスを指定します。
- mysql -u remote_user -p -h mysql_server_IP
パスワードを指定すると、リモートサーバーにログインします。
接続が安全であることを確認してください。
- \s
Output--------------
. . .
SSL: Cipher in use is DHE-RSA-AES256-SHA
. . .
Connection: mysql_server_IP via TCP/IP
. . .
--------------
終了してシェルに戻ります。
- exit
次に、安全でない接続を試みます。
- mysql -u remote_user -p -h mysql_server_IP --ssl-mode=disabled
パスワードの入力を求められたら、接続を拒否する必要があります。
OutputERROR 1045 (28000): Access denied for user 'remote_user'@'mysql_server_IP' (using password: YES)
これが私たちが目指していたものです。 これは、SSL接続が許可されている一方で、暗号化されていない接続は拒否されていることを示しています。
この時点で、MySQLサーバーはリモート接続を安全に受け入れるように構成されています。 これがセキュリティ要件を満たしている場合は、ここで停止できますが、セキュリティと信頼をさらに高めるために配置できる追加の要素がいくつかあります。
MySQL接続の検証の構成(オプション)
現在、MySQLサーバーは、ローカルで生成された認証局(CA)によって署名されたSSL証明書で構成されています。 サーバーの証明書とキーのペアは、着信接続の暗号化を提供するのに十分です。
ただし、現在、認証局が提供できる信頼関係を活用していません。 CA証明書、およびクライアント証明書とキーをクライアントに配布することにより、両当事者は、相互に信頼できる認証局によって証明書が署名されたことを証明できます。 これは、悪意のあるサーバーへのなりすまし接続を防ぐのに役立ちます。
この追加のオプションのセーフガードを実装するには、次のことを行う必要があります。
- 適切なSSLファイルをクライアントマシンに転送します
- クライアント構成ファイルを作成する
- 信頼できる証明書を要求するようにリモートユーザーを変更する
クライアント証明書をクライアントマシンに転送する
まず、MySQLサーバーからMySQL CAおよびクライアント証明書ファイルを取得し、それらをMySQLクライアントに配置する必要があります。
接続に使用するユーザーのホームディレクトリにある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]