前書き

MySQLは、https://db-engines.com/en/ranking [最も人気のある]オープンソースのリレーショナルデータベース管理システムです。 最新のパッケージマネージャーはMySQLを起動して実行する際の摩擦をある程度軽減しましたが、インストール後に実行する必要のある設定がまだいくつかあります。 余分な時間を費やす最も重要な側面の1つはセキュリティです。

デフォルトでは、MySQLはローカル接続、またはMySQLがインストールされているのと同じマシンから発信された接続のみを受け入れるように設定されています。 MySQLデータベースにリモートの場所からアクセスする必要がある場合は、安全にアクセスすることが重要です。 このガイドでは、Ubuntu 18.04でMySQLを設定して、SSL / TLS暗号化によるリモート接続を受け入れる方法を示します。

前提条件

このガイドを完了するには、次のものが必要です。

  • * 2 * Ubuntu 18.04サーバー。 これらのサーバーの1つをMySQLサーバーとして使用し、もう1つをクライアントマシンとして使用します。 `+ sudo `特権を持つ非rootユーザーを作成し、これらの各サーバーで ` ufw +`でファイアウォールを有効にします。 Ubuntu 18.04初期サーバー設定ガイドに従って、両方のサーバーを適切な初期状態にします。

  • マシンの1つ*で、MySQLサーバーをインストールして構成します。 これを行うには、https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-18-04 [MySQLインストールガイドUbuntu 18.04]のステップ1から3 *に従ってください。 このガイドに従って、https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntuで説明されているように、パスワードで認証するように root * MySQLユーザーを構成してください。 -18-04#step-3-%E2%80%94-(optional)-adjusting-user-authentication-and-privileges [Step 3]、これはTCPではなくTCPを使用してMySQLに接続するために必要であるためローカルUnixソケット。

このガイド全体で、MySQLをインストールしたサーバーは* MySQLサーバー*と呼ばれ、このマシンで実行する必要があるコマンドは次のように青色の背景で表示されることに注意してください。

同様に、このガイドでは、他のサーバーを* MySQLクライアント*と呼び、そのマシンで実行する必要のあるコマンドは赤の背景で表示されます。

混乱を避けるために、このチュートリアルに沿って従うときにこれらを念頭に置いてください。

ステップ1-MySQLの現在のSSL / TLSステータスの確認

構成を変更する前に、* MySQLサーバー*インスタンスの現在のSSL / TLSステータスを確認できます。

次のコマンドを使用して、* root * MySQLユーザーとしてMySQLセッションを開始します。 このコマンドには `+ -p `オプションが含まれています。このオプションは、ログインするためにパスワードの入力を求める ` mysql `を指示します。 また、接続するホストを指定するために使用される「 -h 」オプションも含まれています。 この場合、「 127.0.0.1+」、つまり* localhost *としても知られているIPv4ループバックインターフェイスをポイントします。 これにより、クライアントはローカルソケットファイルを使用する代わりにhttps://en.wikipedia.org/wiki/Transmission_Control_Protocol[TCP]で接続するように強制されます。 MySQLは、デフォルトでhttps://en.wikipedia.org/wiki/Unix_domain_socket[Unix socket file]を介して接続を試みます。 これらの接続はローカルでのみ行うことができ、TCP接続が実行する必要のあるすべてのチェックとルーティング操作を実行する必要がないため、これは一般に高速で安全です。 ただし、TCPで接続すると、接続のSSLステータスを確認できます。

mysql -u root -p -h 127.0.0.1

MySQLのインストールおよび構成時に選択したMySQL * root *パスワードの入力を求められます。 入力すると、インタラクティブな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:       [email protected]

Current pager:      stdout
Using outfile:      ''
Using delimiter:    ;
Server version:     5.7.26-0ubuntu0.18.04.1 (Ubuntu)
Protocol version:   10

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 +`というユーティリティを提供します。 https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-18-04 [前提条件の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             1107 May  3 16:43 /var/lib/mysql/
  258919      4 -rw-r--r--   1              451 May  3 16:43 /var/lib/mysql/
  258925      4 -rw-------   1             1675 May  3 16:43 /var/lib/mysql/
  258927      4 -rw-r--r--   1             1107 May  3 16:43 /var/lib/mysql/
  258922      4 -rw-------   1             1675 May  3 16:43 /var/lib/mysql/
  258928      4 -rw-------   1             1675 May  3 16:43 /var/lib/mysql/
  258924      4 -rw-r--r--   1             1107 May  3 16:43 /var/lib/mysql/
  258918      4 -rw-------   1             1679 May  3 16:43 /var/lib/mysql/

これらのファイルは、認証局(「ca」で始まる)、MySQLサーバープロセス(「server」で始まる)、およびMySQLクライアント(「client」で始まる)のキーと証明書のペアです。 さらに、MySQLはSSLを使用していないときにパスワードを安全に転送するために、「+ private_key.pem 」および「 public_key.pem +」ファイルを使用します。

必要な証明書とキーファイルが用意できたので、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:
. . .

. . .
--------------

今回は、接続を保護するために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は強制的に安全な接続のみを許可します。

/etc/mysql/my.cnf

. . .

!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/

デフォルトでは、MySQLは、「+ 127.0.0.1+」(* localhost *を表すループバックIPアドレス)からの接続のみをリッスンするように構成されています。 これは、MySQLサーバーがインストールされているマシンからの接続のみをリッスンするようにMySQLが構成されていることを意味します。

MySQLが外部接続をリッスンできるようにするには、external IPアドレスで接続をリッスンするように設定する必要があります。 これを行うには、「+ bind-address 」設定を追加して、すべてのIPアドレスを表すワイルドカードIPアドレスである「+0.0.0.0」をポイントすることができます。 基本的に、これによりMySQLはすべてのインターフェイスで接続をリッスンします。

/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

これらの行を追加したら、ファイルを保存して閉じます。 ファイルの編集に「+ 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 :3306      0.0.0.0:*               LISTEN      13317/
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アドレスを指定して、そのマシンへの接続を制限し、「+」を選択した安全なパスワードに置き換えてください。 また、将来的に ` require_secure_transport `オプションがオフになった場合の冗長性のために、次のように ` REQUIRE SSL +`句を含めることでこのユーザーにSSLが必要であることを指定します。

CREATE USER ''@'' IDENTIFIED BY '' REQUIRE SSL;

次に、アクセスする必要があるデータベースまたはテーブルに対して、新しいユーザーのアクセス許可を付与します。 実証するために、 `+ example of`データベースを作成します:

CREATE DATABASE example;

次に、このデータベースとそのすべてのテーブルへの新しいユーザーアクセスを許可します。

GRANT ALL ON example.* TO ''@'';

次に、特権をフラッシュして、これらの設定をすぐに適用します。

FLUSH PRIVILEGES;

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

exit

これで、MySQLサーバーがリモートユーザーからの接続を許可するように設定されました。 MySQLに正常に接続できることをテストするには、* MySQLクライアント*に `+ mysql-client +`パッケージをインストールする必要があります。

`+ ssh +`でクライアントマシンにログインします

ssh @

次に、クライアントマシンのパッケージインデックスを更新します。

sudo apt update

そして、次のコマンドで `+ mysql-client +`をインストールします:

sudo apt install mysql-client

プロンプトが表示されたら、 `+ ENTER`を押してインストールを確認します。

APTがパッケージのインストールを完了したら、次のコマンドを実行して、サーバーに正常に接続できるかどうかをテストします。 このコマンドには、* mysql_user *を指定する `+ -u `ユーザーオプションと、* MySQLサーバーのIPアドレスを指定する ` -h +`オプションが含まれています。

mysql -u  -p -h

パスワードを送信すると、リモートサーバーにログインします。 「+ \ s +」を使用してサーバーのステータスを確認し、接続が安全であることを確認します。

\s
Output--------------
. . .

. . .

. . .
--------------

終了してシェルに戻ります。

exit

SSL経由でMySQLに接続できることを確認しました。 ただし、MySQLサーバーが安全でない接続を拒否していることをまだ確認していません。 これをテストするには、もう一度接続してみますが、今回はログインコマンドに「-ssl-mode = disabled +」を追加します。 これは、暗号化されていない接続を試みるように ` mysql-client +`に指示します:

mysql -u  -p -h  --ssl-mode=disabled

プロンプトが表示されたらパスワードを入力した後、接続は拒否されます。

OutputERROR 1045 (28000): Access denied for user 'mysql_user'@'' (using password: YES)

これは、暗号化されていない接続が拒否されている間にSSL接続が許可されていることを示しています。

この時点で、MySQLサーバーは安全なリモート接続を受け入れるように構成されています。 これがセキュリティ要件を満たしている場合はここで停止できますが、2つのサーバー間のセキュリティと信頼性を強化するために追加できる部分がいくつかあります。

ステップ6-(オプション)MySQL接続の検証の構成

現在、MySQLサーバーは、ローカルで生成された認証局(CA)によって署名されたSSL証明書で構成されています。 サーバーの証明書とキーのペアは、着信接続を暗号化するのに十分です。

ただし、認証局が提供できる信頼関係をまだ完全に活用しているわけではありません。 CA証明書とクライアント証明書およびキーをクライアントに配布することにより、両者は証明書が相互に信頼できる認証局によって署名されたことを証明できます。 これにより、悪意のあるサーバーからのなりすまし接続を防ぐことができます。

この追加のオプションのセーフガードを実装するために、適切なSSLファイルをクライアントマシンに転送し、クライアント構成ファイルを作成し、リモート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-----

ファイルの内容をクリップボードにコピーします。 繰り返しますが、最初と最後の行を含めることを忘れないでください。

`+ client-ssl +`ディレクトリ内の* 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サーバーにアクセスするために必要なすべての資格情報があります。 ただし、MySQLサーバーはクライアント接続に信頼できる証明書を要求するように設定されていません。

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

mysql -u root -p

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

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

ALTER USER ''@'' REQUIRE X509;

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

FLUSH PRIVILEGES;

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

exit

その後、接続時に両方の当事者を検証できるかどうかを確認します。

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

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

予想どおり、クライアント証明書が提示されない場合、サーバーは接続を拒否します。

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

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

クライアントに適切な証明書とキーを提供したため、この試行は成功します。

ログアウトして、シェルセッションへのアクセスを回復します。

exit

サーバーへのアクセスを確認したので、接続するたびに証明書ファイルを指定する必要を避けるために、使いやすさを少し改善します。

  • MySQLクライアント*マシンのホームディレクトリ内で、 `+〜/ .my.cnf +`という隠し設定ファイルを作成します。

nano ~/.my.cnf

ファイルの先頭に、「+ [client] 」というセクションを作成します。 その下に、「 ssl-ca」、「+ ssl-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サーバーに証明するために必要なファイルを指します。 クライアントがCAによっても信頼されていることをMySQLサーバーに確認させる場合、これが必要になります。

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

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

mysql -u  -p -h

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

結論

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