![見出し画像](https://assets.st-note.com/production/uploads/images/117812263/rectangle_large_type_2_dbf413aaec1ecb7cb6ad8618bb3dfeda.png?width=1200)
WordPressデータ消失インシデントからの復旧と学び
こんにちは。エンジニアの冨田です。
クラシコムでは定期的に障害対応訓練を行い、手順書をブラッシュアップしてきました。
直近実際に発生したWordPressからのデータ消失インシデントから得た教訓があり、他の会社でも発生し得る内容だったので共有しようと思います。
システム構成
WordPressはAWSの東京リージョン上で稼働しています。
画像はSimple Storage Service(S3)でバージョニングしており、さらに大阪リージョンと別アカウントの東京リージョンにそれぞれレプリケーションしています。
また、RDBMSはMySQL8.0でAmazon RDSで稼働しており、スナップショットの作成とAWS Backupにより大阪リージョンと別アカウントの東京リージョンにバックアップしています。
![](https://assets.st-note.com/img/1696220756722-p4eZUncfRi.png?width=1200)
タイムライン
13:55 問い合わせが入る
コンテンツ管理者からWordPressから画像が消えているという問い合わせがSlack上でありました。
普段テクノロジーグループへの問い合わせは1名のエンジニアが一旦受付を行い、ヒアリングを行ったり、翌週のスプリントプランニング時にアサインしたりするという対応を行っています。
14:27 インシデントだよ全員集合
今回の問い合わせ内容は不穏なためSlackで複数のエンジニアが集まってきて原因を探っているものの、前日にWordPressのプラグインのバージョンアップを行っていたことや一部の画像のみ表示されていないこともあり障害対応フローの通りビデオ会議ツールのAroundに集合するまで約30分かかってしまいました。
14:35 再現しない
ステージング環境も同様の構成のため確認したところ再現しませんでした。
14:36 リバート
前日に行っていたWordPressのプラグイン アップデートのリバートを行いました。
しかし、問題は解消しませんでした。
14:57 レコード消失を確認
本番のデータベースに接続し、本来あるはずの画像のメタデータのレコードがないことに気が付きました。
前日のスナップショットから復元できないか検討を開始し始めました。
コンテンツ管理者にデータベースを切り替えてよいか連絡したのですが、別件の打ち合わせがあったためすぐに連絡が取れませんでした。
15:50 レストア開始
当日朝のスナップショットがあったため、そこからレストアを開始しました。
16:15 レストア終了
レストアしたDBに接続してデータを確認したところ当日公開した記事や下書きのデータが残っていなかったため別途復旧する必要がでてきました。
また、記事のURLでスラッグを利用していなかったため、当日公開した記事のURLが変わる可能性がでてきました。
16:40 画像消失を確認
画像のメタデータだけではなく、S3で保存している画像自体も削除されていることが判明しました。
この時点では原因がわかっておらず複数の説がでてきました。
前日更新したプラグインがなにかの投稿をトリガーに過去のデータを書き換えた説
脆弱性を利用して削除された説
オペレーションミス説
16:45 300件弱画像消失
画像のメタデータを抽出した差分をとったところ300件弱の画像が削除されていることが判明しました。
17:00 コンテンツ管理者と協議
DBの切り替えと記事のURLが変更になることの了承が得られました。
17:36 画像復旧
S3の画像はバージョニングしていたので、画像のパスをリスト化しAWS CLIで削除マークを削除しました。
cat image_list.txt | aws-vault exec ${PROFILE} -- xargs -I {} aws s3api list-object-versions --bucket ${BUCKET} --prefix {} --output json --query 'DeleteMarkers[?IsLatest==`true`].[Key, VersionId]' | jq -r '.[] | "--key '\''" + .[0] + "'\'' --version-id " + .[1]' | aws-vault exec ${PROFILE} -- xargs -L1 aws s3api delete-object --bucket ${BUCKET}
17:37 DBの接続先変更
サイトの設定を変更しリストアしたDBへ接続先を変更しました。
しかし、WordPressアップロード時に自動で作成されるリサイズ画像の復旧も必要であることが判明しました。
画像パスのリストをフルパスで記載していたため、PREFIXのみにし再度AWS CLIを実行し、復旧しました。
18:10 原因判明
CloudWatch Logsで記録してあるWordPressのアクセスログにS3の画像が削除された時間帯にWordPressのユーザーが削除されていることが判明しました。
WordPressはユーザーを削除する際に、コンテンツの消去と移譲が選べるのですがコンテンツが消去されたことが判明しました。
18:25 記事復旧
当日公開した記事を元のDBからデータをコピーし復旧しました。
18:28 解散
翌日以降やらなければならないことをメモし解散することになりました。
クラシコムでは普段ほとんど残業はなく18時すぎに退勤するのですが、この日ばかりは少し残業してしまいました。
振り返りと対策
翌日さっそく振り返り会を行いました。
復旧までの時間の短縮
アクセスログをもっと前に確認していれば原因にたどりつけていました。
今考えると手のあいているエンジニアが居たので作業と並行して調査することも可能でした。
また、14:57にレコードがないということに気づいてから、15:50スナップショットの復元開始まで約1時間ありました。
スナップショットから復元したDBを利用するか否かはともかく、いち早くスナップショットを復元して障害の発生しているDBと比較することで原因の調査の材料にできたと感じました。
WordPress
WordPressに限ったことではないですが、URLにIDが含まれているとDBを復元して新たにレコードを追加していくとIDが変わる可能性もでてきます(途中歯抜けにして調整すれば同一にすることは可能ですが)。
今後はIDではなくスラッグなどの別名をURLに利用しようという話になりました。
また、社内のルールでは退職者のパスワードを変更し、ユーザーの削除は行わないというルールとなっていました。
しかし、オペレーションミスは発生するものです。
WordPress側で削除対象のユーザーのデータを移譲しなければ、ユーザーの削除をできないようにシステムを変更しておくべきでした。
functions.phpで以下の対応を行いました。
add_action( 'delete_user', 'check_delete_user', 10, 2);
function check_delete_user($unuseUserId, $reassign) {
if (is_null($reassign)) {
wp_die('移譲先を選択してください。');
}
}
S3レプリケーションの失敗
今回の件と直接関係ないのですがS3を大阪リージョンへレプリケーションしていました。
しかし、昨年から失敗していることが判明しました。
ちょうどTerraformのAWS Providerのバージョンアップの時期と重なり、もろもろ設定を変更していたのですが、現時点で原因は究明できていません。
代替策としてAWS BackupでS3のバックアップをとりはじめました。
ポイントインタイムリカバリ(PITR)の活用
今回は直近のスナップショットから復元しました。
しかし、AWS Backupで継続的バックアップを実施しておりPITRでインシデント発生時刻直前のデータから復元可能でした。
実技訓練
障害対応訓練は定期的に行っているものの、リリースのロールバックやDBの復元などの実技は行っていませんでした。
今後定期的に実技訓練も行うことにしました。
まとめ
本記事がWordPressを運用されている方のお役にたてれば幸いです。
当店のコンテンツ、商品情報およびコーポレートサイトをコンテンツマネジメントシステム(CMS)で支えており内製CMS、WordPressを併用しています。
お客様がコンテンツを安全・快適にたのしむことができ、コンテンツ管理者が投稿・編集がしやすく、エンジニアの運用の負担が減りつつ・新たな機能追加できるようなCMSへリプレースを検討しています。
当店のシステムに興味がある方、気になるなと思った方はカジュアル面談を行っていますのでSNSやWantedlyなどでお気軽にお声がけください。