こんにちは。ヌーラボでソフトウェアエンジニアとして働いている@vvvatanabeです。
先日、AWS re:Invent 2024に現地参加しました。re:Invent自体初参加です。事前に先人から「とてつもなく歩く」と聞いていたので、トレッキングシューズを新調して「11ナイン」の耐久性を確保したつもりでいました。実際は、予想を遥かに超えて平均歩数は2万歩を超え、脚の応答率は著しく劣化、鳴り止まぬアラート、アドホックなパッチ(湿布)の適用、程遠い「11ナイン」、日頃の運動不足、レジリエンスとはなにか、様々な思いが交錯して、ついにここまでか… と諦めかけた矢先、眼前に「STG363 | Deep dive into data resilience techniques on Amazon S3」というチョークトークが舞い降りました。どうやら、Amazon S3の基本的な耐久性戦略に加え、ヒューマンエラーや外部からの攻撃、アプリケーションの不具合、リージョン障害といったさまざまな脅威に対する対策の手法を詳しく解説してくれるようです。ありがたい。
ということで、このレポートではチョークトーク「STG363」の内容をもとに、Amazon S3のデータのレジリエンスをさらに高めるための実践的なアプローチをご紹介します。
目次
「11ナイン」耐久性を実現する3つの戦略
Amazon S3は、99.999999999%(通称「11ナイン」)という非常に高い耐久性を目指して設計されています。11ナインの実現のためにS3では以下の3つの基本戦略を採用しているとのことでした。
エンドツーエンドのデータ整合性
S3では、データがアップロードされてから保存・取得されるまでの各ステップでチェックサム(ハッシュ)を使ってデータの整合性を確認します。これによって、転送中や保存中にデータが変わってしまうことを防ぎ、常にアップロード時と同じ正しいデータを提供することができます。
冗長化とマルチAZ配置
S3は、受け取ったデータを複数のデバイスに保存し、同時にリージョン内の複数のアベイラビリティゾーン(AZ)に分散して配置します。この仕組みのおかげで、ハードウェアの故障やAZ単位の障害が起きても、別のAZに保存されているデータから確実にアクセスできるため、データの耐久性がしっかりと保たれます。
デバイス故障の継続的監査
S3は常にストレージデバイスの状態を監視し、故障や劣化が見つかった場合には、データを自動的に別のデバイスに再コピーします。この仕組みにより、デバイスの障害が発生してもデータの損失を防ぎ、「11ナイン」の耐久性を維持し続けることができます。
これら3つの戦略を組み合わせることで、S3は長期にわたって高い耐久性を提供し、重要なデータを安全かつ確実に保管しているようです。
考慮すべき脅威シナリオ
S3は非常に高い耐久性を持つサービスですが、データを守るためにはS3そのものだけでなく、運用や外部要因も考慮する必要があります。セッション内のアンケート結果でも、ユーザーが気にしている問題の多くはS3内部ではなく、アプリケーション側や運用のミスによって発生することがわかりました。具体的には、以下の3つの脅威が挙げられます。
人為的ミス
オペレーターの操作ミスや設定ミスによって、データが間違って削除されたり上書きされることがあります。
アプリケーション複雑性による問題
複数のインスタンスが同じバケットにデータを書き込む場合、データの上書きや競合が起きることがあります。
外部からの攻撃
正規のアクセス権限を不正に取得されると、攻撃者によるデータの削除や改ざんが発生する可能性があります。また、リージョン全体が障害に陥ることは滅多にありませんが、不測の事態を考慮しておく必要もあります。
耐久性レビューの考え方
耐久性レビュー(Durability Review)は、データの損失を防ぐために、考えられるリスクや脅威を明らかにして、それに対する対策を検討するプロセスです。S3は非常に高い耐久性を誇りますが、実際の運用では外部要因やヒューマンエラーによってデータが失われる可能性もあります。まずは、耐久性レビューの基本的な考え方を整理していきます。
ユーザー視点で考える「逆算思考」
耐久性レビューでまず大切なのは、「ユーザーにとって何が一番問題になるのか?」という視点です。
- 「データが失われたら、どんな影響が出るのか?」
- 「アプリケーションが正常に動かなくなると、どんな障害が起きるのか?」
たとえば、写真をアップロード・表示・削除できるアプリケーションを例に挙げます。この場合、考えられる問題は「写真が誤って削除される」「既存の写真が別の写真で上書きされてしまう」などが挙げられます。こうした具体的なシナリオから、どんなリスクが潜んでいるのかを洗い出していきます。
考えられるリスクシナリオ
ユーザー視点で逆算していくと、以下の5つの症状が代表的なリスクとして浮かび上がります。
- データ削除:誤操作や不正アクセスが原因で、必要なデータが削除されることがあります。
- データ上書き:キーの重複やアプリケーションの不具合によって、意図せずデータが上書きされ、元のデータが消えてしまうケースです。
- データ破損:ストレージデバイスの故障、ビット反転、アップロード前のメモリ破損などで、データが読み取れなくなる可能性があります
- リージョン障害:地域全体で大規模な障害が発生した場合、そのリージョン内のS3データにアクセスできなくなることがあります。
- KMSキー削除:KMSキーが誤って削除されてしまうと、暗号化されたデータが復号できなくなり、結果的にデータが使えなくなってしまいます。
リスクの原因を探る
これらのリスクを引き起こす主な原因として、次のようなものが考えられます。
- 人的ミス:開発者や運用者が操作を誤り、データを削除してしまうケースです。特に、本番環境とテスト環境を同じアカウントで管理している場合、「テストデータだと思って消したら、本番データだった…」という事故が起こることもあります。
- 権限設定ミス:IAMポリシーやバケットポリシーの設定ミスによって、不正アクセスを許してしまうことがあります。これにより、悪意のある第三者がデータを削除・改ざんするリスクが発生します。
- 外部攻撃(ランサムウェア、不正アクセス):正規のアクセス権限が奪われてしまうと、攻撃者はデータを削除・上書きしたり、KMSキーを削除してデータを使えなくすることも可能です。
- 自然災害や大規模障害:地震や大規模な障害など、予測できないトラブルが発生すると、単一のリージョンにしかデータを保存していない場合、アクセスが停止するリスクがあります。
耐久性レビューでは、これらの「症状」と「原因」をしっかりと特定し、それぞれに対して有効な緩和策を考えていきます。権限管理の強化やアプリケーション設計の工夫、バックアップ戦略の導入など、運用レベルでの対策を組み合わせることで、データの安全性とレジリエンスをしっかりと守ることができます。
次に、考えられるリスクや脅威に対する有効な緩和策を紹介します。
ホワイドボードを用いて即興で解説されていたのが印象的でした
緩和策#1: アカウント分離と権限管理
データ損失のリスクを減らすためには、アカウント構造の見直しや権限の管理が非常に効果的です。
本番環境とテスト環境を分ける
最も基本で重要な対策は、本番環境とテスト環境をはっきり分離することです。本番用のアカウント(例:「prod」)を用意し、テスト環境は別のアカウントで管理します。これによって、「テストデータだと思って誤って本番データを消してしまった…」というようなミスを防げます。
最小権限の原則(Least Privilege)を徹底する
次に、ユーザーやシステムが必要最低限の権限しか持たないようにします。たとえば、Lambda関数には特定のバケットへのオブジェクトアップロード権限のみを与え、バケット削除権限は付与しないといった細かな設定が可能です。また、APIキーは可能な限り使用せず、IAMロールや一時的な認証情報を活用します。
IAMロールやSCPを活用する
IAMロールを使えば、「特定のフォルダ(プレフィックス)以下だけアクセスできる」といった細かな制御ができます。また、Service Control Policy(SCP)を活用すると、組織全体に対して「バケットの削除操作は禁止する」といった強力なルールを適用することが可能です。
緩和策#2: 上書き事故を防ぐ方法
データの上書き事故は、アプリケーションのバグやキー生成の設計ミスなど、予想外の理由で発生することがあります。たとえば、写真をアップロードする際に重複するキーが割り当てられて、別の写真が上書きされてしまう、というケースです。
条件付き書き込み(Conditional Write)を使う
条件付き書き込みとは、オブジェクトの状態に応じて操作を制御できる仕組みです。たとえば、「オブジェクトがまだ存在しない場合だけ書き込みを許可する」といった条件をリクエストに追加できます。これにより、意図せず既存データが上書きされるリスクを防げます。また、不要なデータを削除する場合も同様に条件を付けられるため、より安全にデータを管理できます。
標準的なキー生成ライブラリを活用する
条件付き書き込みと合わせて、データのキー生成ロジックにも注意が必要です。キーの生成に失敗して重複が発生すると、上書き事故が起こりやすくなります。
特にカスタムアルゴリズムを使う場合は、十分なエントロピー(ランダム性)を確保する必要があります。UUID(Universally Unique Identifier)のような標準的なキー生成手法や、信頼できるライブラリを使えば、重複リスクを大幅に減らせます。
緩和策#3: バージョニングと削除対策
誤ってデータを削除してしまった場合や、意図しないバージョンの削除が発生した場合でも、復元できる仕組みが必要です。
バージョニングでデータのロールバックを確保
バージョニングを有効にすると、データが上書きや削除されても、過去の状態に戻せるようになります。たとえば、アプリケーションのバグでデータが間違って上書きされても、以前のバージョンを簡単に復元できます。
ライフサイクルポリシーとタグ付けの活用
データをすぐに削除せず、タグを付けてライフサイクルポリシーで一定期間後に削除する、という戦略もあります。これには多少のコストがかかるかもしれませんが、データを「凍結」しておく期間があることで、誤って削除してもすぐに気づけば元に戻せます。
「Delete Object Version」操作を制限する
バージョニングを使っていても、特定のバージョンを「完全削除(ハードデリート)」してしまうと元に戻せません。このリスクを防ぐには、削除操作そのものを制限するのが効果的です。例えば、SCP(Service Control Policy)やバケットポリシーを使って、「Delete Object Version」操作を禁止します。これにより、誤って完全に削除されることを防げます。
緩和策#4: データ破損を防ぐには
データ破損は、物理的なストレージの故障やビット反転だけでなく、ソフトウェアのバグなど、さまざまな原因で起こります。S3は内部的にチェックサムを使ってデータの整合性を守っていますが、より高い耐久性を求める場合、ユーザー側でも追加の検証方法を組み合わせると安心です。
チェックサムで整合性を確認する
チェックサムは、データが正しく保存・転送されたかを確認するシンプルで基本的な方法です。
データをアップロードする前に、チェックサム(ハッシュ値)を計算してS3に渡しておくと、S3側でその値をもとにデータの整合性を検証してくれます。もしアップロード中や保存中にデータが破損していた場合、S3がチェックサムの不一致エラーを返し、問題を知らせてくれます。
書き込み後にリードバックして確認する
チェックサムの検証に加えて、データを書き込んだ後にデータをリードバック(再読み込み)して期待するデータと一致しているかを確認する方法も有効です。
別実装のコードで結果を突合する
さらに踏み込んだ方法として、同じ処理を別々のシステムやコードベースで実行し、その結果を突き合わせて確認する手法があります。結果が一致しない場合、どちらかのシステムにバグやデータ破損が起きている可能性を特定できます。
この方法は実装や運用が少し複雑になりますが、ソフトウェアのバグが原因でデータが破損するリスクを大幅に減らせます。
緩和策#5: KMSキーの誤削除リスクを減らす
KMSキーが削除されてしまうと、暗号化されているデータを復号できなくなり、実質的にはデータが失われてしまいます。
SCPを使う
サービスコントロールポリシー(SCP)を利用すれば、組織全体でKMSキーの削除操作を一律に禁止することが可能です。たとえば、「KMSキーを削除できない」というSCPを設定すれば、いかなるユーザーやアカウントからもキー削除が行えず、誤操作や不正アクセスによるキー消失を防げます。
CloudFormationのDeletion Policyを設定する
CloudFormationを使ってKMSキーを作成するときに、「Deletion Policy」を「Retain」に設定しておくと、スタックを削除してもKMSキーだけは残り続けます。
これにより、「間違えてスタックごと削除してしまった…」という場合でも、KMSキーが失われる心配はありません。暗号化データを復号する手段をしっかり守ることができます。
緩和策#6: オーファンデータを防ぐには
S3を使うアプリケーションでは、データベースがS3上のオブジェクトを参照することがありますが、何らかの理由でデータベース側のレコードが削除されたり失われたりすると、S3には参照元がない「オーファンデータ(孤立データ)」が残ってしまうことがあります。この状態では、オブジェクトがどのユーザーやリソースに紐づいているのか分からなくなり、管理が難しくなります。
ここでは、オーファンデータを防ぐ方法や、発生後の検出・修復のアプローチについて紹介します。
メタデータを使用する
オーファンデータを発生させないための基本的な方法は、S3オブジェクトにメタデータを付けておくことです。
オブジェクトに顧客IDや関連情報をタグとして追加しておけば、データと利用者・リソースの紐づけが簡単に分かるようになります。
こういったメタデータを付けておくことで、万が一データベース側の情報が失われても、S3に残るオブジェクト自体が手がかりになり、所有者や関連情報を再構築しやすくなります。
定期的な監査と整合性チェックで検出・修復する
孤立データを完全に防ぐのは難しいので、定期的な監査や整合性チェックを行い、発生後に早めに見つけて修正することが大切です。
リコンシリエーション(整合性確認):
データベースとS3上のオブジェクトを突き合わせて、参照先の情報が欠けていないかをチェックします。オブジェクト側のメタデータを確認すれば、不整合を特定する手がかりになります。
S3インベントリの活用:
S3インベントリを使えば、S3に保存されているオブジェクトの一覧を取得できます。これをデータベースと突き合わせることで、オーファンデータを発見できます。ただし、インベントリには一部制約があるため、オブジェクトの詳細な情報を確認するにはHEADリクエストが必要になり、その分コストが増える点には注意が必要です。
監査は週単位や月単位で行うようにすれば、コストを抑えつつデータの整合性を維持できます。
S3 Tablesによる継続的な監視
今後登場が期待されるS3 Tablesという新機能を使えば、データベースとS3の整合性チェックをリアルタイムに近い形で行えるようになるかもしれません。S3 Tablesでは、オブジェクトに関する情報をまとめて管理しやすくなるため、孤立データの早期発見や修正が今よりもっとスムーズになることが期待されています。
緩和策#7: オブジェクトロックでデータを守る
どんなに対策をしても、組織全体がセキュリティ侵害を受け、ルート権限まで奪われるなどの攻撃を完全に防ぐのは難しいものです。そんな非常事態でも、データが削除されるのを防ぐ強力な手段がオブジェクトロック(Object Lock)です。
オブジェクトロックは、指定した期間中、誰であってもオブジェクトを変更・削除できない状態にできます。ランサムウェア攻撃や内部不正といった状況でも、データを守る「最後の砦」となる強力な保護策です。
オブジェクトロックの2つのモード
コンプライアンスモード(Compliance Mode):
設定した保持期間中は、どんなユーザーでもオブジェクトを削除・上書きできません。さらに、保持期間そのものの変更や短縮も不可能です。最も厳格なデータ保護が必要な場合に使えます。
ガバナンスモード(Governance Mode):
特定の権限(ガバナンス権限)を持つユーザーだけが、保持期間中でも変更や削除が可能です。コンプライアンスモードよりも少し柔軟性があり、一部の管理者に限定的な操作権を与えることができます。
保持期間とリーガルホールド
オブジェクトの保持期間は、日数単位で設定できます。これにより、一定期間オブジェクトが「触れられない状態」になります。
また、状況によって保持期間が定められない場合は、リーガルホールド(Legal Hold)を使うのが便利です。APIリクエストでオン・オフを切り替えられるため、柔軟に保護を適用できます。
既存オブジェクトへの一括適用
「過去のデータにもオブジェクトロックを設定したい」という場合は、S3バッチ操作(Batch Operations)を使うと便利です。これを活用すれば、大量の既存オブジェクトにも一括でロック設定を適用でき、過去のデータまでしっかり保護できます。
ポイントインタイムのリストア
ここまでの対策を組み合わせることで、データの上書き、削除、破損、さらにはキー削除といったリスクを大幅に減らすことができます。ただし、それだけでは「特定の過去の時点でのデータの状態」を確認することは難しい場合があります。ここでは、過去の状態にアクセスするための具体的な方法をご紹介します。
S3インベントリとAthenaで時点スナップショットを作成
過去の状態を再現する一つの方法として、S3インベントリレポートとAthenaを活用した時点スナップショットの作成が考えられます。
S3インベントリ:
バケット内のオブジェクトやそのバージョン情報を、定期的にレポートとして出力します。
Athena:
S3インベントリのレポートをクエリすることで、特定の時点を基準に、どのオブジェクトがどのバージョンだったのかを確認できます。
この組み合わせを使えば、特定の日時におけるバケット内オブジェクトの構成を「スナップショット」として再現することが可能になります。
S3 Object Lambdaで時点アクセスを実現
さらに、S3 Object Lambdaを活用すれば、指定した時点に対応するオブジェクトバージョンを直接取得することも可能です。
S3 Object Lambdaとは?
ユーザーからのリクエストに応じてLambda関数を介し、オブジェクトをオンデマンドで加工・変換して返す仕組みです。
この機能を応用すると、ユーザーが「特定の日時」を指定した際に、その時点に対応するオブジェクトバージョンを自動で取得することができます。これにより、あたかもその時点の状態をリアルタイムで再現するような体験を提供できます。
参考情報
具体的な実装方法や手順については、AWS公式ブログで詳しく解説されています。
Access a point in time with Amazon S3 Object Lambda
上記のAWS公式ブログから引用した構成図:
まとめ
主要な脅威への対策:
ヒューマンエラーや外部攻撃、複雑なアプリケーションが引き起こす問題を想定して、適切なリスク緩和策を適用します。
データの分離と保護:
バケットやAWSリージョン、アカウントごとにデータを分けることで、被害を最小限に抑えられます。また、アクセス権や削除権限を制御することで、誤操作や不正アクセスのリスクも減らせます。
S3の機能を活用する:
- バージョニング: データの上書きや削除のリスクを軽減できます。
- レプリケーション: データを複製し、障害時にも復旧を容易にできます。
- オブジェクトロック: 特定期間、データの変更や削除を防止できます。
- 過去のデータにアクセスできる仕組みを作る: S3インベントリとAthenaを組み合わせれば、特定の時点のデータ状態を再現する「スナップショット」を作れます。また、S3 Object Lambdaを使えば、必要な時点のデータをリアルタイムで取得することもできます。
バックアップで万が一に備える:
バックアップやデータのレプリカを作成しておけば、災害やトラブルがあってもすぐにデータを復元できます。
Amazon S3は「11ナイン」の耐久性を持つ信頼性の高いストレージですが、さらにデータを安全に守り抜くためには、ユーザー側で複数の対策を組み合わせることが大切だと学びました。紹介された対策を、S3におけるレジリエンスを高めるためのガイドラインとして役立てていければと思います。