MySQLでSSLクライアント証明書を使う

  • 32
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

MySQLでSSLクライアント証明書を使ってみたくなったので試してみました。

MySQL のバージョンとか

  • CentOS 6.4
  • MySQL 5.5.34 (mysql-server-5.5.34-1.el6.remi.x86_64)

CA証明書とサーバ証明書を作成

証明書を保存するディレクトリを作成します。
どこでもいいのですがとりあえず /etc/mysql/ssl/ にします。

# mkdir -p /etc/mysql/ssl/
# cd /etc/mysql/ssl/

CAの秘密鍵と自己署名証明書を作成します。

# openssl req -new -out ca.crt -keyout ca.key -x509 -days 3650 -newkey rsa:2048 -nodes -subj "/C=JP/ST=Tokyo/L=SonoHen/O=OreOre/OU=Dev/CN=OreOre CA"

Generating a 2048 bit RSA private key
..............................
writing new private key to 'ca.key'
-----

秘密鍵のパーミッションを変更します。0644 のままでも動作しますが変更しておいて損はないでしょう。

# chmod 600 ca.key

サーバ証明書の秘密鍵とCSRを作成します。CN(example.jp)にはサーバのホスト名を指定します。

# openssl req -new -out server.csr -keyout server.key -newkey rsa:2048 -nodes -subj "/C=JP/ST=Tokyo/L=SonoHen/O=OreOre/OU=Dev/CN=example.jp"

Generating a 2048 bit RSA private key
..............................
writing new private key to 'server.key'
-----

秘密鍵のパーミッションとオーナーをを変更します。パーミッションを変更する場合 mysqld から読めるようにオーナーの変更も必要です。

# chmod 600 server.key
# chown mysql: server.key

サーバ証明書を作成します。

# openssl x509 -req -days 3650 -in server.csr -out server.crt -CA ca.crt -CAkey ca.key -CAcreateserial

Signature ok
subject=/C=JP/ST=Tokyo/L=SonoHen/O=OreOre/OU=Dev/CN=example.jp
Getting CA Private Key

クライアント証明書の秘密鍵とCSRを作成し、CSRをサーバに送信します。 この作業はクライアント側で行います。

$ openssl req -new -out client.csr -keyout client.key -newkey rsa:2048 -nodes -subj "/C=JP/ST=Tokyo/L=SonoHen/O=OreOre/OU=Dev/CN=ore@example.jp"

Generating a 2048 bit RSA private key
..............................
writing new private key to 'client.key'
-----

$ chmod 600 client.key
$ scp client.csr example.jp:/tmp/

サーバ側でクライアント証明書を作成します。

# cd /etc/mysql/ssl/
# openssl x509 -req -days 3650 -in /tmp/client.csr -out /tmp/client.crt -CA ca.crt -CAkey ca.key -CAcreateserial

Signature ok
subject=/C=JP/ST=Tokyo/L=SonoHen/O=OreOre/OU=Dev/CN=ore@example.jp
Getting CA Private Key

クライアント側にCA証明書とクライアント証明書をダウンロードします。

$ scp example.jp:/etc/mysql/ssl/ca.crt ./
$ scp example.jp:/tmp/client.crt ./

MySQL の設定

MySQLでサーバ証明書を設定します。
とりあえずSSL通信だけを試すので ssl-ca は設定しません。

my.cnf
ssl-key  = /etc/mysql/ssl/server.key
ssl-cert = /etc/mysql/ssl/server.crt

設定を反映します。

# service mysqld restart

設定が有効になっていることを確認します。

# mysql -e "SHOW VARIABLES LIKE '%ssl%'"

次のように出力されるはずです。

+---------------+---------------------------+
| Variable_name | Value                     |
+---------------+---------------------------+
| have_openssl  | YES                       |
| have_ssl      | YES                       |
| ssl_ca        |                           |
| ssl_capath    |                           |
| ssl_cert      | /etc/mysql/ssl/server.crt |
| ssl_cipher    |                           |
| ssl_key       | /etc/mysql/ssl/server.key |
+---------------+---------------------------+

SSLが必須なユーザーを作成します。

# mysql

次のように作成します。

GRANT ALL ON test.* TO ssluser@'%' IDENTIFIED BY 'pass' REQUIRE SSL;

SSLで接続

まずは普通に接続してみます。ssluser はSSLが必須なので弾かれます。

$ mysql -h example.jp -u ssluser -ppass
ERROR 1045 (28000): Access denied for user 'ssluser'@'192.0.2.101' (using password: YES)

--sslオプションを指定してみます。が、これだけだとSSL通信にはなりませんでした。

$ mysql -h example.jp -u ssluser -ppass --ssl
ERROR 1045 (28000): Access denied for user 'ssluser'@'192.0.2.101' (using password: YES)

SSLで接続するためには --ssl-cipher--ssl-ca--ssl-cert の指定が必要です。

--ssl-cert はクライアント証明書を指定するものなので今は使いません。ひとまず他の2つで接続してみます。

$ mysql -h example.jp -u ssluser -ppass --ssl-cipher=DHE-RSA-AES256-SHA
$ mysql -h example.jp -u ssluser -ppass --ssl-ca=ca.crt

どちらでも接続できました。

--ssl-ca を指定する場合はサーバ証明書がそのCA証明書で署名されている必要があります。
なので適当な自己署名証明書を指定しても接続できません。

$ openssl req -new -out another.crt -keyout another.key -x509 -days 3650 -newkey rsa:2048 -nodes -subj "/C=JP/ST=Tokyo/L=SonoHen/O=OreOre/OU=Dev/CN=OreOre Another CA"

Generating a 2048 bit RSA private key
.................................
writing new private key to 'another.key'
-----

$ mysql -h example.jp -u ssluser -ppass --ssl-ca=another.crt
ERROR 2026 (HY000): SSL connection error: error:00000001:lib(0):func(0):reason(1)

--ssl-verify-server-cert を追加で指定するとサーバ証明書の CommonName と接続先ホスト名の比較も行われます。
例えば、次のように IP アドレスを指定すると接続できません。

$ mysql -h 192.0.2.100 -u ssluser -ppass --ssl-ca=ca.crt --ssl-verify-server-cert
ERROR 2026 (HY000): SSL connection error: SSL certificate validation failure

サーバ証明書の CommonName と同じホスト名で接続する必要があります。

$ mysql -h example.jp -u ssluser -ppass --ssl-ca=ca.crt --ssl-verify-server-cert

クライアント証明書を使って接続

次にクライアント証明書を使ってみます。

まずは my.cnf でクライアント証明書に署名したCA証明書を ssl-ca に指定します。

my.cnf
ssl-key  = /etc/mysql/ssl/server.key
ssl-cert = /etc/mysql/ssl/server.crt
ssl-ca   = /etc/mysql/ssl/ca.crt

設定を反映します。

# service mysqld restart

設定が反映されていることを確認します。

# mysql -e "SHOW VARIABLES LIKE '%ssl%'"

次のように表示されます。

+---------------+---------------------------+
| Variable_name | Value                     |
+---------------+---------------------------+
| have_openssl  | YES                       |
| have_ssl      | YES                       |
| ssl_ca        | /etc/mysql/ssl/ca.crt     |
| ssl_capath    |                           |
| ssl_cert      | /etc/mysql/ssl/server.crt |
| ssl_cipher    |                           |
| ssl_key       | /etc/mysql/ssl/server.key |
+---------------+---------------------------+

クライアント証明書が必要なユーザーを作成します。

$ mysql

次のように作成します。

GRANT ALL ON test.* TO ssluser@'%' IDENTIFIED BY 'pass' REQUIRE X509;

クライアント証明書を使わずに接続してみます。ssluser はクライアント証明書が必要なので接続できません。

$ mysql -h example.jp -u ssluser -ppass --ssl-cipher=DHE-RSA-AES256-SHA
ERROR 1045 (28000): Access denied for user 'ssluser'@'192.0.2.101' (using password: YES)

$ mysql -h example.jp -u ssluser -ppass --ssl-ca=ca.crt
ERROR 1045 (28000): Access denied for user 'ssluser'@'192.0.2.101' (using password: YES)

$ mysql -h example.jp -u ssluser -ppass --ssl-ca=ca.crt --ssl-verify-server-cert
ERROR 1045 (28000): Access denied for user 'ssluser'@'192.0.2.101' (using password: YES)

次のようにクライアント証明書を指定すれば接続出来ます。

$ mysql -h example.jp -u ssluser -ppass --ssl-cert=client.crt --ssl-key=client.key

もちろん --ssl-ca--ssl-verify-server-cert を一緒に指定することも出来ます。

$ mysql -h example.jp -u ssluser -ppass --ssl-ca=ca.crt --ssl-verify-server-cert --ssl-cert=client.crt --ssl-key=client.key

その他

今回はCA証明書とサーバ証明書を別にしましたが、同じでも大丈夫です。

その場合は次のようにサーバ証明書を自己署名で作成し、

$ openssl req -new -out server.crt -keyout server.key -x509 -days 3650 -newkey rsa:2048 -nodes -subj "/C=JP/ST=Tokyo/L=SonoHen/O=OreOre/OU=Dev/CN=example.jp"

クライアント証明書にはサーバ証明書で署名して、

$ openssl x509 -req -days 3650 -in /tmp/client.csr -out /tmp/client.crt -CA server.crt -CAkey server.key -CAcreateserial

my.cnf でCA証明書にサーバ証明書を指定して、

my.cnf
ssl-key  = /etc/mysql/ssl/server.key
ssl-cert = /etc/mysql/ssl/server.crt
ssl-ca   = /etc/mysql/ssl/server.crt

クライアント側は --ssl-ca にサーバ証明書を指定します。

$ mysql -h example.jp -u ssluser -ppass --ssl-ca=server.crt --ssl-verify-server-cert --ssl-cert=client.crt --ssl-key=client.key