ASR(Automated Security Response on AWS)のKMSコスト問題を、Member StackSet自前化で回避する
はじめに
みなさん、Security Hub の検出結果を自動修復してくれる AWS 公式ソリューション ASR(Automated Security Response on AWS) はご存知でしょうか。
私は最近このソリューションをマルチアカウント・マルチリージョン環境に展開しようとしたのですが、コスト課題に直面しました。試算の結果このまま全リージョン・全アカウントに展開すると、KMS の料金だけで年数十万 になってしまうことがわかりました。
今回はこの課題を、Member 側の StackSet だけを、自前 CDK 実装に置き換えることで解決した話をご紹介します。
ASR(Automated Security Response on AWS)とは
ASR は、Security Hub の検出結果(Finding)に対して自動修復アクションを実行する AWS 公式ソリューションです。AWS Solutions Library から提供されており、以下のような修復を自動で実行できます。
- S3 バケットへの SSL ポリシー強制適用(S3.5)
- RDS インスタンスのパブリックアクセス無効化(RDS.1/2)
- Lambda 関数のパブリックアクセス削除(Lambda.1)
- EC2 セキュリティグループのルール修正(EC2.2/15/18/19/23)
- IAM の未使用の認証情報を失効させる処理(IAM.8)
上記以外にも多くの対応コントロールが存在します。
Admin / Member の 2 層構成
ASR は Admin 側と Member 側の 2 つのコンポーネントで構成されています。
| コンポーネント | 役割 | デプロイ先 |
|---|---|---|
| Admin | Finding 受信・オーケストレーション・修復 Lambda の管理 | 管理アカウント |
| Member | 各アカウントでの実際の修復実行。IAM Role を作成するスタックと SSM Document を展開するスタックの 2 種類をデプロイ | 各メンバーアカウント × 対象リージョン |
Security Hub で Finding を検出すると、Admin 側の Lambda が SSM Automation Document を特定して Member アカウントへ指示します。実際の修復処理は Member 側の IAM Role が担当します。
課題:Member StackSet が必ず作るカスタマーマネージドキーのコスト
公式 ASR の Member StackSet をデプロイすると、各アカウント・各リージョンに カスタマーマネージドキー が作成されます。このキーは自動修復で SNS トピックや CloudWatch Logs の暗号化に使われます。
逆に言えば、これらのコントロールが修復対象でないならば不要なリソースです。
カスタマーマネージドキーの課金構造
カスタマーマネージドキーは リージョン単位・キー単位で月額課金 されます。
- 料金:約 $1 / キー / 月
- カスタマーマネージドキーはアカウントをまたいで共用できない(アカウント内に作成される)
つまり Member StackSet をデプロイしたアカウントとリージョンの数だけカスタマーマネージドキーが増え続けます。
展開規模を想定したコスト試算です。
| 想定規模 | リージョン数 | アカウント数 | KMS キー数 | 月額コスト | 年間コスト |
|---|---|---|---|---|---|
| 小規模 | 2 | 10 | 20 | $20 | $240 |
| 中規模 | 5 | 50 | 250 | $250 | $3,000 |
| 大規模 | 17 | 100 | 1,700 | $1,700 | $20,400 |
(大規模想定の $20,400 ≒ 約 315 万円、1 ドル≒155 円換算)
ほとんどのケースでリージョン制限で全リージョン展開することはないですが、中規模だけでも相当なコストになります。
自動修復を動かすためだけに置かれたカスタマーマネージドキーにこのコストを支払うのは、さすがに見合わないと判断して対応することにしました。
解決アプローチ:どこを自前化し、どこを流用するか
この問題を解決するにあたり、まず「本当にカスタマーマネージドキーが必要か」を整理しました。
実際に使いたい修復コントロールを確認すると、修復対象のコントロール自体は KMS に依存していない ことがわかりました。カスタマーマネージドキーが作られているのはあくまで暗号化のためです。
そこで以下の方針を決めました。
方針:Admin 側は流用、Member 側だけ自前化
- Admin 側:変更なし。公式ソリューションをそのまま利用
- Member 側 StackSet:CDK で自前実装。カスタマーマネージドキーの作成を廃止
Admin 側には SSM Automation Document のオーケストレーションや Orchestrator Lambda など重要なロジックが集まっています。ここを自前化すると公式追従のコストが非常に大きいため、変更なしで流用します。
Member 側の主な役割は「SSM Document(runbook)と IAM Role の展開」です。KMS キーを自動修復で利用しないコントロールを自前化することで、カスタマーマネージドキーの作成をスキップできます。
自前化アーキテクチャの設計
自前化した Member StackSet のアーキテクチャについて説明します。
大まかな流れはこうです。
- 公式 runbook を取り込んで CloudFormation テンプレートを生成する
- Admin アカウントの S3 バケットにテンプレートを配置する(CDK デプロイ時に自前で作成)
- StackSet でテンプレートの S3 URL を参照し、各メンバーアカウント・各リージョンに展開する
(1) 公式 runbook の取り込みとテンプレートビルダー
公式 ASR の修復処理は SSM Automation Document(runbook) に実装されています。このロジックを独自に再実装すると公式のバグ修正や挙動変更に追従できなくなるため、「公式の SSM Document をそのまま取り込んで使う」方針にしました。
取り込みフロー
専用の取り込みスクリプトで自動化しています。
公式 ASR の SSM Document は CloudFormation テンプレート内に定義されています。そのため公式リポジトリを指定バージョンで clone し、cdk synth を実行して CFn テンプレートを生成します。そこから対象コントロールの SSM Document を抽出し、CloudFormation 組み込み関数(Ref / Fn::Join)を解決します。最終的に CDK から直接参照できる完成形の YAML に変換します。
生成される YAML は以下の 3 種類です。
| 種類 | 役割 |
|---|---|
| outer YAML | Admin Orchestrator から起動される入口 Document。ASR-SC_2.0.0_{ControlId} という名前で展開される |
| inner YAML | outer から呼ばれ、実際の修復処理を実行する Document |
| scripts(Python) | inner に埋め込まれる修復実装。デプロイ時に inner YAML 内に展開される |
CDK のテンプレートビルダーがこれらの YAML を読み込み、各コントロールの CloudFormation テンプレートを動的に生成します。生成されるテンプレートには SSM Automation Document と IAM Role(修復実行用)が含まれます。
(2) テンプレートの配置と StackSet 展開
生成したテンプレートは必要なコントロールのみ Admin アカウントの S3 バケットに配置します。StackSet はこの S3 URL を参照してメンバーアカウントへスタックを展開します。
Admin アカウント
├── S3 バケット(CDK デプロイ時に自前作成)
│ ├── SC_S3.5_iam-role.yaml(IAM Role スタック)
│ ├── SC_S3.5_ssm-doc.yaml(SSM Document スタック)
│ ├── SC_RDS.1_iam-role.yaml
│ ├── SC_RDS.1_ssm-doc.yaml
│ └── ...(コントロール × 2 スタック分)
└── StackSet → 各メンバーアカウント × 各リージョンに展開
S3 バージョニングを有効化してテンプレートの更新を追跡できます。
補足: テンプレートが 51,200 バイト未満の場合、S3 を使わず
TemplateBody(インライン)で StackSet を直接展開することも可能です。また、cdk-stacksets のStackSetStackを使う場合は CDK の bootstrap バケットが自動的に使われるため、専用 S3 バケットの新規作成は不要です。
アップデート方法
Member StackSet を自前実装にした代償として、公式 ASR のアップデートを反映する手順が変わります。もともと StackSet は公式スタックのアップデートを自動適用する仕組みではないため、自前化の前後を問わず公式の新バージョンへの追従は手動で行う必要があります。
変わるのは「公式ソリューションを再デプロイする」から「自前の runbook・テンプレートを最新版に合わせて更新する」という手順です。Admin スタックは通常の更新方法で問題ありません。
旧 ASR との並行運用は不可
既存のメンバーアカウントに旧 ASR(aws-sharr-member)が展開されている場合、新しい自前実装 StackSet をそのまま追加展開すると FAILED になります。
原因は固定名リソースの衝突です。
| 衝突するリソース | リソース名 |
|---|---|
| SSM Document | ASR-SC_2.0.0_*(コントロールごとに固定名) |
| IAM Role | SO0111-ASR-Orchestrator-Member |
これらは公式 ASR の命名規則で固定されており、変更できません。
移行は旧 StackSet を削除してから新 StackSet を展開が必須です。「新旧を並行運用しながら切り替え」という方針は取れませんでした。すでに展開している場合は注意が必要です。
まとめ
ASR の Member StackSet を自前 CDK 実装に置き換えて、カスタマーマネージドキーの作成を廃止しました。この実装で大幅にメンバーアカウントのコスト削減を見込めるようになりました。
今回の取り組みで感じた教訓は「公式ソリューションは 全部使う か 全部捨てる かの二択ではない」ということです。ソリューションの層を理解して「どこを流用し、どこを自前化するか」を判断することで、コストとメンテナンス負荷のバランスが取れます。
同じ課題(ASR のマルチアカウント展開でのコスト最適化)を検討されている方の参考になれば嬉しいです。
以上、鈴木純がお送りしました。








