LABO IWASAKI

DBにSSLで接続する

MySQL DBサーバー SSL

ubuntuのDBサーバーSSLで接続します。
前提としてWEBサーバーとDBサーバーは別々に構築。
クライアントからWEBサーバーはSSL通信

そのWEBサーバーからDBサーバーにアクセス。
ここをSSLで通信する設定になります。
ついでにphpmyadminもSSLで接続します。

今回の環境

Environ

まず、WEBサーバーとDBサーバーがあるという前提で今回の設定をしていきます。
サイトはWEBサーバーに置いてある訳ですが、サイトを見る際はSSLになっています。

これに関してはLet's EncryptでSSL化します。
この方法に関しては無料のSSLを使うに記載しています。

WEBサーバーへのアクセスはSSLだけど、そこからDBサーバーへのアクセスはSSLになってません。

今回は別サーバーのDBにアクセスする際もSSLで通信する設定です。

PDOでMySQLに接続しますが、その際にOpenSSLで作ったオレオレ認証局を通します。

DBサーバーにはドメインを1つあてがっており、phpmyadminを使う際も、このドメインを使用します。
phpmyadminにアクセスする際もSSLのみ接続できるように設定します。

現状の確認

Current status

まず現在の状態を確認しておきます。

DBサーバーでMySQLにログインしてSSLの状態を確認します。

 MySQLにログイン 
 mysql -u ユーザー名 -p (パスワードを入力)
 状態の確認 
 mysql > show variables like '%ssl%';

上記のように入力すると以下が表示されます。

 Status 
+----------------+------------+ | Variable_name | Value | +----------------+------------+ | have_openssl | DISABLED |  ← disabledになっている | have_ssl    | DISABLED | | ssl_ca     |      | | ssl_capath   |      | | ssl_cert    |      | | ssl_cipher   |      | | ssl_key    |      | +---------------+-------------+

何もしてなければ上記のhave_opensslはdisabledになっているはずです。
これをopensslを設定してdisabledからYESに変えます。

その後、phpでPDOの接続設定とphpmyadminを設定します。
こういう流れですので不要なところは読み飛ばしてください。

以下のプライベート認証局に関しては
プライベート認証局の証明書、サーバー証明書、クライアント証明書の作成方法について
を参考、また引用させていただいています。
かなり詳しく書いてくれています。尊敬します。

認証局

OpenSSL

プライベート認証局を作成し、証明書を発行します。
OpenSSLはメールサーバー構築の際にも利用しますが、今回もメールサーバー構築の際も、両方で使いやすいように作っていきます。

たぶん入ってると思いますが、OpenSSLが入ってるか確認します。

 OpenSSL確認 
 takayoshi@dbserver:~$ openssl version -a

上記のように入力すると以下が表示されます。

 OpenSSL確認 
OpenSSL 1.0.1f 6 Jan 2014 built on: Mon Feb 29 18:11:15 UTC 2016 platform: debian-amd64 options: bn(64,64) rc4(16x,int) des(idx,cisc,16,int) blowfish(idx) compiler: cc -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Wl,-Bsymbolic-functions -Wl,-z,relro -Wa,--noexecstack -Wall -DMD32_REG_T=int -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM OPENSSLDIR: "/usr/lib/ssl"

これが表示されたら入ってます。
入ってなかったらinstallしましょう。

まず、OpenSSLで発行する証明書の有効期限を自由に設定できるように変更します。

 編集 
 takayoshi@dbserver:~$ sudo vim /usr/lib/ssl/misc/CA.sh

以下のようにあわせます。

 編集箇所 
#CADAYS="-days 1095" # 3 years  これをコメントアウト if [ -z "$CADAYS" ] ; then CADAYS="-days 1095" ; fi # 3 years ↑ これを追加

次に基本設定を編集していきます。
これは別にやらなくてもイイですが、設定しておくと後々楽です。

 ファイルを開く 
 takayoshi@dbserver:~$ sudo vim /usr/lib/ssl/openssl.cnf

ファイル内の下記部分を探してそれぞれ変更します。

 設定を編集 
[ req_distinguished_name ] countryName = Country Name (2 letter code) #countryName_default = AU           コメントアウト countryName_default = JP # デフォルト国コード上をコピーして変更 countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) #stateOrProvinceName_default = Default Province      コメントアウト stateOrProvinceName_default = Osaka # デフォルト都道府県 上をコピーして変更 localityName = Locality Name (eg, city) localityName_default = Osaka # デフォルト市町村区 追加 0.organizationName = Organization Name (eg, company) #0.organizationName_default = Default Company Ltd             コメントアウト 0.organizationName_default = ドメイン.com # デフォルト会社名 or ドメイン名上をコピーして変更 (ここには例えばphpmyadminにアクセスする際に使うドメインを指定しても良い) # we can do this but it is not needed normally :-) #1.organizationName = Second Organization Name (eg, company) #1.organizationName_default = World Wide Web Pty Ltd organizationalUnitName = Organizational Unit Name (eg, section) #organizationalUnitName_default = commonName = Common Name (eg, your name or your server\'s hostname) commonName_max = 64 emailAddress = Email Address emailAddress_max = 64 emailAddress_default = メール@ドメイン.com # デフォルト管理者メールアドレス 追加

証明書発行

Certificate

では、証明書を発行していきます。

 ディレクトリ移動 
cd /etc/mysql/ スーパーユーザーになる
sudo -s

下記の手順で入力していきます。

まずca-key.pemを発行します。

 ca-key.pem発行 
takayoshi@dbserver:~# openssl genrsa 2048 > ca-key.pem

これを実行すると以下が表示されます。

 ca-key.pem発行ー結果 
Generating RSA private key, 2048 bit long modulus .......................................................................................................................................................................+++ ...............................................................................................+++ unable to write 'random state' e is 65537 (0x10001)

これが表示されたらOK。
次にいきます。
ca-cert.pemを発行します。

 ca-cert.pem発行 
takayoshi@dbserver:~# openssl req -new -x509 -nodes -days 3600 -key ca-key.pem -out ca-cert.pem

これを実行すると以下が順番に表示されます。
さっき設定した基本設定が反映されるので、問題なければエンターをおします。

ただし「Common Name」の項目だけは注意が必要です。
前提条件で書いたように、DBサーバーにドメインを与えています。
「Common Name」には、このドメインを指定します。

 ca-cert.pem発行中 
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) [JP]: このままエンター State or Province Name (full name) [Osaka]: このままエンター Locality Name (eg, city) [Osaka]:  このままエンター Organization Name (eg, company) [ドメイン.com(orデフォルト会社名)]:  ドメインが正しければそのままエンター Organizational Unit Name (eg, section) []:  このままエンター Common Name (e.g. server FQDN or YOUR name) []:  DBサーバーに指定したドメイン名 Email Address [メール@ドメイン.com]:  ドメインが正しければそのままエンター

次にいきます。
server-req.pemを発行します。

 server-req.pem発行 
takayoshi@dbserver:~# openssl req -newkey rsa:2048 -days 3600 -nodes -keyout server-key.pem -out server-req.pem

これを実行すると以下が表示されます。
先ほどと同じように「Common Name」に注意して進んでください。

 server-req.pem発行中 
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) [JP]: このままエンター State or Province Name (full name) [Osaka]: このままエンター Locality Name (eg, city) [Osaka]:  このままエンター Organization Name (eg, company) [ドメイン.com(orデフォルト会社名)]:  ドメインが正しければそのままエンター Organizational Unit Name (eg, section) []:  このままエンター Common Name (e.g. server FQDN or YOUR name) []:  DBサーバーに指定したドメイン名 Email Address [メール@ドメイン.com]:  ドメインが正しければそのままエンター Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:  このままエンター An optional company name []  このままエンター

次にserver-key.pemを発行します。

 server-key.pem発行 
takayoshi@dbserver:~# openssl rsa -in server-key.pem -out server-key.pem server-key.pem発行ー結果
writing RSA key

次にserver-cert.pemを発行します。

 server-cert.pem発行 
takayoshi@dbserver:~# openssl x509 -req -in server-req.pem -days 3600 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 -out server-cert.pem server-cert.pem発行ー結果
Signature ok subject=/C=JP/ST=Osaka/L=Osaka/O=ドメイン.com/CN=ドメイン.com/emailAddress=メール@ドメイン.com Getting CA Private Key unable to write 'random state'

これで必要な証明書の発行が完了しました。
発行されたモノは以下にあるので、ちゃんと出来てるか確認しておいてください。

 証明書の確認 
takayoshi@dbserver:~$ cd /etc/mysql takayoshi@dbserver:/etc/mysql$ ls -l -rw-r--r-- 1 root root 1391 4月 21 17:58 ca-cert.pem -rw-r--r-- 1 root root 1675 4月 21 17:57 ca-key.pem drwxr-xr-x 2 root root 4096 3月 15 15:44 conf.d -rwxr-xr-x 1 root root 1220 10月 22 23:23 debian-start -rw------- 1 root root 333 12月 22 18:49 debian.cnf -rw-r--r-- 1 root root 3758 4月 21 18:01 my.cnf -rw-r--r-- 1 root root 1265 4月 21 17:59 server-cert.pem -rw-r--r-- 1 root root 1675 4月 21 17:59 server-key.pem -rw-r--r-- 1 root root 1041 4月 21 17:59 server-req.pem

MySQLの設定

DB Setting

先ほど作った証明書をMySQLに設定していきます。

 サーバー 
takayoshi@dbserver:~# sudo vim /etc/mysql/my.cnf 以下を追加
[mysqld]の項目を探して、この項目の下の方に以下を追記。 ssl-ca=/etc/mysql/ca-cacert.pem ssl-cert=/etc/mysql/server-cert.pem ssl-key=/etc/mysql/server-key.pem ([mysqld]の下の方にコメントアウトされた同じような項目があるので、それを書き換えても良い。

次にMySQLを再起動します。

 MySQLを再起動 
sudo service mysql restart

ここまで出来たら、MySQLに入って、SSLが有効になっているか確認しましょう。

 MySQLにログイン 
 mysql -u ユーザー名 -p (パスワードを入力)
 状態の確認 
 mysql > show variables like '%ssl%';
 Status 
+-------------------+----------------------------------+ | Variable_name  | Value     | +-------------------+----------------------------------+ | have_openssl  | YES     | | have_ssl    | YES     | | ssl_ca     | /etc/mysql-ssl/ca-cert.pem  | | ssl_capath    |      | | ssl_cert    | /etc/mysql-ssl/server-cert.pem | | ssl_cipher   |      | | ssl_key   | /etc/mysql-ssl/server-key.pem | +-------------------+----------------------------------+

「have_openssl」「have_ssl」がYESになっていれば成功です。
YESになっていない場合、再度再起動するか、証明書を発行し直してみてください。

次に、MySQLにSSLで接続するユーザーを設定します。

 MySQL 
 mysql > GRANT ALL PRIVILEGES ON *.* TO ユーザー名@'%' IDENTIFIED BY 'パスワード' REQUIRE SSL; 結果
Query OK, 0 rows affected (0.00 sec) (こういう表示が出たらOK)

作ったユーザーを反映します。

 MySQL 
 mysql > flush privileges; 結果
Query OK, 0 rows affected (0.00 sec) (こういう表示が出たらOK)

もしWEBサーバーとDBサーバーが同一であれば、これで大丈夫ですが、今回のようにサーバーが別々の場合は「ca-cert.pem」をWEBサーバー側に移動しておく必要があります。

これでやっと準備ができたので、ここからPHPでPDOを使ってMySQLに接続する方法を書きます。
また、あとでphpmyadminもSSLで接続してみましょう。

MySQLに接続

PDO MySQL

MySQLにPDOで接続します。
普通に接続する記述プラス証明書を指定して接続します。

$dbhost = 'host名またはipアドレス';
$dbname = 'DB名';
$dsn = 'mysql:host='.$dbhost.';dbname='.$dbname;
$user = 'MySQLのSSLユーザー名';
$pass = 'パスワード';
$options = array(
  PDO::MYSQL_ATTR_SSL_CA => '/etc/mysql/ca-cert.pem'
//このパスは証明書がある場所を指定してください。上記はただの例です。
//DBサーバーとWEBサーバーが同一の場合はこのパスで大丈夫です。
);

$pdo = new PDO($dsn,$user,$pass,$options);

行目で証明書のパスを指定しています。

しかし、さっき作った証明書はDBサーバーで発行し、DBサーバーの中にあります。
今回はWEBサーバーと、DBサーバーは別々なので、上記のphpはWEBサーバー側のはずです。

証明書はDBサーバーにあるのですから、このままだとエラーが出ます。
証明書をWEBサーバーに移動しましょう。

次に、phpmyadminもSSLで接続しましょう。
SSLを導入していない場合は
無料のSSLをubuntuで使う|Let's Encrypt
を参考にして、まずSSLを導入しておいてください。

phpmyadminの設定

phpmyadmin SSL

SSLを導入していればスグ完了します。
今回はそのためにDBサーバーにドメインも指定しました。

 apache.confを編集 
 takayoshi@dbserver:~$ sudo vim /etc/phpmyadmin/apache.conf 以下を追記
# phpMyAdmin default Apache configuration Alias /example /usr/share/phpmyadmin <Directory /usr/share/phpmyadmin> Options FollowSymLinks DirectoryIndex index.php     SSLRequireSSL    (ここにこれを追記するだけ)

これでphpmyadminにSSLで接続できるはずです。
指定したSSLドメイン/phpmyadminのパス にアクセスしてみてください。

またSSL以外で(http://で)でアクセスすると、弾かれるはずです。

以上になります。