SecurityHubの自動修復アクションをカスタムして導入してみた話
はじめに
Septeni Japan株式会社でプロダクト開発&セキュリティエンジニアの市原と申します。前回はSecurityHubの運用フローをアップデートした話をしました。
今回は更にもう一歩踏み込んで、SecurityHub で検出されたセキュリティリスクの修復を自動化することで、SecurityHub での検出から数分以内という極めて短いリードタイムで修復を行い、開発チームのタスク自体を発生させない状態を実現した話となります。
前提
- AWS Organizations 経由でAuditアカウントにSecurityHub の管理権限を委任することで、マルチアカウント運用を実現できている状態
- Audit アカウント・メンバーアカウントに「AWS提供の自動修復ソリューション」を導入するための、Cloud Formation の実行権限やロールの作成権限などを持っている状態
AWS 提供の自動修復ソリューションの概要
出処: Automated Security Response on AWS Implementation Guideより引用
- SecurityHubによる脆弱性の検出
- 検出結果に対応した EventBridge が起動
- Step Functionsが自動修復を実行する Lambda関数を呼び出す
- メンバーアカウントのSSM Document を参照して自動修復を実行
- SNSに結果を送信すると共に、SecurityHubのワークフローステータスを「RESOLVED」に変更
発生した課題
「AWS 提供の自動修復ソリューション」を適用すればそれで自動修復ソリューションの対応は終わりかと思いきや、我々が想定していた挙動と異なる部分があり、デフォルトの仕様では導入できないことが分かりました。その課題とは、例外として「抑制済み」にしたリソースに対しても自動修復アクションが動作してしまうため、例外ケースの運用が一切できなくなるという点でした。
解決策の概要
そこで、「AWS 提供の自動修復ソリューション」をカスタマイズすることで、「抑制済み」の場合は自動修復の実行をスキップする仕様に変更を行いました。
通常の状態遷移パターン
- ユーザーによるリソースの作成・変更
- AWS SecurityHubによる検出
- 自動修復アクションによるリソースの修復
解決後の状態遷移パターン
- ユーザーがリソースの作成・変更
- AWS SecurityHubによる検出
- 自動修復アクションによるリソースの修復
- ユーザーが検出結果のワークフローステータスを抑制済みに変更
- 自動修復されたリソースの設定を元に戻す
- 状態としては非準拠となるが自動修復アクションは動作しない
- 再度自動修復の対象としたい場合はワークフローステータスを解決済みに変更
解決策の詳細
スキップ処理を適用したコードは Github に公開していますので、カスタマイズされる際の参考なれば幸いです。なお、ソリューションのデプロイ方法は幾つかありますが、当社では CloudFormation StackSetsを利用しています。詳細は こちらのページを参照してください。 ※デプロイ方法はAutomated Security Response on AWSのGitHubのREADMEを参照してください
それでは、主な改修箇所を紹介していきます。
Orchestrator の Step Functions にステップを追加
デフォルトの状態では、Finding WorkFlow State NEW? の後に、Get Remediation Approval Requirement に処理が流れますが、その間に以下2つのステップを追加しました。
- Get Latest Finding Workflow SUPPRESSED: リソースが「抑制済み」かどうかの判定
- Remediation skip or execute?: 「抑制済み」の場合に処理をスキップ
1. Get Latest Finding Workflow SUPPRESSEDの処理
対象のFindingのうち、同じアカウントID、かつ、同じリソースで直近のFindingのワークフローステータスがSUPPRESSEDであれば、SKIPPEDをメッセージと共にレスポンスの中に含める。それ以外の場合はEXECUTEをメッセージと共にレスポンスに含める。
if latest_workflow_status is None:
return {"status": "EXECUTE", "message": "Past findings not found."}
elif latest_workflow_status == "SUPPRESSED":
return {"status": "SKIPPED", "message": "Latest finding is suppressed."}
else:
return {"status": "EXECUTE", "message": f'Latest finding is {latest_workflow_status}.'}
checkWorkflowNew.when(
sfn.Condition.or(
sfn.Condition.stringEquals('$.EventType', 'Security Hub Findings - Custom Action'),
sfn.Condition.and(
sfn.Condition.stringEquals('$.Finding.Workflow.Status', 'NEW'),
sfn.Condition.stringEquals('$.EventType', 'Security Hub Findings - Imported'),
),
),
getLastWorkflowStateSuppressed,
);
checkWorkflowNew.otherwise(docNotNew);
getLastWorkflowStateSuppressed.next(checkExecSkip);
2. Remediation skip or execute?の処理
Get Latest Finding Workflow SUPPRESSEDでレスポンスに追加したStateがEXECUTEであれば、getApprovalRequirementへ、SKIPPEDであれば、notifyへ分岐させる。
const checkExecSkip = new sfn.Choice(this, 'Remediation skip or execute?');
checkExecSkip.when(sfn.Condition.stringEquals('$.Notification.State', 'EXECUTE'), getApprovalRequirement);
checkExecSkip.when(sfn.Condition.stringEquals('$.Notification.State', 'SKIPPED'), notify);
CloudFormation StackSetsで複数リージョンにデプロイできるように修正
CloudFormation StackSets を使用することで、複数のメンバーアカウントに対して一括でソリューションをデプロイすることが可能となります。
しかし、複数のリージョンにデプロイしようとすると Orchestrator RoleとCloudWatch Dashboardを作成する工程で、「作成しようとしているリソースと、同一のリソースが既に存在する」というエラーが発生しました。これは通常、RoleやCloudWatch Dashboardはグローバルで管理されており、リージョン毎にリソースを作成する際に重複したリソースとしてエラーになるためです。
こちらの回避策として、リソース名の末尾にリージョン名を記載する処理を追加しました。
Orchestrator Role
const orchestratorRole = new Role(this, 'orchestratorRole', {
assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
description: 'Lambda role to allow cross account read-only SHARR orchestrator functions',
roleName: `${RESOURCE_PREFIX}-SHARR-Orchestrator-Admin-${this.region}`,
});
CloudWatch Dashboard
const remediationDashboard = new Dashboard(scope, 'RemediationDashboard', {
dashboardName: `ASR-Remediation-Metrics-Dashboard-${region}`,
defaultInterval: Duration.days(7),
});
まとめ
「AWS 提供の自動修復ソリューション」をカスタマイズすることにより、自動修復アクションによる迅速なセキュリティリスクへの対処と、自動修復を適用外としたい例外ケースをうまく融合させることができました。
今後の課題
新規で作成したアカウントを自動修復ソリューションの適用対象とするには、以下のような手作業が発生するため、自動化を検討したいと考えています。
- 対象アカウントにCloudFormation StackSetsの実行ロールを付与
- CloudFormation StackSets のパラメータに新規作成したアカウントIDを登録して実行
Discussion