MySQLサーバにSSLで接続する

という作業が離れたところで進行中であることを聞きつけた。感興をそそる。しかし端で会話を聞いているとx509の証明書かどうのとかGrant構文でREQUIRE節がこうのと云うことであり微塵も理解できない。人の会話までも暗号化とはSSL恐れ入った。流行に置き去りにされぬよう実際に設定しておく必要を強く感ずる。ひとまず

MySQLサーバ(192.168.0.8) <---SSL接続--- MySQLクライアント(192.168.0.10)

こういう目論見を立てて、まずはMySQLサーバのインストール。暗号化接続のサポートを有効にするには --with-ssl オプションをつけてのコンパイルが必需ということである。

$ wget -c http://dev.mysql.com/get/Downloads/MySQL-5.1/mysql-5.1.35.tar.gz/from/http://ftp.jaist.ac.jp/pub/mysql/
$ tar zxvf mysql-5.1.35.tar.gz
$ cd mysql-5.1.35/
$ ./configure --prefix=/usr/local/mysql --with-ssl
$ make
$ sudo make install

MySQL のインストールが完了したら my.cnf の mysqld セクションに ssl と追記しておいた。

$ sudo vi /etc/my.cnf
[mysqld]
ssl

これでMySQLサーバを再起動して接続すると have_openssl システム変数の値が YES となりSSL接続に対応したことが分かる。

mysql> show variables like '%ssl%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| have_openssl  | YES   |
| have_ssl      | YES   |

次に秘密鍵・証明書・CA証明書の作成である。先ず秘密鍵を作成。

$ openssl genrsa -rand /dev/urandom -out mysql.key 1024
2048 semi-random bytes loaded
Generating RSA private key, 1024 bit long modulus
.++++++
.......++++++
e is 65537 (0x10001)
$ chmod 400 mysql.key
$ sudo chown root:root mysql.key

次は自己認証局の構築である。Ubuntu 9.04 には自己認証局を構築するためのスクリプトが /usr/lib/ssl/misc 以下に用意されていたので楽ちんぽんである。欣快に堪えない。

$ cd /usr/lib/ssl/misc/
$ sudo bash CA.sh -newca
CA certificate filename (or enter to create) (上位CAの証明書は無いのでENTER)
Making CA certificate ...
Generating a 1024 bit RSA private key
..++++++
...........++++++
writing new private key to './demoCA/private/./cakey.pem'
Enter PEM pass phrase: (CA秘密鍵にパスフレーズを設定)
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/./cakey.pem: (CA秘密鍵のパスフレーズを入力)
(snip)

必要事項を適宜入力し自己認証局が構築できた。と思う。この自己認証局に証明書を発行してもらうためにCSRを作成。

$ sudo openssl req -new -days 365 -key mysql.key -out mysql.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

あとはこのCSRに自己認証局が署名して証明書の出来上がりである。

$ cd /usr/lib/ssl/misc
$ sudo openssl ca -in /etc/ssl/mysql.csr -keyfile demoCA/private/cakey.pem -cert demoCA/cacert.pem -out /etc/ssl/mysql.crt
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for demoCA/private/cakey.pem:
Check that the request matches the signature
Signature ok
(snip)
Certificate is to be certified until Jun 27 18:22:32 2010 GMT (365 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

これで漸くCA証明書・証明書・秘密鍵の作成が完了した。それぞれ適当な場所へ設置してから my.cnf の mysqld セクションにこれらの場所を指定しておく。

[mysqld]
ssl-ca = /usr/lib/ssl/misc/demoCA/cacert.pem
ssl-cert = /etc/ssl/certs/mysql.crt
ssl-key = /etc/ssl/private/mysql.key

MySQLサーバを再起動してSSL絡みの各種システム変数を確認すると

mysql> show variables like '%ssl%';
+---------------+-------------------------------------+
| Variable_name | Value                               |
+---------------+-------------------------------------+
| have_openssl  | YES                                 |
| have_ssl      | YES                                 |
| ssl_ca        | /usr/lib/ssl/misc/demoCA/cacert.pem |
| ssl_capath    |                                     |
| ssl_cert      | /etc/ssl/certs/mysql.crt            |
| ssl_cipher    |                                     |
| ssl_key       | /etc/ssl/private/mysql.key          |
+---------------+-------------------------------------+

なんか良いような佇まいである。もしファイルのパス指定などに誤りがあれば have_openssl と have_ssl システム変数は DISABLE になっているのですぐに分かる。ここまで終わったらクライアントからの接続を許可するユーザを作成しておく。

mysql> grant all privileges on *.* to guro@192.168.0.10 identified by 'password' with grant option;

あと、自己証明書をクライアントへコピー。

$ scp /usr/lib/ssl/misc/demoCA/cacert.pem guro@192.168.0.10:/home/guro/

長かった。ここまできたらあとはクライアントからサーバへ接続するだけである。

$ mysql -h 192.168.0.8 -u guro --ssl-ca=cacert.pem -p

Ssl_cipherシステム変数を確認。値が空でなければSSLで接続できているんである。

mysql> SHOW STATUS LIKE 'Ssl_cipher';
+---------------+--------------------+
| Variable_name | Value              |
+---------------+--------------------+
| Ssl_cipher    | DHE-RSA-AES256-SHA |
+---------------+--------------------+
1 row in set (0.01 sec)

できとる。実際に tcpdump でやり取りの内容を確認すると、たとえば select user from mysql.user のようなクエリを実行しても

$ sudo tcpdump -nxX -s 2000 port 3306
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 2000 bytes
03:49:33.022792 IP 192.168.0.10.45950 > 192.168.0.8.3306: P 2660057346:2660057415(69) ack 2482237137 win 902 
        0x0000:  4508 0079 5be9 4000 4006 5d2b c0a8 000a  E..y[.@.@.]+....
        0x0010:  c0a8 0008 b37e 0cea 9e8d 4102 93f3 eed1  .....~....A.....
        0x0020:  8018 0386 e86e 0000 0101 080a 0011 c2d7  .....n..........
        0x0030:  000f b1ed 1703 0100 40ba e9be ed69 60c3  ........@....i`.
        0x0040:  6244 a004 2e7e 7a8e 87dd 6b8f 9737 3875  bD...~z...k..78u
        0x0050:  d8ee 0cbf 3a71 f076 07ab f65d ffc1 87d4  ....:q.v...]....
        0x0060:  2632 21b6 3164 7472 18a5 731b 2d0f c242  &2!.1dtr..s.-..B
        0x0070:  bc8d 85cf f959 f49d 43

理解に苦しむ文字列が並んでおりなんかこう、せつない。翻ってSSLでの接続をしていないと

03:51:22.839881 IP 192.168.0.10.40535 > 192.168.0.8.3306: P 100:132(32) ack 162 win 365 
        0x0000:  4508 0054 5ce9 4000 4006 5c50 c0a8 000a  E..T.@.@.P....
        0x0010:  c0a8 0008 9e57 0cea ba42 87fa aeeb 8761  .....W...B.....a
        0x0020:  8018 016d 7547 0000 0101 080a 0011 edbd  ...muG..........
        0x0030:  0010 0b95 1c00 0000 0373 656c 6563 7420  .........select.
        0x0040:  7573 6572 2066 726f 6d20 6d79 7371 6c2e  user.from.mysql.
        0x0050:  7573 6572                                user

クエリがもろだし状態となる。コワイヒー。
あと MySQL Query Browser で接続する場合は Advanced Parameters を下記の用に設定することでSSLによる接続が可能となった。なお↓キーを押さないとパラメータが追記できない。これになかなか気が付けず、USE_SSL Yes を追記するだけの作業に30分くらいかかったことは厳粛に受け止め慎重に対応していきたい。

mysql_browser_ssl

参考
http://dev.mysql.com/doc/refman/5.1/ja/secure-connections.html
http://dev.mysql.com/doc/query-browser/en/mysql-gui-options-ssl-connections.html

One thought on “MySQLサーバにSSLで接続する

  1. 話題あがってから記事になるまで早すぎワロタwwww
    すばらしい、さすがguro_chan!
    死亡説がある人から流れてたけど、やっぱり死んでなかった!

コメントを残す

メールアドレスが公開されることはありません。


*

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>