2026年11月06日 12:00 / - PV

こんにちは!朝晩がすっかり冷え込んできましたね。yuku_tasです。
ハッカーの皆様は、RDSのマスターパスワードを本番で変えたことはありますか?
退職者が知っていた、どこかに貼ってしまった、そもそも誰も覚えていない。変えなければいけない日は突然やってきます。 でも「変えた瞬間、動いているアプリはどうなるのか」を実際に見たことがある人は、案外少ないのではないでしょうか。
公式ドキュメントには「ダウンタイムは発生しない」と書いてあります。そこで、使い捨てのRDSを作って実際に変更し、0.5秒〜1秒ごとにログインを試して記録しました。
max_connections 60 / max_connect_errors 100 / skip_name_resolve OFFローテーション以外の項目は1回ずつの計測です。インスタンスサイズや負荷が変われば数字は動くはずなので、「このくらいの桁で起きる」という目安として読んでください。
Multi-AZ、リードレプリカ、PostgreSQL、Aurora、負荷がかかった状態は試していません。
# 履歴に平文を残さないよう、read で受ける
read -rs NEW_PW
aws rds modify-db-instance --no-cli-pager \
--db-instance-identifier mydb \
--master-user-password "$NEW_PW" \
--query 'DBInstance.[DBInstanceStatus,PendingModifiedValues]'
--apply-immediately は要りません。AWS CLIのリファレンスどおり、付けなくても変更は非同期ですぐに適用されます。メンテナンスウィンドウまで待ってはくれないので、実行した時点で本番に効くと思ってください。
なお、/、@、"、空白はパスワードに使えません。試すと次のエラーで即拒否されました。
Only printable ASCII characters besides '/', '@', '"', ' ' may be used.| t(秒) | 起きたこと |
|---|---|
| 0.31 | APIが応答 |
| 0.8 | 状態は available のまま(変更は保留中) |
| 3.6 | 旧パスワードが失敗し、新パスワードが通るようになる |
| 4.0 | 状態が resetting-master-credentials になる |
| 64.5 | 状態が available に戻る |
ここから分かることが2つあります。
1つ目は、状態が available でも完了とは限らないことです。呼び出しの直後は available のままなので、状態だけを見る確認だと「もう終わった」と誤認します。PendingModifiedValues も一緒に見るか、resetting-master-credentials になるのを確かめてから待ちましょう。
2つ目は、状態が戻るのを待たなくても新パスワードは効いていることです。約60秒の resetting-master-credentials は、新パスワードが使えない時間ではありませんでした。
新しく接続しようとすると、t=3.6以降は失敗します。 一方で、変更前のパスワードですでに張ってある接続は切れません。変更の前後で次の4つを動かし続けましたが、いずれも無傷でした。
SELECT 1(90回、エラーなし)SELECT SLEEP(45)(完走)COMMIT(成功)app_user の新規ログイン(175回すべて成功)ということは、接続プールが接続を持ち続けている間は問題が表に出ません。 新しい接続を張るタイミング、つまりプールの寿命切れ、再起動、デプロイ、スケールアウトのときに初めて失敗します。「変更した直後は平気だったのに、夜のデプロイで落ちた」という形になりやすいはずです(この部分は計測からの推測です)。
変更の約1秒後にもう一度変更を呼ぶと、拒否されました。
InvalidDBInstanceState有効なのは1回目のパスワードで、状態が available に戻ったのは2回目の呼び出しから約61秒後でした。つまり、打ち間違えたパスワードで確定すると、新しい接続が通らないまま約1分は直せません。
変更するパスワードは、シェルに入力する前にシークレットの保管先へ入れておき、そこからコピーして使うのが安全です。
パスワードを変えた直後に、古いパスワードのアプリが再接続を繰り返す場面を想定しました。誤ったパスワードでの20並列のログインを60秒間続け、その間に毎秒、正しいパスワードでのログインも試しています。
1045 Access denied)Threads_connected のピークは24(max_connections は60)毎秒約290回も失敗しているのに max_connect_errors の100に届きません。performance_schema.host_cache を見ると、SUM_CONNECT_ERRORS は0のままで、COUNT_AUTHENTICATION_ERRORS だけが増えていました。認証失敗はブロックの計数に入りません。
ただし、これはパスワードの間違いでブロックされないという意味であって、次のリスク3とは別の話です。また、今回は無負荷のDBです。負荷がかかったDBで同じことが起きても平気だとは言えません。
ここが今回いちばん知っておきたいところです。 認証失敗は数えられませんが、認証の前に切断された接続は数えられます。
TCPでつないで、認証に進まず切断する。これを正常なログインを挟まずに繰り返すと、101回目でブロックされました。 解除後にもう一度試しても101回目でした。
1129: Host '...' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'ブロック中の様子と、解除を試した結果は次のとおりです。
| 試したこと | 結果 |
|---|---|
同じIPから admin でログイン | 1129で拒否 |
同じIPから app_user でログイン | 1129で拒否(ユーザーではなく接続元単位) |
| ブロック前から保持していた接続 | 問題なく使える |
| マスターパスワードの再設定(64秒) | 解除されない |
FLUSH HOSTS | 8.4では 1064 の構文エラー。解除されない |
TRUNCATE TABLE performance_schema.host_cache | 解除された |
| インスタンスの再起動(約49秒) | 解除された |
「ログインできない!」と慌ててパスワードを再設定しても、1分待たされたうえに状況は何も変わりません。エラーコードが1045か1129かを見てから動くのが大事です。
また、FLUSH HOSTS は長年の定番ですが、今回の8.4では構文エラーでした。古い手順書をそのまま実行すると、ここで詰まります。エラー文とマニュアルにある mysqladmin flush-hosts は今回試していません。
TRUNCATE を実行するには、ブロックされていない経路からの接続が必要です。今回はブロック前の接続を保持していたので実行できました。別のIPの踏み台があれば、そちらからでも実行できるはずです。どちらもなければ再起動になり、その間は全接続が切れます。
試しに、20回ごとに正常なログインを挟んで同じ切断を300回繰り返すと、ブロックされませんでした。MySQLのマニュアルが「成功した接続なしに連続して」と書いているとおりの動きです。
ここからは推測ですが、普段からログインが成功し続けているアプリサーバーより、たまにしか正常ログインしない接続元のほうが危ないと考えられます。DBのポートにTCPで疎通確認だけをする監視やヘルスチェックは、今回の実験と同じ形です。また、NATゲートウェイの裏の全サーバーはDBから同じIPに見えるので、ブロックされれば全台が巻き添えになるはずです。どちらも今回は試していません。
RDSにパスワードの管理を任せる --manage-master-user-password は、人がパスワードを扱わずに済む良い機能です。ところが、即時ローテーションを計測すると意外な結果になりました。
aws rds modify-db-instance --no-cli-pager ローテーション中に約1秒ごとに GetSecretValue で値を取り直し、その値でログインを試しました。
| 回 | 起動方法 | 失敗の開始(t) | 失敗の終了(t) | 長さ |
|---|---|---|---|---|
| 1 | RDS経由 | 8.6 | 69.4 | 60.8秒 |
| 2 | RDS経由 | 8.9 | 68.7 | 59.8秒 |
| 3 | RDS経由 | 8.4 | 68.2 | 59.8秒 |
| 4 | RDS経由 | 7.7 | 67.6 | 59.9秒 |
| 5 | Secrets Manager経由 | 9.1 | 69.2 | 60.1秒 |
| 6 | Secrets Manager経由 | 7.5 | 68.1 | 60.6秒 |
6回とも、ほぼ60秒でした。偶然ではなさそうです。
失敗している間、シークレットの次の版(ステージ AWSPENDING)の値でも試すと、そちらではログインできました(2〜6回目で確認)。
つまり、この約60秒間はこういう状態です。
GetSecretValue が既定で返す AWSCURRENT は、まだ古い値のまま切り替わった先の値が取得できるようになるのは、状態が available に戻るころです。新旧の入れ替わりそのものは手動変更と同じく、計測間隔(約1秒)の中ではどちらも通らない時間は見えませんでした。
よくある「認証に失敗したらシークレットを取り直して再接続」が、1回きりだと効きません。 取り直しても約60秒は古い値が返ってくるからです。
今回試した範囲から言える対策はこちらです。
AWSPENDING も試す手はありますが、おすすめはしません。 今回のローテーション開始直後は、版が存在しなかったり、存在してもまだログインできなかったりしました。AWSが利用者向けに保証している動きでもなさそうです監視についても1つ注意があります。describe-db-instances の SecretStatus は、RDS経由だと rotating になりましたが、RotateSecret(Secrets Manager経由)では計測中ずっと active のままに見えました。ローテーション中かどうかの判定には使えません。
RDS管理のシークレットは、既定で7日ごとにローテーションされます。今回の5・6回目は、Secrets Managerの RotateSecret で起動しました。ただし、スケジュールで起動した本物の自動ローテーションは計測していません。 待つと1回につき7日かかるためです。
同じ経路だとすれば、アプリが新しい接続を張った瞬間が、毎週の約60秒に当たると失敗することになります。任せる前に、接続処理のリトライが60秒を超えて続くかを確かめておくことをおすすめします。
ResourceNotFound になりましたDeletedDate が付きます。戻したあとは古いシークレットを読みに行かないよう、アプリ側の参照先を変えておく必要がありますどちらも既存の接続は無傷でした。
マスターパスワードの再設定は、ログインできなくなったときの最後の手段として語られます。公式ドキュメントにも、権限を誤って消したら再設定で戻せると書いてあります。8.4の admin は SHOW GRANTS で見ると権限を rds_superuser_role というロール経由で持っているので、実際に壊して試しました。
| 壊し方 | 症状 | 再設定で直ったか |
|---|---|---|
ALTER USER ... ACCOUNT LOCK | 3118 でログイン不可 | 直った(完了まで約62秒) |
SET DEFAULT ROLE NONE | ログインはできるが SELECT が 1142、CREATE USER が 1227 | 直った(約63秒) |
REVOKE rds_superuser_role | 同上。SHOW GRANTS は GRANT USAGE のみ | 直った(約62秒) |
| 認証前の切断を繰り返す | 1129 でログイン不可 | 直らない |
ロールを剥がした場合も、再設定だけで GRANT と既定ロールが元どおりになりました。
小さな落とし穴として、8.4の admin に REVOKE CREATE USER, SELECT を実行すると、成功扱いなのに SHOW GRANTS は変わりません。 権限が直接ではなくロールに付いているので、直接の権限を剥がす操作は何も変えません。以前の感覚で権限を確認すると、思っていた状態と違うかもしれません。
CloudTrailの ModifyDBInstance を確認しました。パスワードを渡した7件すべてで、値は次のように伏せられていました。
"masterUserPassword": "HIDDEN_DUE_TO_SECURITY_REASONS"拒否された変更(二重変更の2回目、使えない文字)も記録に残っていました。誰がいつ変えようとしたかは後から追えます。
一方で、シェルの履歴には自分の入力がそのまま残りえます。先ほどの read -rs はそのための一手間です(こちらは一般的な注意で、今回検証したものではありません)。
available かどうかだけで判断しない実行していろいろ試してみた結果の知見を以下にまとめてみます。
resetting-master-credentials はパスワードが使えない時間ではないTRUNCATE TABLE performance_schema.host_cache か再起動で解除する。8.4の FLUSH HOSTS は構文エラーいざという時に一番効くのは、慌てて再設定する前に、エラーコードを見ることです。1045なら再設定、1129なら再設定しても無駄です。この1行だけでも、手順書の先頭に書いておくと1分を節約できます。
この記事が何かのお役に立てれば幸いです。
最後までお読みいただきありがとうございました!
Share Me!