【MySQL版】RDSの証明書更新について少しだけ深掘りする

記事タイトルとURLをコピーする

こんにちは。テクニカルサポート課の森本です。

昨年8月に RDS と Aurora で SSL/TLS 証明書の更新がアナウンスされました。

当該アナウンスに関しては弊社市野が過去にブログにまとめておりますが、今回は詳しいことは極力抜きにして、どのような時にクライアント側で対応が必要になるか少しまとめてみました。

blog.serverworks.co.jp

なお、今回の検証では MySQL クライアントを用いた接続の検証を行なっており、アプリケーションの信頼ストアを使用した証明書の検証については実施しておりません。

大前提

RDSの証明書更新に伴い、必要な手続きは3つあります。このうち、全てのお客様に関係するのは3の手続きです。1および2の手続きに関して必要になるかどうかはお客様のアプリケーション側(クライアント側)の設定に依存します。

  1. 新しい SSL/TLS 証明書をダウンロードする

  2. 新しい SSL/TLS 証明書を使用するようにアプリケーションを更新する

  3. DB インスタンスを変更して、CA を rds-ca-2019 から rds-ca-rsa2048-g1(利用中の DB エンジンによっては rds-ca-rsa4096-g1、または rds-ca-ecc384-g1) に変更する。

アプリケーション側(クライアント側)で証明書の検証が必要な設定をしている場合は1および2の設定が手続が必要になりますが、弊社サポート窓口で確認できるDBインスタンスの設定からアプリケーション側(クライアント側)での設定変更が必要になるかどうかを判断する術はなく、お客様ご自身で更新の必要性をご確認いただく必要があります。

SSL/TLS 証明書を今すぐローテーションしましょう – Amazon RDS と Amazon Aurora については 2024 年に期限切れになります | Amazon Web Services ブログ

現在、アプリケーションが接続するための前提条件として証明書の検証が必要かどうかを、DB インスタンス自体から簡単に判断する方法はありません。 ここでの唯一のオプションは、アプリケーションのソースコードまたは設定ファイルを検査することです。

事前準備

証明書の準備

現時点で AWS 公式から入手できる証明書バンドルには旧証明書と新証明書のすべての証明書が含まれています。 旧証明書のみが含まれている証明書が欲しかったので、以下手順にて雑に旧証明書と新証明書を分割します。

こちらのサンプルスクリプトの中で証明書毎にデコードを行いエイリアスを取得している処理があったので流用して以下の shell を作成しました。東京リージョン用の証明書バンドル(ap-northeast-1-bundle.pem)を取得しています。

#!/bin/sh
mydir=tmp/certs
if [ ! -e "${mydir}" ]
then
mkdir -p "${mydir}"
fi

curl -sS "https://truststore.pki.rds.amazonaws.com/ap-northeast-1/ap-northeast-1-bundle.pem" > ${mydir}/ap-northeast-1.pem
awk 'split_after == 1 {n++;split_after=0} /-----END CERTIFICATE-----/ {split_after=1}{print > "rds-ca-" n ".pem"}' < ${mydir}/ap-northeast-1.pem

for CERT in rds-ca-*; do
  alias=$(openssl x509 -noout -text -in $CERT | perl -ne 'next unless /Subject:/; s/.*(CN=|CN = )//; print')
  echo "$alias"
  rm $CERT
done

処理結果

$ sudo bash certapne1.sh
Amazon RDS Root 2019 CA
Amazon RDS ap-northeast-1 2019 CA
Amazon RDS ap-northeast-1 Root CA RSA4096 G1, L=Seattle
Amazon RDS ap-northeast-1 Root CA ECC384 G1, L=Seattle
Amazon RDS ap-northeast-1 Root CA RSA2048 G1, L=Seattle

東京リージョン用の証明書バンドルのうち、一番上が旧認証機関用(rds-ca-2019)の証明書、3番目から5番目が新認証機関用の証明書っぽいということがわかります。

今回は1番目と5番目をそれぞれ手動で分割して別のファイルに保存します。

$ ls -al *.pem
-rw-rw-r-- 1 ec2-user ec2-user   1460  1月 25 14:58 apne1_RSA2048.pem  <- rds-ca-rsa2048-g1 用
-rw-rw-r-- 1 ec2-user ec2-user   1456  1月 25 14:28 root2019.pem <- rds-ca-2019  用

DBインスタンスの準備

今回は以下の設定のDBインスタンスを使用しました。

  • RDS MySQL 8.0.35
  • 認証機関 rds-ca-2019 (後の検証中に更新します)
  • Performance Schema のみパラメータグループで有効化

なお、DBインスタンス側のSSL設定はデフォルトで有効化されていることを確認しています。

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

MySQL :: MySQL 8.0 リファレンスマニュアル :: 5.1.8 サーバーシステム変数

have_ssl --(中略)-- YES (SSL サポートが使用可能)    

検証用MySQLユーザの作成

便宜上 admin ユーザとは別に以下の4ユーザを作成しています。

  • ssl_disabled
  • ssl_preferred
  • ssl_verifyidentity
  • ssl_verifyca

検証

検証方法

MySQLクライアントからの接続時、以下の ssl-mode オプションによる挙動の違いを検証します。それぞれのオプションの違いについてはこちらをご確認ください。

  • DISABLED
  • PREFERRED
  • VERIFY_CA
  • VERIFY_IDENTITY

接続にSSL/TLSを使用しているかどうかの確認はこちらのドキュメントの内容に従います。

ssl_mode = disabled

接続文字列

$ mysql -h certcheck.xxx.ap-northeast-1.rds.amazonaws.com -u ssl_disabled --ssl_mode disabled -p

確認結果

+----+-----------------+-----------------+-----------------+
| id | user            | host            | connection_type |
+----+-----------------+-----------------+-----------------+
(中略)
| 27 | ssl_disabled    | 10.0.0.46:37542 | TCP/IP          |
(中略)
+----+-----------------+-----------------+-----------------+

connection_type が TCP/IP となっているため、SSL/TLS を使用していないことがわかります。

ssl_mode = preferred

接続文字列

mysql -h certcheck.xxx.ap-northeast-1.rds.amazonaws.com -u ssl_preferred --ssl_mode preferred -p

確認結果

+----+-----------------+-----------------+-----------------+
| id | user            | host            | connection_type |
+----+-----------------+-----------------+-----------------+
(中略)
| 30 | ssl_preferred   | 10.0.0.46:48356 | SSL/TLS         |
(中略)
+----+-----------------+-----------------+-----------------+

connection_type が SSL/TLS となっているため、SSL/TLS を使用していることがわかります。

また、接続文字列内に証明書のパスを指定していません。そのため、サーバ証明書の検証はしていないが、通信自体は暗号化されている状態です。 なお、preferredにつきましてはssl_modeを省略した場合のデフォルトのオプションとなっています。

ssl_mode = verify_identity

接続文字列

mysql -h certcheck.xxx.ap-northeast-1.rds.amazonaws.com -u ssl_verifyidentity --ssl_mode verify_identity --ssl-ca=~/root2019.pem -p

確認結果

+----+--------------------+-----------------+-----------------+
| id | user               | host            | connection_type |
+----+--------------------+-----------------+-----------------+
(中略)
| 31 | ssl_verifyidentity | 10.0.0.46:45716 | SSL/TLS         |
(中略)
+----+--------------------+-----------------+-----------------+

接続文字列内に --ssl-ca=~/root2019.pem と証明書のパスを指定しています。

ssl_mode = verify_ca

接続文字列

mysql -h certcheck.xxx.ap-northeast-1.rds.amazonaws.com -u ssl_verifyca --ssl_mode verify_ca --ssl-ca=~/root2019.pem -p

確認結果

+----+-----------------+-----------------+-----------------+
| id | user            | host            | connection_type |
+----+-----------------+-----------------+-----------------+
(中略)
| 33 | ssl_verifyca    | 10.0.0.46:41994 | SSL/TLS         |
(中略)
+----+-----------------+-----------------+-----------------+

接続文字列内に --ssl-ca=~/root2019.pem と証明書のパスを指定しています。

一旦まとめ

ssl_mode が verify_identity もしくは verify_ca を使用している場合、接続時に証明書のパスを指定する必要があります。

認証機関を変更して再度検証

DBインスタンス側の認証機関を rds-ca-2019 から rds-ca-rsa2048-g1 に変更します。

$ aws rds modify-db-instance --db-instance-identifier certcheck --ca-certificate-identifier rds-ca-rsa2048-g1 --apply-immediately 
ssl_mode = disabled

接続文字列

$ mysql -h certcheck.xxx.ap-northeast-1.rds.amazonaws.com -u ssl_disabled --ssl_mode disabled -p

確認結果

+-----+-----------------+-----------------+-----------------+
| id  | user            | host            | connection_type |
+-----+-----------------+-----------------+-----------------+
(中略)
| 283 | ssl_disabled    | 10.0.0.46:55902 | TCP/IP          |
(中略)
+-----+-----------------+-----------------+-----------------+

接続文字列を変更しなくても問題なく接続できます。

ssl_mode = preferred

接続文字列

mysql -h certcheck.xxx.ap-northeast-1.rds.amazonaws.com -u ssl_preferred --ssl_mode preferred -p

確認結果

+-----+-----------------+-----------------+-----------------+
| id  | user            | host            | connection_type |
+-----+-----------------+-----------------+-----------------+
(中略)
| 286 | ssl_preferred   | 10.0.0.46:38566 | SSL/TLS         |
(中略)
+-----+-----------------+-----------------+-----------------+

こちらも、接続文字列を変更しなくても問題なく接続できます。

ssl_mode = verify_identity

接続文字列

mysql -h certcheck.xxx.ap-northeast-1.rds.amazonaws.com -u ssl_verifyidentity --ssl_mode verify_identity --ssl-ca=~/root2019.pem -p

確認結果

ERROR 2026 (HY000): SSL connection error: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed

接続文字列内に --ssl-ca=~/root2019.pem が残っている場合は接続に失敗します。

変更した接続文字列

mysql -h certcheck.xxx.ap-northeast-1.rds.amazonaws.com -u ssl_verifyidentity --ssl_mode verify_identity --ssl-ca=~/apne1_RSA2048.pem -p

確認結果

+-----+--------------------+-----------------+-----------------+
| id  | user               | host            | connection_type |
+-----+--------------------+-----------------+-----------------+
(中略)
| 290 | ssl_verifyidentity | 10.0.0.46:49392 | SSL/TLS         |
(中略)
+-----+--------------------+-----------------+-----------------+

接続文字列内の証明書のパスを --ssl-ca=~/apne1_RSA2048.pem に変更すると問題なく接続されます。

ssl_mode = verify_ca

接続文字列

mysql -h certcheck.xxx.ap-northeast-1.rds.amazonaws.com -u ssl_verifyca --ssl_mode verify_ca --ssl-ca=~/root2019.pem -p

確認結果

ERROR 2026 (HY000): SSL connection error: error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed

接続文字列内に --ssl-ca=~/root2019.pem が残っている場合は接続に失敗します。

更新した接続文字列

mysql -h certcheck.xxx.ap-northeast-1.rds.amazonaws.com -u ssl_verifyca --ssl_mode verify_ca --ssl-ca=~/apne1_RSA2048.pem -p

確認結果

+-----+-----------------+-----------------+-----------------+
| id  | user            | host            | connection_type |
+-----+-----------------+-----------------+-----------------+
(中略)
| 294 | ssl_verifyca    | 10.0.0.46:41246 | SSL/TLS         |
(中略)
+-----+-----------------+-----------------+-----------------+

接続文字列内の証明書のパスを --ssl-ca=~/apne1_RSA2048.pem に変更すると問題なく接続されます。

まとめ

以上の検証から、MySQL クライアントを使用している場合、RDS の SSL/TLS 証明書変更に伴いアプリケーション側(クライアント側)の変更が必要になるのは以下の2つの場合です。

  1. ssl_mode で verify_identity を指定している場合
  2. ssl_mode で verify_ca を指定している場合

接続にSSL/TLSを用いていない場合(ssl_mode が disabled の場合) や、サーバ証明書の検証を行なっていない場合(ssl_mode が preferred 等の場合)に関してはクライアント側の変更は特に必要ではありません。また DB インスタンス側の認証機関変更も AWS 側の自動適用を待つことも可能です。(とはいえ適用時に再起動が発生する DB エンジンバージョンもありますので、ご都合の良いタイミングで手動適用いただくことをお勧めいたします。)

今回の場合は検証のためにクライアント側の証明書を分割しましたが、本来 AWS から提供される証明書バンドルには古い認証機関と新しい認証機関用の全ての証明書が含まれています。そのため、クライアント側の既存の証明書および接続文字列をあらかじめ更新しておき、都合の良いタイミングでDBインスタンス側の証明書を更新するといった運用も可能かと思います。

この記事がどなたかのお役に立てば幸いです。

参考ドキュメント

SSL/TLS 証明書を今すぐローテーションしましょう – Amazon RDS と Amazon Aurora については 2024 年に期限切れになります | Amazon Web Services ブログ

SSL/TLS 証明書のローテーション-証明書を信頼ストアにインポートするためのサンプルスクリプト

MySQL :: MySQL 8.0 リファレンスマニュアル :: 5.1.8 サーバーシステム変数

MySQL :: MySQL 8.0 リファレンスマニュアル :: 4.2.3 サーバーに接続するためのコマンドオプション

新しい SSL/TLS 証明書を使用して MySQL DB インスタンスに接続するようにアプリケーションを更新する-SSL を使用して MySQL DB インスタンスに接続しているアプリケーションがあるかどうかの確認

森本 晃大(執筆記事の一覧)

テクニカルサポート課

2023年10月入社。絶賛仕事と子育てに奔走中です。