Ubuntu16.04でMySQLのSSL/TLSを構成する方法

提供:Dev Guides
移動先:案内検索

序章

MySQLは、世界で最も人気のあるオープンソースのリレーショナルデータベース管理システムです。 最新のパッケージマネージャーは、MySQLを起動して実行するための摩擦を軽減しましたが、インストール後に実行する必要のある構成がいくつかあります。 余分な時間を費やす最も重要な領域の1つは、セキュリティです。

デフォルトでは、MySQLはローカル接続のみを受け入れるように構成されています。 リモート接続を許可する必要がある場合は、安全に許可することが重要です。 このガイドでは、SSL/TLS暗号化を使用したリモート接続を受け入れるようにUbuntu16.04でMySQLを構成する方法を示します。

前提条件

このガイドに従うには、2台のUbuntu16.04サーバーが必要です。 1つをMySQLサーバーとして使用し、もう1つをクライアントとして使用します。 これらの各サーバーでsudo権限を持つ非rootユーザーを作成します。 Ubuntu 16.04初期サーバーセットアップガイドに従って、サーバーを適切な初期状態にします。

最初のマシンでは、MySQLサーバーがインストールおよび構成されている必要があります。 Ubuntu 16.04MySQLインストールガイドに従って、ソフトウェアをインストールおよび構成します。

2番目のマシンに、MySQLクライアントパッケージをインストールします。 aptパッケージインデックスを更新し、次のように入力して必要なソフトウェアをインストールできます。

sudo apt-get update
sudo apt-get install mysql-client

サーバーとクライアントの準備ができたら、以下に進みます。

現在のSSL/TLSステータスを確認する

始める前に、MySQLサーバーインスタンスでSSL/TLSの現在のステータスを確認できます。

rootMySQLユーザーを使用して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_cassl_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_transportONに設定します。

/etc/mysql/my.cnf

. . .

!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」に設定できます。

/etc/mysql/my.cnf

. . .

!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]ディレクトリ内のMySQLクライアントで同じ名前のファイルを開きます。

nano ~/client-ssl/client-cert.pem

クリップボードから内容を貼り付けます。 ファイルを保存して閉じます。

最後に、クライアントキーファイルの内容をMySQLサーバーに表示します。

sudo cat /var/lib/mysql/client-key.pem
Output-----BEGIN RSA PRIVATE KEY-----

. . .

-----END RSA PRIVATE KEY-----

表示された内容(最初と最後の行を含む)をクリップボードにコピーします。

MySQLクライアントで、client-sslディレクトリにある同じ名前のファイルを開きます。

nano ~/client-ssl/client-key.pem

クリップボードから内容を貼り付けます。 ファイルを保存して閉じます。

これで、クライアントマシンは、MySQLサーバーにアクセスするために必要なすべての資格情報を持っているはずです。 次に、リモートユーザーを変更する必要があります。

リモートユーザーの信頼できるCAからの証明書を要求する

現在、MySQLクライアントには、接続時にサーバーに証明書を提示するために使用できるファイルがあります。 ただし、サーバーは、信頼できるCAからのクライアント証明書を要求するようにまだ設定されていません。

これを変更するには、MySQLサーバーでMySQLルートアカウントに再度ログインします。

mysql -u root -p

次に、リモートユーザーの要件を変更する必要があります。 REQUIRE SSL句の代わりに、REQUIRE X509句を適用する必要があります。 これは、前の要件によって提供されたすべてのセキュリティを意味しますが、接続するクライアントは、MySQLサーバーが信頼する認証局によって署名された証明書を提示する必要があります。

ユーザー要件を調整するには、ALTER USERコマンドを使用します。

ALTER USER 'remote_user'@'mysql_client_IP' REQUIRE X509;

変更をフラッシュして、すぐに適用されるようにします。

FLUSH PRIVILEGES;

終了したら、シェルに戻ります。

exit

次に、接続できることを確認するためにテストできます。

接続時のテスト証明書の検証

今こそ、接続時に両方の当事者を検証できるかどうかを確認する良い機会です。

MySQLクライアントで、最初にクライアント証明書を提供せずに接続を試みます。

mysql -u remote_user -p -h mysql_server_IP
OutputERROR 1045 (28000): Access denied for user 'remote_user'@'mysql_client_IP' (using password: YES)

クライアント証明書を提供しない場合、サーバーは接続を拒否します。

次に、--ssl-ca--ssl-cert、および--ssl-keyオプションを使用して接続し、~/client-sslディレクトリ内の関連ファイルをポイントします。

mysql -u remote_user -p -h mysql_server_IP --ssl-ca=~/client-ssl/ca.pem --ssl-cert=~/client-ssl/client-cert.pem --ssl-key=~/client-ssl/client-key.pem

正常にログインする必要があります。 ログアウトして、シェルセッションへのアクセスを回復します。

exit

サーバーへのアクセスを確認したので、使いやすさを少し改善できます。

MySQLクライアント構成ファイルを作成する

接続するたびに証明書ファイルを指定する必要がないように、単純なMySQLクライアント構成ファイルを作成できます。

MySQLクライアントマシンのホームディレクトリ内に、~/.my.cnfという隠しファイルを作成します。

nano ~/.my.cnf

ファイルの先頭に、[client]というセクションを作成します。 その下で、ssl-cassl-cert、およびssl-keyオプションを設定して、サーバーからコピーしたファイルを指すようにすることができます。 次のようになります。

〜/ .my.cnf

[client]
ssl-ca = ~/client-ssl/ca.pem
ssl-cert = ~/client-ssl/client-cert.pem
ssl-key = ~/client-ssl/client-key.pem

ssl-caオプションは、MySQLサーバーによって提示された証明書が、指定した認証局によって署名されていることを確認するようにクライアントに指示します。 これにより、クライアントは信頼できるMySQLサーバーに接続していることを信頼できます。

ssl-certおよびssl-keyオプションは、MySQLサーバーにも同じ認証局によって署名された証明書があることを証明するために必要なファイルを指します。 これは、MySQLサーバーでクライアントがCAによっても信頼されていることを確認する場合に必要です。

終了したら、ファイルを保存して閉じます。

これで、コマンドラインに--ssl-ca--ssl-cert、および--ssl-keyオプションを追加せずに、MySQLサーバーに接続できます。

mysql -u remote_user -p -h mysql_server_ip

これで、クライアントとサーバーは、接続をネゴシエートするときにそれぞれ証明書を提示する必要があります。 各パーティは、ローカルにあるCA証明書に対してリモート証明書を検証するように構成されています。

結論

これで、MySQLサーバーは、リモートクライアントにセキュリティで保護された接続を要求するように構成されているはずです。 さらに、認証局を使用して接続を検証する手順に従った場合、リモートパーティが正当であるという、ある程度の信頼が両側で確立されます。