マルチアカウント環境のAWS Backup設計(ランサムウェア対策)〜CloudTrailとGuardDutyの利用料増加と対処〜(第4回)

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

マルチアカウント環境のAWS Backup設計(ランサムウェア対策)〜おまけ・CloudTrailとGuardDutyの利用料増加と対処〜(第4回)

ソリューションアーキテクト1課の櫻井です。

第1回から第2回第3回にかけて、マルチアカウント環境でのAWS Backupによるランサムウェア対策について、暗号鍵・全体構成・運用の観点でまとめてきました。最終回となる今回は、バックアップの本稼働を開始した後に発覚した、想定外のコスト増加とその対処についてです。

結論から書くと、原因はAWS BackupがS3バックアップ時にオブジェクトのACLとタグを取得する仕様でした。このAPI呼び出しがCloudTrailのデータイベントとして記録され、同じイベントをGuardDutyのS3 Protectionが分析するため、2つのサービスで同時にコストが積み上がる構造になっていました。

なお本記事は実際に構築した環境をもとにしていますが、固有の情報は伏せ、金額は実額ではなく倍率で記載しています。

事象:CloudTrailとGuardDutyの利用料増加

この事象は、私が設計側で気づいたものではなく、コストを確認していた別のメンバーから「CloudTrailとGuardDutyの利用料が増えている」と共有されたことがきっかけでした。そこに、こちらが持っていたバックアップの導入時期の情報を突き合わせたところ、増加の始まりとバックアップ本稼働のタイミングが一致していることが分かり、原因の特定につながっています。

共通基盤環境において、CloudTrailのデータイベント記録と、GuardDutyのS3 Protectionの利用料が増加していました。バックアップ設定完了前の水準に対し、本稼働開始の翌月以降はおよそ3倍で高止まりする状態です。

Cost Explorerで使用タイプごとに分解すると、増えていたのは次の2つでした。

使用タイプ 内容
APN1-DataEventsRecorded CloudTrailのデータイベント記録
APN1-PaidS3DataEventsAnalyzed GuardDutyによるS3データイベントの分析

増加分の内訳は、おおむねCloudTrailが6割、GuardDutyが4割です。AWS Backupの設定が完了したのが3月、本稼働の開始が4月で、コストが跳ね上がった時期とちょうど重なっていました。

原因:AWS BackupによるACL・タグの取得

CloudTrailのログを集計し、データイベントをイベント名ごとに分類したところ、内訳は明確でした。ACLの取得(GetObjectAcl)が約49%、タグの取得(GetObjectTagging)が約48%で、この2つだけで全体の約97%を占めていました。通常のアプリケーションからのGetObjectなどは、割合としてはごくわずかです。

これはAWS Backupの仕様によるものです。AWS BackupでS3をバックアップすると、オブジェクト本体だけでなく、そのオブジェクトに紐づくACLとオブジェクトタグもメタデータとして取得します。このとき、対象オブジェクトごとにGetObjectAclGetObjectTaggingが呼び出されます。初回のフルバックアップでは全オブジェクトに対して、それ以降は変更・追加されたオブジェクトに対して発行される動作です。

オブジェクト数の多いバケットを対象に含めていると、このAPI呼び出しが一気に膨らみます。今回はマルチアカウント環境で幅広くバックアップ対象にしていたため、組織全体で相応の量になっていました。

2つのサービスで同時にコストが増える構造

ここが今回の肝で、私が最初に理解を誤っていた点でもあります。

GetObjectAclGetObjectTaggingは、S3のオブジェクトレベルのAPI操作です。CloudTrailではこれらは「データイベント」に分類され、証跡でデータイベントを記録している場合は、1件ごとに記録の料金が発生します。

一方GuardDutyのS3 Protectionも、CloudTrailのS3データイベントを分析対象としています。ポイントは、GuardDutyがCloudTrailの証跡設定とは独立してデータイベントを取得している点です。AWSのドキュメントにも、S3 Protectionを使うためにCloudTrail側でS3データイベントのログ記録を明示的に有効化する必要はない、と記載されています。

つまり同じ1回のAPI呼び出しに対して、CloudTrailが記録の料金を、GuardDutyが分析の料金を、それぞれ別々に課金する構造です。API呼び出しが増えれば、両方が同時に増えます。

そしてこの独立性は、対処を考えるうえで重要になります。CloudTrail側で記録対象から外しても、GuardDutyはAPI呼び出し自体を独自に見ているため、GuardDutyのコストは減りません。逆に、API呼び出し自体を止めれば両方に効きます。この違いを踏まえて、対処を2段階に分けて整理しました。

ステップ1:CloudTrailの高度なイベントセレクターによる除外

まず着手したのが、CloudTrail側でACL・タグの取得を記録対象から外すことです。証跡を高度なイベントセレクター(Advanced Event Selectors)に移行し、eventNameGetObjectAclGetObjectTaggingを除外します。

高度なイベントセレクターへの移行が必要なのは、従来の基本イベントセレクターではeventNameによる絞り込みができないためです。eventNameでフィルタしたい場合は高度なイベントセレクターを使う必要がある、とドキュメントに明記されています。

CLIでの指定例は次のような形です。

aws cloudtrail put-event-selectors \
  --trail-name <trail-name> \
  --advanced-event-selectors '[
    {
      "Name": "S3 data events (exclude ACL/Tagging reads)",
      "FieldSelectors": [
        { "Field": "eventCategory", "Equals": ["Data"] },
        { "Field": "resources.type", "Equals": ["AWS::S3::Object"] },
        { "Field": "eventName", "NotEquals": ["GetObjectAcl", "GetObjectTagging"] }
      ]
    }
  ]'

実行時の注意点として、このコマンドは証跡のセレクター設定を置き換えます。管理イベントなど他の記録設定もあわせて指定する必要があるため、事前にget-event-selectorsで現行の設定を控えたうえで適用するのが安全です。

この対処で失うのは、ACLとタグに対する「読み取りアクセスの記録」だけです。オブジェクトの書き込み・削除の記録は維持されるので、監査上の追跡可能性への影響は限定的ですし、バックアップの動作やリストア機能にも影響しません。

一方、前述の通りこれはCloudTrailの記録を止めるだけなので、GuardDuty側のコストには効きません。

ステップ2:AWS Backup側でのACL取得の無効化

GuardDutyのコストにも効かせるには、API呼び出し自体を減らす必要があります。そのために、AWS Backup側でACLの取得を無効化します。

AWS Backupには、S3バックアップに含めるメタデータを制御する設定があり、ACLとオブジェクトタグをバックアップ対象から除外できます(2025年9月に追加された機能で、それ以前はどちらも一律で含まれていました)。ACLやタグを使っていないのであれば除外して構わない、というのがAWS側の案内です。設定はマネジメントコンソールとCLIのどちらからでも変更できます。

ACLの取得を止めると、GetObjectAclの呼び出し自体が発生しなくなるため、CloudTrail・GuardDutyの両方に効きます。ステップ1を実施済みであれば、CloudTrail側は既に削減されているので、上乗せ分はGuardDutyのコストということになります。

失うのは、リストア時にオブジェクトのACLを復元できなくなる点です。ただしAWS自体が、バケット所有者に権限を集約してACLを無効化する運用を推奨しているため、実害は限定的だと判断しました。ACLを実際に使って権限管理をしている環境では、この判断は変わります。

なお、今回はタグの取得は残しています。ACLはAWS自身が無効化を推奨しているため除外の判断がしやすいのに対し、オブジェクトタグは実際に運用で使われているケースが多く、除外の可否は個別に確認が必要だからです。タグを使っていない環境であれば、ここも合わせて除外すればさらに削減できます。

この設定変更自体はコンソールまたはCLIで完結しますが、実際に着手する前に必要だったのは、システムの所有者への確認でした。ACLやタグをバックアップに含めないということは、復旧時にそれらを復元できないということです。「その前提で問題ないか」は設計側だけでは判断できないため、対象システムの担当者に確認したうえで実施しています。

コスト削減の施策は、技術的には設定を1つ変えるだけということが少なくありません。ただし今回のように、削減と引き換えに何かの機能が失われる場合、判断の主体は設定を変える側ではなく、その機能を必要とするかどうかを知っている側にあります。手を動かす前に確認する相手を間違えないことが、結果的には早道だと感じました。

検討した選択肢:GuardDuty S3 Protectionの停止

コストだけを見れば、GuardDutyのS3 Protectionを停止するという選択肢もあります。残っているGuardDutyのコストが丸ごとなくなるため、削減幅としては最も大きくなります。

ただし今回は採用しませんでした。S3 Protectionを止めると、S3に対する脅威の自動検知ができなくなります。不審なアクセスやデータ持ち出しの予兆に気づけず、攻撃の初動で発見できないまま被害が拡大してから発覚する、というリスクが上がります。そもそも今回の一連の取り組みはランサムウェア対策として始まったものなので、コスト削減のために検知の仕組みを外すのは本末転倒です。

コスト最適化の選択肢を並べるときには、削減幅だけでなく「何を失うか」を必ず併記して比較するようにしています。今回のように、削減幅としては最大でも採るべきでない選択肢が混ざるためです。

削減の見込み

3つの案を、対処前の月額を1とした比率で並べると次のようになります。

状態 対処前を1とした月額 CloudTrail GuardDuty
現状(対処前) 1.00 - -
ステップ1実施後 約0.4 削減 変化なし
ステップ1+2実施後 約0.2 削減済み 削減
さらにS3 Protection停止 約0.02 削減済み 全額削減(不採用)

ステップ1とステップ2の両方を実施することで、月額はおよそ5分の1になる見込みです。実際にはまずステップ1から着手し、効果を確認したうえでステップ2へ進める形で進めています。

まとめ

今回の内容を振り返ります。AWS BackupでS3をバックアップすると、オブジェクトごとにACLとタグを取得するAPIが発行されます。これがCloudTrailのデータイベント記録とGuardDutyのS3データイベント分析の両方に課金され、コストが増加していました。CloudTrail側だけを絞ってもGuardDutyには効かないため、記録を止めるステップ1と、API呼び出し自体を止めるステップ2の2段構えで対処しています。

私自身の反省ですが、バックアップの設計時には保護の範囲と復旧の確実性ばかりを見ていて、バックアップの実行そのものが周辺サービスの課金を押し上げる、という観点が完全に抜けていました。設計した本人がコスト面の異常に気づけず、別のメンバーからの指摘で発覚した点も含めての反省です。しかも今回のように、1つのAPI呼び出しが複数サービスで別々に課金される構造だと、片方だけ対処しても効果が半分にしかなりません。バックアップに限らず、定期実行される仕組みを新しく入れるときは、その仕組みが発行するAPIがどのログ・監視サービスに流れ込むかまで見ておくべきだったと感じました。

コストが跳ねてから調べる形になりましたが、Cost Explorerで使用タイプまで分解し、CloudTrailのログをイベント名で集計すれば、原因の特定自体は比較的短時間でできます。同じ構成でコストの増加に心当たりがある方は、まずデータイベントの内訳を確認してみてください。

全4回にわたって、マルチアカウント環境でのAWS Backupによるランサムウェア対策をまとめてきました。暗号鍵の制約から構成が決まり、その構成を実装し、適用後のエラーとコストに対処する、という一連の流れが、どなたかの参考になれば幸いです。

参考