terraform-aws-security-hub-report

Operations

Run on demand

aws stepfunctions start-execution --state-machine-arn <state_machine_arn>

The execution history in the Step Functions console shows each account’s collect step and its error, if any. A scheduled run is identical; the EventBridge rule just calls StartExecution.

Reading the notification

Security Hub report ready for Hubbsters (with failures)
Accounts: 298 succeeded, 2 failed of 300
Findings: 41873
S3 path: s3://example-logging-bucket/SecurityHubReports/2026/09/15/Hubbsters-Security-Hub-Findings.xlsx
Download: aws s3 cp s3://example-logging-bucket/SecurityHubReports/2026/09/15/Hubbsters-Security-Hub-Findings.xlsx .
Failed accounts: 111111111111, 222222222222

Troubleshooting

Symptom Where to look Usual cause
Account error with assume_role: ... AccessDenied Summary sheet Errors column SecurityHubReadOnlyCrossAccount is missing in that account or trusts the wrong collector role ARN. Redeploy the CloudFormation template there.
Account partial with <region>: ... InvalidAccessException Summary sheet Errors column Security Hub is not enabled in that region for that account. Enable it or drop the region from report_regions.
Account missing Summary sheet collect crashed outright (timeout, out of memory). Check the collect log group for the account ID and the Step Functions execution for CollectCrashed.
Account crashed in the execution history Step Functions console Same as missing, seen from the state machine side.
Failure notification Environment variable X is required but not set discover/aggregate logs A tfvars value is empty. Every env var is rendered from variables in lambda.tf.
Failure notification with No accounts to report on discover logs account_ids is empty and the deploying account is not the management or delegated admin account, or has no ACTIVE accounts.
Report present but no Slack/Teams message aggregate logs Webhook rejected the payload; the log line has the HTTP status. SNS is still published.
aggregate runs out of memory aggregate logs Raise memory_size for aggregate in lambda.tf. 1024 MB handles several hundred thousand rows.

The part file for any account is at s3://<out_bucket>/SecurityHubReports/YYYY/MM/DD/parts/<HHMMSS>/<account>.json and contains the same status, errors and findings the Summary sheet was built from.

Log groups are /aws/lambda/<cust_name>-security-hub-report-<function> with log_retention_days retention.

Monitoring

Nothing is alarmed by design (cost). Two signals are worth watching if you want to add alarms later:

Limits