- 公開日
- 最終更新日
【Step Functions】Security Hub CSPMの通知件名カスタマイズ・ワークフローステータスの自動変更
この記事を共有する
目次
はじめに
こんにちは。サービスGの中野です。
AWS Security Hub(CSPM)でSNS通知を設定されている方は多いと思いますが、いざ運用を始めると以下のような課題に直面するのではないでしょうか。
- 同じ内容の通知が、とめどなく届く
- 件名が一律(AWS Notification Message)で、何の通知か開くまで分からない
- 本文がJSONの塊で、パッと見での解読がしんどい
本文の見づらさだけであれば、EventBridgeの「入力トランスフォーマー」で手軽に整形できますが、件名のカスタマイズは思いのほかEventBridgeではできません。
また、通知の重複を防ぐために、「ワークフローステータスが NEW のものだけを通知し、通知後にステータスをNOTIFIEDに自動更新」したいとなれば、Lambda使うしかないか、、と諦めていました。
しかし、Step Functionsを使えば、Lambdaを導入せずとも超簡単にこれらすべてを解決できることが分かったので、備忘録を兼ねて実際に実装したStep Functionsの定義を記録します。
構成図
以下が構成図です。

参考までに、SNSトピック、EventBridge、Step Functions、それぞれのサービスが使うIAMロールを定義したCloudFormationのテンプレートを以下に記載しておきます。(リソース名などべた書きですがご了承ください)
CloudFormationテンプレート
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
# ===========================================================================
# Common Configuration
# ===========================================================================
email:
Type: String
Description: email address
Default: xxx
Resources:
# ===========================================================================
# Create SNS Topic
# ===========================================================================
# SNS Topic for Security Monitoring
SecurityMonitoringSNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: sns-topic-security-alert
DisplayName: Security Hub High Severity Alerts
KmsMasterKeyId: alias/aws/sns
# HTTPS Subscription for SNS Topic
SecurityMonitoringHTTPSSubscription:
Type: AWS::SNS::Subscription
Properties:
Protocol: email
TopicArn: !Ref SecurityMonitoringSNSTopic
Endpoint: !Ref email
SecurityMonitoringSNSTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref SecurityMonitoringSNSTopic
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AllowStepFunctionsPublish
Effect: Allow
Principal:
Service: states.amazonaws.com
Action: sns:Publish
Resource: !Ref SecurityMonitoringSNSTopic
# ===========================================================================
# IAM Role for Step Functions
# ===========================================================================
SecurityAlertStateMachineRole:
Type: AWS::IAM::Role
Properties:
RoleName: iam-role-sfn-security-alert
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: states.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
aws:SourceArn: !Sub arn:aws:states:${AWS::Region}:${AWS::AccountId}:stateMachine:sfn-security-alert
Policies:
- PolicyName: iam-policy-sfn-security-alert
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- sns:Publish
Resource: !Ref SecurityMonitoringSNSTopic
- Effect: Allow
Action:
- securityhub:BatchUpdateFindings
Resource: !Sub arn:aws:securityhub:${AWS::Region}:${AWS::AccountId}:hub/default
# ===========================================================================
# IAM Role for EventBridge
# ===========================================================================
EventBridgeStateMachineRole:
Type: AWS::IAM::Role
Properties:
RoleName: iam-role-eb-sfn
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: events.amazonaws.com
Action: sts:AssumeRole
Condition:
StringEquals:
aws:SourceArn: !Sub arn:aws:events:${AWS::Region}:${AWS::AccountId}:rule/eb-rule-security-alert
Policies:
- PolicyName: iam-policy-eb-sfn
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- states:StartExecution
Resource: !Ref SecurityAlertStateMachine
# ===========================================================================
# Step Functions State Machine
# ===========================================================================
SecurityAlertStateMachine:
Type: AWS::StepFunctions::StateMachine
Properties:
StateMachineName: sfn-security-alert
RoleArn: !GetAtt SecurityAlertStateMachineRole.Arn
DefinitionString: !Sub |
{
"Comment": "Security Hub 検出結果のSNS通知とワークフローステータスの更新(NEW⇒NOTIFIED)",
"StartAt": "FormatAndPublishToSNS",
"States": {
"FormatAndPublishToSNS": {
"Type": "Task",
"Resource": "arn:aws:states:::sns:publish",
"Parameters": {
"TopicArn": "${SecurityMonitoringSNSTopic}",
"Subject.$": "States.Format('[SecurityHub] {} アカウントで {} が検出されました({})', $.detail.findings[0].AwsAccountId, $.detail.findings[0].FindingProviderFields.Severity.Label, $.detail.findings[0].Region)",
"Message.$": "States.Format('AWS Security Hubで以下が検出されました。\n\n・タイトル: {}\n・製品名: {}\n・検出内容: {}\n・重要度: {}\n・AWSアカウント: {}\n・リージョン: {}\n・リソース: {}\n\n・詳細は以下のURLにアクセスしてください (対象アカウントへのログインが必要です)。\nhttps://ap-northeast-1.console.aws.amazon.com/securityhub/home?region=ap-northeast-1#/findings?search=Id%3D%255Coperator%255C%253AEQUALS%255C%253A{}', $.detail.findings[0].Title, $.detail.findings[0].ProductName, $.detail.findings[0].Description, $.detail.findings[0].FindingProviderFields.Severity.Label, $.detail.findings[0].AwsAccountId, $.detail.findings[0].Region, $.detail.findings[0].Resources[0].Id, $.detail.findings[0].Id)"
},
"Next": "UpdateWorkflowStatus",
"ResultPath": "$.snsResult"
},
"UpdateWorkflowStatus": {
"Type": "Task",
"Resource": "arn:aws:states:::aws-sdk:securityhub:batchUpdateFindings",
"Parameters": {
"FindingIdentifiers": [
{
"Id.$": "$.detail.findings[0].Id",
"ProductArn.$": "$.detail.findings[0].ProductArn"
}
],
"Workflow": {
"Status": "NOTIFIED"
},
"Note": {
"Text": "通知済み",
"UpdatedBy": "Step Functions"
}
},
"End": true,
"ResultPath": "$.updateResult"
}
}
}
# ===========================================================================
# Create EventBridge Rule
# ===========================================================================
SecurityHubHighSeverityRule:
Type: AWS::Events::Rule
Properties:
Name: eb-rule-security-alert
Description: Rule to detect high severity events (CRITICAL and HIGH) from Security Hub
EventBusName: default
State: ENABLED
EventPattern:
detail-type:
- Security Hub Findings - Imported
source:
- aws.securityhub
detail:
findings:
Compliance:
Status:
- anything-but: PASSED
- exists: false
RecordState:
- ACTIVE
Workflow:
Status:
- NEW
Severity:
Label:
- CRITICAL
- HIGH
Targets:
- Id: SecurityAlertStateMachine
Arn: !Ref SecurityAlertStateMachine
RoleArn: !GetAtt EventBridgeStateMachineRole.Arn
# ===========================================================================
# Outputs
# ===========================================================================
Outputs:
SNSTopicArn:
Description: ARN of the SNS topic for security monitoring
Value: !Ref SecurityMonitoringSNSTopic
SNSTopicName:
Description: Name of the SNS topic
Value: !GetAtt SecurityMonitoringSNSTopic.TopicName
SubscriptionArn:
Description: ARN of the HTTPS subscription
Value: !Ref SecurityMonitoringHTTPSSubscription
StateMachineArn:
Description: ARN of the Step Functions state machine
Value: !Ref SecurityAlertStateMachine
RuleName:
Description: Name of the EventBridge rule
Value: !Ref SecurityHubHighSeverityRule
RuleArn:
Description: ARN of the EventBridge rule
Value: !GetAtt SecurityHubHighSeverityRule.Arn
Step Functionsの定義
以下が定義の内容です。
{
"Comment": "Security Hub 検出結果のSNS通知とワークフローステータスの更新(NEW⇒NOTIFIED)",
"StartAt": "FormatAndPublishToSNS",
"States": {
"FormatAndPublishToSNS": {
"Type": "Task",
"Resource": "arn:aws:states:::sns:publish",
"Parameters": {
"TopicArn": "arn:aws:sns:ap-northeast-1:<アカウントID>:sns-topic-security-alert",
"Subject.$": "States.Format('[SecurityHub] {} アカウントで {} が検出されました({})', $.detail.findings[0].AwsAccountId, $.detail.findings[0].FindingProviderFields.Severity.Label, $.detail.findings[0].Region)",
"Message.$": "States.Format('AWS Security Hubで以下が検出されました。\n\n・タイトル: {}\n・製品名: {}\n・検出内容: {}\n・重要度: {}\n・AWSアカウント: {}\n・リージョン: {}\n・リソース: {}\n\n・詳細は以下のURLにアクセスしてください (対象アカウントへのログインが必要です)。\nhttps://ap-northeast-1.console.aws.amazon.com/securityhub/home?region=ap-northeast-1#/findings?search=Id%3D%255Coperator%255C%253AEQUALS%255C%253A{}', $.detail.findings[0].Title, $.detail.findings[0].ProductName, $.detail.findings[0].Description, $.detail.findings[0].FindingProviderFields.Severity.Label, $.detail.findings[0].AwsAccountId, $.detail.findings[0].Region, $.detail.findings[0].Resources[0].Id, $.detail.findings[0].Id)"
},
"Next": "UpdateWorkflowStatus",
"ResultPath": "$.snsResult"
},
"UpdateWorkflowStatus": {
"Type": "Task",
"Resource": "arn:aws:states:::aws-sdk:securityhub:batchUpdateFindings",
"Parameters": {
"FindingIdentifiers": [
{
"Id.$": "$.detail.findings[0].Id",
"ProductArn.$": "$.detail.findings[0].ProductArn"
}
],
"Workflow": {
"Status": "NOTIFIED"
},
"Note": {
"Text": "通知済み",
"UpdatedBy": "Step Functions"
}
},
"End": true,
"ResultPath": "$.updateResult"
}
}
}
本ステートマシーンで実行される処理のステップ "States" は、以下の2つのみです。

- SNS通知用の
"FormatAndPublishToSNS" - ワークフローステータスの変更用の
"UpdateWorkflowStatus"
なお、"FormatAndPublishToSNS" 内の "Subject.$" と "Message.$" で States.Format を利用して通知内容を整形しており、こちらの定義をそのまま利用すると以下のような通知内容になります。
件名例:
[SecurityHub] 123456789012 アカウントで HIGH が検出されました(ap-northeast-1)
本文例:
AWS Security Hubで以下が検出されました。
・タイトル: xxx
・製品名: Security Hub (Inspector、Guardduty 等)
・検出内容: xxx
・重要度: HIGH
・AWSアカウント: 123456789012
・リージョン: ap-northeast-1
・リソース: AWS::::Account:123456789012
・詳細は以下のURLにアクセスしてください (対象アカウントへのログインが必要です)。
https://ap-northeast-1.console.aws.amazon.com/securityhub/home?region=ap-northeast-1#/xxx
おわりに
Step Functionsを使えばランタイムの管理も不要になり、とても便利だと感じました。
より複雑なロジックを入れたい場合はLambdaでの実装が必要になることも多いかと思いますが、単純な処理であればまずは一度Step Functionsでできないかを検討していきたいと思います。
この記事は私が書きました
中野 友加里
記事一覧身体動かすの好きです。頑張って同じくらい頭も動かします。