Overview
AWS Security Hub provides a comprehensive view of security alerts and compliance status across AWS accounts. It aggregates findings from AWS security services and third-party tools, enabling centralized security management and automated remediation.
Who Should Use This Guide:
- Cloud security engineers securing AWS environments
- Security operations teams managing multi-account AWS
- Compliance officers monitoring cloud security posture
- DevSecOps engineers automating security workflows
Security Hub Capabilities:
| Feature | Description |
|---|---|
| Aggregated Findings | Centralize findings from AWS services |
| Security Standards | CIS, PCI DSS, NIST, AWS Foundational |
| Custom Insights | Create custom security metrics |
| Cross-Account | Aggregate findings across AWS Organization |
| Automation | EventBridge rules for auto-remediation |
| Third-Party | Integrate with partner security tools |
Integrated AWS Services:
| Service | Finding Types |
|---|---|
| GuardDuty | Threat detection, anomalies |
| Inspector | Vulnerability findings |
| Macie | Sensitive data exposure |
| IAM Access Analyzer | External access, unused permissions |
| Firewall Manager | Firewall policy violations |
| Config | Resource configuration issues |
| Systems Manager | Patch compliance |
Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ AWS Security Hub Architecture │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ AWS Account (Member) AWS Account (Member) │
│ ┌────────────────────┐ ┌────────────────────┐ │
│ │ ┌──────────┐ │ │ ┌──────────┐ │ │
│ │ │GuardDuty │ │ │ │Inspector │ │ │
│ │ └────┬─────┘ │ │ └────┬─────┘ │ │
│ │ │ │ │ │ │ │
│ │ ┌────▼─────┐ │ │ ┌────▼─────┐ │ │
│ │ │Security │ │ │ │Security │ │ │
│ │ │Hub Local │ │ │ │Hub Local │ │ │
│ │ └────┬─────┘ │ │ └────┬─────┘ │ │
│ └────────┼───────────┘ └────────┼───────────┘ │
│ │ │ │
│ └────────────────┬───────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ Security Hub Administrator Account │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ Aggregated Findings │ │ │
│ │ │ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ │ │
│ │ │ │ Critical │ │ High │ │ Medium │ │ │ │
│ │ │ │ 23 │ │ 156 │ │ 892 │ │ │ │
│ │ │ └───────────┘ └───────────┘ └───────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ Security Standards │ │ │
│ │ │ □ AWS Foundational □ CIS Benchmark □ PCI DSS │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ EventBridge → Lambda → Remediation │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘Step 1: Enable Security Hub
Enable via AWS CLI
# Enable Security Hub in the current region
aws securityhub enable-security-hub \
--enable-default-standards \
--region us-east-1
# Verify Security Hub is enabled
aws securityhub describe-hub \
--region us-east-1Enable via Terraform
# main.tf
provider "aws" {
region = "us-east-1"
}
resource "aws_securityhub_account" "main" {}
resource "aws_securityhub_standards_subscription" "cis" {
depends_on = [aws_securityhub_account.main]
standards_arn = "arn:aws:securityhub:us-east-1::standards/cis-aws-foundations-benchmark/v/1.4.0"
}
resource "aws_securityhub_standards_subscription" "aws_foundational" {
depends_on = [aws_securityhub_account.main]
standards_arn = "arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0"
}
resource "aws_securityhub_standards_subscription" "pci_dss" {
depends_on = [aws_securityhub_account.main]
standards_arn = "arn:aws:securityhub:us-east-1::standards/pci-dss/v/3.2.1"
}Enable in Multiple Regions
#!/bin/bash
# enable-securityhub-all-regions.sh
REGIONS=$(aws ec2 describe-regions --query "Regions[].RegionName" --output text)
for region in $REGIONS; do
echo "Enabling Security Hub in $region..."
aws securityhub enable-security-hub \
--enable-default-standards \
--region $region 2>/dev/null || echo "Already enabled or error in $region"
doneStep 2: Configure Security Standards
Available Security Standards
| Standard | ARN | Focus |
|---|---|---|
| AWS Foundational | standards/aws-foundational-security-best-practices/v/1.0.0 | AWS best practices |
| CIS AWS Foundations | standards/cis-aws-foundations-benchmark/v/1.4.0 | CIS hardening |
| PCI DSS | standards/pci-dss/v/3.2.1 | Payment card compliance |
| NIST 800-53 | standards/nist-800-53/v/5.0.0 | Federal security |
Enable Specific Standards
# Get available standards ARNs
aws securityhub describe-standards \
--region us-east-1 \
--query "Standards[].StandardsArn"
# Enable AWS Foundational Best Practices
aws securityhub batch-enable-standards \
--standards-subscription-requests '[
{"StandardsArn": "arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0"}
]' \
--region us-east-1
# Enable CIS Benchmark
aws securityhub batch-enable-standards \
--standards-subscription-requests '[
{"StandardsArn": "arn:aws:securityhub:us-east-1::standards/cis-aws-foundations-benchmark/v/1.4.0"}
]' \
--region us-east-1Disable Specific Controls
# List controls for a standard
aws securityhub describe-standards-controls \
--standards-subscription-arn "arn:aws:securityhub:us-east-1:123456789012:subscription/aws-foundational-security-best-practices/v/1.0.0" \
--query "Controls[?ControlStatus=='ENABLED'].{Id:ControlId,Title:Title}" \
--region us-east-1
# Disable a control (if not applicable)
aws securityhub update-standards-control \
--standards-control-arn "arn:aws:securityhub:us-east-1:123456789012:control/aws-foundational-security-best-practices/v/1.0.0/IAM.6" \
--control-status DISABLED \
--disabled-reason "Not applicable - using SSO for user management" \
--region us-east-1Step 3: Integrate AWS Security Services
Enable GuardDuty Integration
# Enable GuardDuty
aws guardduty create-detector \
--enable \
--finding-publishing-frequency FIFTEEN_MINUTES \
--region us-east-1
# GuardDuty findings automatically appear in Security Hub
# Verify integration
aws securityhub describe-products \
--region us-east-1 \
--query "Products[?ProductName=='GuardDuty']"Enable Inspector Integration
# Enable Inspector for EC2 and ECR
aws inspector2 enable \
--resource-types EC2 ECR LAMBDA \
--region us-east-1
# Verify integration
aws securityhub list-enabled-products-for-import \
--region us-east-1Enable IAM Access Analyzer
# Create analyzer
aws accessanalyzer create-analyzer \
--analyzer-name org-analyzer \
--type ORGANIZATION \
--region us-east-1
# Findings flow to Security Hub automaticallyEnable Macie
# Enable Macie
aws macie2 enable-macie \
--finding-publishing-frequency FIFTEEN_MINUTES \
--region us-east-1
# Create discovery job for S3 buckets
aws macie2 create-classification-job \
--job-type SCHEDULED \
--name "s3-sensitive-data-scan" \
--s3-job-definition '{
"bucketDefinitions": [{
"accountId": "123456789012",
"buckets": ["my-data-bucket"]
}]
}' \
--schedule-frequency '{"dailySchedule": {}}' \
--region us-east-1Step 4: Multi-Account Setup (AWS Organizations)
Designate Administrator Account
# From Organizations management account
aws securityhub enable-organization-admin-account \
--admin-account-id 123456789012 \
--region us-east-1Enable for All Organization Accounts
# From administrator account - auto-enable for new accounts
aws securityhub update-organization-configuration \
--auto-enable \
--region us-east-1
# Enable for existing accounts
aws securityhub create-members \
--account-details '[
{"AccountId": "111111111111"},
{"AccountId": "222222222222"}
]' \
--region us-east-1Create Aggregator Region
# Designate aggregator region
aws securityhub create-finding-aggregator \
--region us-east-1 \
--region-linking-mode ALL_REGIONS
# Or specific regions only
aws securityhub create-finding-aggregator \
--region us-east-1 \
--region-linking-mode SPECIFIED_REGIONS \
--regions us-east-1 us-west-2 eu-west-1Step 5: View and Manage Findings
Query Findings via CLI
# Get all critical findings
aws securityhub get-findings \
--filters '{
"SeverityLabel": [{"Value": "CRITICAL", "Comparison": "EQUALS"}]
}' \
--region us-east-1 \
--query "Findings[].{Title:Title,Resource:Resources[0].Id,Account:AwsAccountId}"
# Get findings for specific resource
aws securityhub get-findings \
--filters '{
"ResourceId": [{"Value": "arn:aws:s3:::my-bucket", "Comparison": "EQUALS"}]
}' \
--region us-east-1
# Get failed compliance checks
aws securityhub get-findings \
--filters '{
"ComplianceStatus": [{"Value": "FAILED", "Comparison": "EQUALS"}],
"RecordState": [{"Value": "ACTIVE", "Comparison": "EQUALS"}]
}' \
--region us-east-1Update Finding Status
# Mark finding as resolved
aws securityhub batch-update-findings \
--finding-identifiers '[
{
"Id": "arn:aws:securityhub:us-east-1:123456789012:finding/12345",
"ProductArn": "arn:aws:securityhub:us-east-1::product/aws/securityhub"
}
]' \
--workflow '{"Status": "RESOLVED"}' \
--region us-east-1
# Suppress finding (false positive)
aws securityhub batch-update-findings \
--finding-identifiers '[{"Id": "...", "ProductArn": "..."}]' \
--workflow '{"Status": "SUPPRESSED"}' \
--note '{"Text": "False positive - verified manually", "UpdatedBy": "security-team"}' \
--region us-east-1Step 6: Create Custom Insights
Create Insight via CLI
# Critical findings by account
aws securityhub create-insight \
--name "Critical Findings by Account" \
--filters '{
"SeverityLabel": [{"Value": "CRITICAL", "Comparison": "EQUALS"}],
"RecordState": [{"Value": "ACTIVE", "Comparison": "EQUALS"}]
}' \
--group-by-attribute "AwsAccountId" \
--region us-east-1
# Findings by resource type
aws securityhub create-insight \
--name "Findings by Resource Type" \
--filters '{
"RecordState": [{"Value": "ACTIVE", "Comparison": "EQUALS"}]
}' \
--group-by-attribute "ResourceType" \
--region us-east-1
# Failed controls by standard
aws securityhub create-insight \
--name "Failed Controls by Standard" \
--filters '{
"ComplianceStatus": [{"Value": "FAILED", "Comparison": "EQUALS"}],
"RecordState": [{"Value": "ACTIVE", "Comparison": "EQUALS"}]
}' \
--group-by-attribute "ComplianceSecurityControlId" \
--region us-east-1Useful Custom Insights
| Insight Name | Group By | Filter |
|---|---|---|
| Critical by Account | AwsAccountId | Severity=CRITICAL |
| Public Resources | ResourceType | NetworkConfiguration.Public=true |
| Unpatched Resources | ResourceId | Type=Software and Vulnerability |
| IAM Issues | ResourceId | ProductName=IAM Access Analyzer |
| Top Failing Controls | ComplianceSecurityControlId | ComplianceStatus=FAILED |
Step 7: Automate Remediation
EventBridge Rule for High Severity Findings
# Create EventBridge rule
aws events put-rule \
--name "SecurityHub-HighSeverity" \
--event-pattern '{
"source": ["aws.securityhub"],
"detail-type": ["Security Hub Findings - Imported"],
"detail": {
"findings": {
"Severity": {
"Label": ["CRITICAL", "HIGH"]
},
"Workflow": {
"Status": ["NEW"]
}
}
}
}' \
--state ENABLED \
--region us-east-1Lambda Auto-Remediation Example
# lambda_function.py
import boto3
import json
def lambda_handler(event, context):
"""Auto-remediate Security Hub findings."""
finding = event['detail']['findings'][0]
finding_id = finding['Id']
resource_id = finding['Resources'][0]['Id']
control_id = finding.get('Compliance', {}).get('SecurityControlId', 'Unknown')
print(f"Processing finding: {finding_id}")
print(f"Control: {control_id}, Resource: {resource_id}")
remediation_result = None
# S3.2 - Block public access
if control_id == 'S3.2':
remediation_result = remediate_s3_public_access(resource_id)
# EC2.19 - Default security group restricts all traffic
elif control_id == 'EC2.19':
remediation_result = remediate_default_sg(resource_id)
# IAM.3 - Access keys should be rotated
elif control_id == 'IAM.3':
remediation_result = notify_key_rotation(resource_id)
if remediation_result:
# Update finding status
update_finding_status(finding_id, finding['ProductArn'])
return {"statusCode": 200, "body": json.dumps(remediation_result)}
def remediate_s3_public_access(bucket_arn):
"""Block public access on S3 bucket."""
s3 = boto3.client('s3')
bucket_name = bucket_arn.split(':')[-1]
s3.put_public_access_block(
Bucket=bucket_name,
PublicAccessBlockConfiguration={
'BlockPublicAcls': True,
'IgnorePublicAcls': True,
'BlockPublicPolicy': True,
'RestrictPublicBuckets': True
}
)
return {"bucket": bucket_name, "action": "blocked_public_access"}
def remediate_default_sg(sg_arn):
"""Remove all rules from default security group."""
ec2 = boto3.client('ec2')
sg_id = sg_arn.split('/')[-1]
# Get security group
sg = ec2.describe_security_groups(GroupIds=[sg_id])['SecurityGroups'][0]
# Revoke all ingress rules
if sg['IpPermissions']:
ec2.revoke_security_group_ingress(
GroupId=sg_id,
IpPermissions=sg['IpPermissions']
)
# Revoke all egress rules
if sg['IpPermissionsEgress']:
ec2.revoke_security_group_egress(
GroupId=sg_id,
IpPermissions=sg['IpPermissionsEgress']
)
return {"sg_id": sg_id, "action": "removed_all_rules"}
def notify_key_rotation(resource_id):
"""Send notification for key rotation."""
sns = boto3.client('sns')
sns.publish(
TopicArn='arn:aws:sns:us-east-1:123456789012:SecurityAlerts',
Subject='Action Required: Rotate AWS Access Key',
Message=f'Access key requires rotation: {resource_id}'
)
return {"resource": resource_id, "action": "notification_sent"}
def update_finding_status(finding_id, product_arn):
"""Mark finding as resolved after remediation."""
securityhub = boto3.client('securityhub')
securityhub.batch_update_findings(
FindingIdentifiers=[{'Id': finding_id, 'ProductArn': product_arn}],
Workflow={'Status': 'RESOLVED'},
Note={'Text': 'Auto-remediated by Lambda', 'UpdatedBy': 'auto-remediation'}
)Deploy Lambda with EventBridge
# Create Lambda function
aws lambda create-function \
--function-name SecurityHub-AutoRemediation \
--runtime python3.11 \
--handler lambda_function.lambda_handler \
--role arn:aws:iam::123456789012:role/SecurityHubRemediationRole \
--zip-file fileb://function.zip \
--region us-east-1
# Add Lambda as EventBridge target
aws events put-targets \
--rule SecurityHub-HighSeverity \
--targets '[
{
"Id": "SecurityHubRemediation",
"Arn": "arn:aws:lambda:us-east-1:123456789012:function:SecurityHub-AutoRemediation"
}
]' \
--region us-east-1
# Grant EventBridge permission to invoke Lambda
aws lambda add-permission \
--function-name SecurityHub-AutoRemediation \
--statement-id EventBridgeInvoke \
--action lambda:InvokeFunction \
--principal events.amazonaws.com \
--source-arn arn:aws:events:us-east-1:123456789012:rule/SecurityHub-HighSeverity \
--region us-east-1Step 8: Integrate Third-Party Tools
Enable Partner Integrations
# List available integrations
aws securityhub describe-products \
--region us-east-1 \
--query "Products[?IntegrationTypes[?contains(@,'SEND_FINDINGS_TO_SECURITY_HUB')]].{Name:ProductName,Arn:ProductArn}"
# Enable integration (example: Splunk)
aws securityhub enable-import-findings-for-product \
--product-arn "arn:aws:securityhub:us-east-1::product/splunk/splunk-enterprise" \
--region us-east-1Send Findings to SIEM
# Lambda to forward findings to Splunk HEC
import boto3
import requests
import json
def forward_to_splunk(event, context):
"""Forward Security Hub findings to Splunk."""
splunk_hec_url = "https://splunk.company.com:8088/services/collector"
hec_token = boto3.client('secretsmanager').get_secret_value(
SecretId='splunk-hec-token'
)['SecretString']
findings = event['detail']['findings']
for finding in findings:
payload = {
"event": finding,
"sourcetype": "aws:securityhub",
"source": "aws:securityhub:findings",
"index": "security"
}
response = requests.post(
splunk_hec_url,
headers={"Authorization": f"Splunk {hec_token}"},
json=payload,
verify=True
)
return {"statusCode": 200}Step 9: Generate Reports
Export Findings to S3
# Create export configuration
aws securityhub create-action-target \
--name "ExportToS3" \
--description "Export findings to S3 for reporting" \
--id "ExportToS3" \
--region us-east-1
# Use Athena to query findings
# First, enable findings export (via console)
# Then query with Athena:-- Athena query for Security Hub findings
SELECT
awsaccountid,
severity.label as severity,
title,
COUNT(*) as finding_count
FROM security_hub_findings
WHERE recordstate = 'ACTIVE'
GROUP BY awsaccountid, severity.label, title
ORDER BY finding_count DESC
LIMIT 100;Generate Compliance Summary
# Get compliance summary
aws securityhub get-insights \
--insight-arns "arn:aws:securityhub:us-east-1:123456789012:insight/custom/summary" \
--region us-east-1
# Export to CSV
aws securityhub get-findings \
--filters '{"ComplianceStatus": [{"Value": "FAILED", "Comparison": "EQUALS"}]}' \
--query "Findings[].{Control:Compliance.SecurityControlId,Title:Title,Resource:Resources[0].Id,Account:AwsAccountId}" \
--output text \
--region us-east-1 > compliance-failures.csvTroubleshooting
Common Issues
| Symptom | Possible Cause | Solution |
|---|---|---|
| No findings appearing | Standards not enabled | Enable security standards |
| GuardDuty not integrated | Not in same region | Enable in matching regions |
| Cross-account not working | Member not accepted | Accept invitation in member |
| Controls showing UNKNOWN | Config not enabled | Enable AWS Config |
| Finding stuck as NEW | No automation | Update workflow manually/via Lambda |
Diagnostic Commands
# Check Security Hub status
aws securityhub describe-hub --region us-east-1
# List enabled standards
aws securityhub get-enabled-standards --region us-east-1
# Check member account status
aws securityhub list-members --region us-east-1
# Verify product integrations
aws securityhub list-enabled-products-for-import --region us-east-1
# Check findings import health
aws securityhub get-insights \
--insight-arns "arn:aws:securityhub:::insight/securityhub/default/1" \
--region us-east-1Security Best Practices
Least Privilege for Security Hub
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"securityhub:GetFindings",
"securityhub:GetInsights",
"securityhub:DescribeStandards"
],
"Resource": "*"
},
{
"Effect": "Deny",
"Action": [
"securityhub:DisableSecurityHub",
"securityhub:BatchDisableStandards"
],
"Resource": "*"
}
]
}Protect Administrator Account
# Enable MFA on administrator
# Use AWS Organizations SCPs to prevent disabling
# SCP to prevent Security Hub disable
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ProtectSecurityHub",
"Effect": "Deny",
"Action": [
"securityhub:DisableSecurityHub",
"securityhub:DeleteMembers",
"securityhub:DisassociateFromAdministratorAccount"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:PrincipalArn": "arn:aws:iam::*:role/SecurityAdministrator"
}
}
}
]
}Verification Checklist
Setup:
- Security Hub enabled in all required regions
- Security standards enabled (Foundational, CIS, PCI)
- Aggregator region configured
- Member accounts added (multi-account)
Integrations:
- GuardDuty findings flowing
- Inspector findings flowing
- Macie findings flowing (if data classification needed)
- IAM Access Analyzer enabled
Operations:
- Custom insights created
- EventBridge rules for automation
- Auto-remediation Lambda deployed
- Notification/alerting configured
Compliance:
- All controls reviewed
- Non-applicable controls disabled with documentation
- Regular compliance score review scheduled
Next Steps
After implementing Security Hub:
- Enable AWS Config Rules - Additional compliance checks
- Implement GuardDuty Threat Detection - Advanced threat hunting
- Deploy AWS Firewall Manager - Centralized firewall policies
- Create Security Dashboards - QuickSight/Grafana visualizations
References
- AWS Security Hub Documentation
- Security Hub Controls Reference
- Security Hub Automation
- Multi-Account Setup
- CIS AWS Foundations Benchmark
Last Updated: February 2026