re:Invemt2022の re:Play 開催中、 2022年12月2日 13:15 ~17:30 (日本時間) に発生していた、DevelopersIOのブログ障害について共有させていただきます。
公式ツイート
【お知らせ】現在 #DevelopersIO の記事ページの表示不具合が発生し、現在確認・修正を進めております。ご迷惑おかけしますが今しばらくお待ちください
— クラスメソッド (@classmethod) December 2, 2022
事象内容
- 個別記事、記事一覧ページを有効でURLで開くと、「404」案内ページが表示される状態でした。
正常応答率の変化
対応時系列(JST)
- 13:15 障害発生
- 13:30 社内報告をうけ、調査に着手
- 15:00 Lambda関数で発生していたエラーを特定
- 15:30 実行環境交換、 キャッシュクリア
- 16:45 エラー回避のパッチ完成
- 17:15 パッチを評価後、デプロイ
- 17:30 復旧確認
原因
不要な Authorization ヘッダー
WordPress をヘッドレスCMSとして 公開済みの記事データを参照、HTMLを生成する SSR (Server Side Rendering)用の Lambda関数で、 不要な Authorization ヘッダーが付与されていました。
export const getPost### = async (slug: string) => {
const response = await axiosInstance.get<Post[]>(`${endpoint}`, {
auth: config.auth
})
当設定は、SSR利用の初期段階で、Basic認証で保護された検証環境を利用するためのものでした。
WordPressのアプリケーションパスワード設定
正規CMS利用者(執筆者)が、自身の権限で WordPress APIを実行する事を意図して、アプリケーションパスワード が新規に登録されました。
アプリケーションパスワードを設定したユーザーが存在しない WordPress は、 無効な Authorization ヘッダー が リクエストヘッダー に含まれている場合でも、認証を必須としない WordPress のAPIを利用可能でした。
- アプリケーションパスワード設定前
$ curl -u user:password https://example.com/wp-json/wp/v2/statuses/ -s | jq .
{
"publish": {
"name": "公開済み",
"public": true,
"queryable": true,
"slug": "publish",
"date_floating": false,
"_links": {
"archives": [
{
"href": "https://example.com/wp-json/wp/v2/posts"
}
]
}
}
}
アプリケーションパスワードが設定後のWordPress は、 リクエストヘッダーに Authorization ヘッダーが存在する場合、その値を評価する様になり、 認証エラー(401)が発生するようになりました。
- アプリケーションパスワード設定後
$ curl -u user:password https://example.com/wp-json/wp/v2/statuses/ -s | jq .
{
"code": "invalid_username",
"message": "<strong>エラー</strong>: 不明なユーザー名です。もう一度確認するか、メールアドレスを入力してください。",
"data": {
"status": 401
}
}
対策
今回、暫定対策として、以下を行いました。
- Lambda関数の修正。 無効な Authorization ヘッダーの付与撤去。
- 認証失敗により生成されたネガティブキャッシュデータの削除
まとめ
想定外の障害でしたが、社内各方面からの支援により半日程度で復旧ができました。 ご協力頂いた方々、この場を借りてお礼させていただきます。
今回明らかになった各種テスト不足や、エラーハンドリングなどの課題については、逐次改善を図りたいと思います。
根本対策としては、類似の障害が発生した場合でもサービス影響を極小化できる仕組みの実現。 Amazon S3を筆頭とする非機能要件に優れたサービス、より疎結合に活用する方向で検討を進めていきたいと思います。