Module Overview
Estimated Time : 2-3 hours | Difficulty : Intermediate | Prerequisites : GuardDuty, IAM, basic compliance concepts
AWS Security Hub provides a comprehensive view of your security state across AWS accounts. It aggregates findings from multiple AWS services and third-party tools, enabling centralized security management and compliance monitoring.
What You’ll Learn:
Security Hub architecture and data flow
Security standards and compliance frameworks
Findings management and automation
Multi-account deployment
Custom insights and dashboards
How Security Hub Works
┌─────────────────────────────────────────────────────────────────────────┐
│ Security Hub Architecture │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Finding Sources Security Hub Actions │
│ ─────────────── ──────────── ─────── │
│ │
│ AWS Services: ┌──────────────┐ │
│ ┌──────────────┐ │ │ ┌───────────────┐ │
│ │ GuardDuty │───────────▶│ Finding │─────▶│ EventBridge │ │
│ └──────────────┘ │ Aggregation│ └───────────────┘ │
│ ┌──────────────┐ │ + │ │
│ │ Inspector │───────────▶│ Security │ ┌───────────────┐ │
│ └──────────────┘ │ Standards │─────▶│ Custom Actions│ │
│ ┌──────────────┐ │ + │ └───────────────┘ │
│ │ Macie │───────────▶│ Insights │ │
│ └──────────────┘ │ │ ┌───────────────┐ │
│ ┌──────────────┐ └──────────────┘─────▶│ SIEM Export │ │
│ │ Firewall │ └───────────────┘ │
│ │ Manager │─────────────────────▶ │
│ └──────────────┘ │
│ ┌──────────────┐ │
│ │ IAM Access │─────────────────────▶ │
│ │ Analyzer │ │
│ └──────────────┘ │
│ │
│ Third-Party: ┌──────────────┐ │
│ ┌──────────────┐ │ Compliance │ │
│ │ Palo Alto │───────────▶│ Score │ │
│ └──────────────┘ │ │ │
│ ┌──────────────┐ │ CIS: 85% │ │
│ │ CrowdStrike │───────────▶│ PCI: 92% │ │
│ └──────────────┘ │ AWS FB: 78% │ │
│ ┌──────────────┐ └──────────────┘ │
│ │ Qualys │─────────────────────▶ │
│ └──────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Enabling Security Hub
Console or CLI
# Enable Security Hub
aws securityhub enable-security-hub \
--enable-default-standards \
--control-finding-generator STANDARD_CONTROL
# Enable specific standards
aws securityhub batch-enable-standards \
--standards-subscription-requests '[
{
"StandardsArn": "arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.4.0"
},
{
"StandardsArn": "arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0"
}
]'
# List enabled standards
aws securityhub get-enabled-standards
AWSTemplateFormatVersion : '2010-09-09'
Description : Enable Security Hub with standards
Resources :
SecurityHub :
Type : AWS::SecurityHub::Hub
Properties :
Tags :
Environment : Production
CostCenter : Security
# AWS Foundational Security Best Practices
AWSFoundationalStandard :
Type : AWS::SecurityHub::Standard
DependsOn : SecurityHub
Properties :
StandardsArn : !Sub 'arn:aws:securityhub:${AWS::Region}::standards/aws-foundational-security-best-practices/v/1.0.0'
# CIS AWS Foundations Benchmark
CISStandard :
Type : AWS::SecurityHub::Standard
DependsOn : SecurityHub
Properties :
StandardsArn : !Sub 'arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.4.0'
Security Standards
Available Standards
Standard Controls Focus AWS Foundational Security Best Practices 200+ AWS-specific best practices CIS AWS Foundations Benchmark 60+ Industry-standard hardening PCI DSS 150+ Payment card security NIST 800-53 200+ US Federal compliance SOC 2 100+ Service organization controls
AWS Foundational Security Best Practices
# Example controls:
# [ACM.1] ACM certificates should be renewed within 30 days
# [CloudTrail.1] CloudTrail should be enabled
# [EC2.1] EBS snapshots should not be publicly restorable
# [IAM.1] IAM policies should not allow full "*" administrative privileges
# [S3.1] S3 Block Public Access should be enabled
# [Lambda.1] Lambda functions should prohibit public access
# [RDS.1] RDS snapshots should be private
Disable Specific Controls
# Disable a control that doesn't apply to your environment
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/S3.11" \
--control-status DISABLED \
--disabled-reason "We don't use S3 Object Lock"
Findings Management
{
"SchemaVersion" : "2018-10-08" ,
"Id" : "arn:aws:securityhub:us-east-1:123456789012:subscription/aws-foundational-security-best-practices/v/1.0.0/S3.1/finding/abc123" ,
"ProductArn" : "arn:aws:securityhub:us-east-1::product/aws/securityhub" ,
"GeneratorId" : "aws-foundational-security-best-practices/v/1.0.0/S3.1" ,
"AwsAccountId" : "123456789012" ,
"Types" : [
"Software and Configuration Checks/Industry and Regulatory Standards/AWS-Foundational-Security-Best-Practices"
],
"FirstObservedAt" : "2024-01-15T10:00:00.000Z" ,
"UpdatedAt" : "2024-01-15T10:00:00.000Z" ,
"CreatedAt" : "2024-01-15T10:00:00.000Z" ,
"Severity" : {
"Label" : "HIGH" ,
"Normalized" : 70
},
"Title" : "S3.1 S3 Block Public Access setting should be enabled" ,
"Description" : "This control checks whether S3 Block Public Access is enabled at the account level." ,
"Remediation" : {
"Recommendation" : {
"Text" : "Enable S3 Block Public Access at the account level" ,
"Url" : "https://docs.aws.amazon.com/..."
}
},
"Resources" : [
{
"Type" : "AwsAccount" ,
"Id" : "AWS::::Account:123456789012" ,
"Partition" : "aws" ,
"Region" : "us-east-1"
}
],
"Compliance" : {
"Status" : "FAILED" ,
"RelatedRequirements" : [
"PCI DSS 1.2.1"
]
},
"Workflow" : {
"Status" : "NEW"
},
"RecordState" : "ACTIVE"
}
Finding Workflow
┌─────────────────────────────────────────────────────────────────────────┐
│ Finding Workflow States │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌───────────┐ ┌──────────┐ ┌───────────┐ │
│ │ NEW │───▶│ NOTIFIED │───▶│ RESOLVED │ │SUPPRESSED │ │
│ └─────────┘ └───────────┘ └──────────┘ └───────────┘ │
│ │ │
│ └─────────────────────────────────────────────▶ │
│ │
│ States: │
│ ─ NEW: Finding just created, needs triage │
│ ─ NOTIFIED: Assigned to team/individual │
│ ─ SUPPRESSED: Accepted risk or false positive │
│ ─ RESOLVED: Issue has been fixed │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Query Findings
# Get all high severity findings
aws securityhub get-findings \
--filters '{
"SeverityLabel": [{"Value": "HIGH", "Comparison": "EQUALS"}],
"WorkflowStatus": [{"Value": "NEW", "Comparison": "EQUALS"}],
"RecordState": [{"Value": "ACTIVE", "Comparison": "EQUALS"}]
}'
# Get findings for specific resource
aws securityhub get-findings \
--filters '{
"ResourceId": [{"Value": "arn:aws:s3:::my-bucket", "Comparison": "EQUALS"}]
}'
# Get findings by product
aws securityhub get-findings \
--filters '{
"ProductName": [{"Value": "GuardDuty", "Comparison": "EQUALS"}]
}'
Update Finding Workflow
# Mark finding as resolved
aws securityhub batch-update-findings \
--finding-identifiers '[{
"Id": "arn:aws:securityhub:us-east-1:123456789012:subscription/.../finding/abc123",
"ProductArn": "arn:aws:securityhub:us-east-1::product/aws/securityhub"
}]' \
--workflow '{"Status": "RESOLVED"}'
# Suppress finding with note
aws securityhub batch-update-findings \
--finding-identifiers '[{...}]' \
--workflow '{"Status": "SUPPRESSED"}' \
--note '{"Text": "Accepted risk - internal application", "UpdatedBy": "security-team"}'
EventBridge Integration
Resources :
SecurityHubRule :
Type : AWS::Events::Rule
Properties :
Name : securityhub-auto-remediate
Description : Auto-remediate Security Hub findings
EventPattern :
source :
- aws.securityhub
detail-type :
- Security Hub Findings - Imported
detail :
findings :
Severity :
Label :
- CRITICAL
- HIGH
Workflow :
Status :
- NEW
Compliance :
Status :
- FAILED
Targets :
- Arn : !GetAtt RemediationLambda.Arn
Id : RemediationFunction
# remediation.py
import boto3
import json
s3 = boto3.client( 's3' )
ec2 = boto3.client( 'ec2' )
securityhub = boto3.client( 'securityhub' )
def lambda_handler ( event , context ):
for finding in event[ 'detail' ][ 'findings' ]:
control_id = finding.get( 'GeneratorId' , '' )
if 'S3.1' in control_id:
remediate_s3_public_access(finding)
elif 'EC2.19' in control_id:
remediate_security_group(finding)
elif 'IAM.3' in control_id:
remediate_iam_access_keys(finding)
# Update finding status
update_finding_resolved(finding)
return { 'statusCode' : 200 }
def remediate_s3_public_access ( finding ):
"""S3.1 - Enable S3 Block Public Access"""
s3control = boto3.client( 's3control' )
account_id = finding[ 'AwsAccountId' ]
s3control.put_public_access_block(
AccountId = account_id,
PublicAccessBlockConfiguration = {
'BlockPublicAcls' : True ,
'IgnorePublicAcls' : True ,
'BlockPublicPolicy' : True ,
'RestrictPublicBuckets' : True
}
)
def remediate_security_group ( finding ):
"""EC2.19 - Security groups should not allow unrestricted access to high risk ports"""
for resource in finding[ 'Resources' ]:
if resource[ 'Type' ] == 'AwsEc2SecurityGroup' :
sg_id = resource[ 'Details' ][ 'AwsEc2SecurityGroup' ][ 'GroupId' ]
# Remove unrestricted SSH access
ec2.revoke_security_group_ingress(
GroupId = sg_id,
IpPermissions = [{
'IpProtocol' : 'tcp' ,
'FromPort' : 22 ,
'ToPort' : 22 ,
'IpRanges' : [{ 'CidrIp' : '0.0.0.0/0' }]
}]
)
def remediate_iam_access_keys ( finding ):
"""IAM.3 - IAM users' access keys should be rotated every 90 days"""
iam = boto3.client( 'iam' )
for resource in finding[ 'Resources' ]:
if resource[ 'Type' ] == 'AwsIamUser' :
username = resource[ 'Id' ].split( '/' )[ - 1 ]
# List and deactivate old keys (> 90 days)
response = iam.list_access_keys( UserName = username)
for key in response[ 'AccessKeyMetadata' ]:
# Check key age and deactivate if > 90 days
pass
def update_finding_resolved ( finding ):
"""Update finding workflow status to RESOLVED"""
securityhub.batch_update_findings(
FindingIdentifiers = [{
'Id' : finding[ 'Id' ],
'ProductArn' : finding[ 'ProductArn' ]
}],
Workflow = { 'Status' : 'RESOLVED' },
Note = {
'Text' : 'Auto-remediated by Lambda' ,
'UpdatedBy' : 'automation'
}
)
Custom Insights
Create Custom Insight
# Create insight for unresolved critical findings
aws securityhub create-insight \
--name "Critical Findings Older Than 7 Days" \
--filters '{
"SeverityLabel": [{"Value": "CRITICAL", "Comparison": "EQUALS"}],
"WorkflowStatus": [{"Value": "NEW", "Comparison": "EQUALS"}],
"CreatedAt": [{"DateRange": {"Value": 7, "Unit": "DAYS"}}]
}' \
--group-by-attribute "ResourceType"
# Create insight for findings by AWS account
aws securityhub create-insight \
--name "Findings by Account" \
--filters '{
"RecordState": [{"Value": "ACTIVE", "Comparison": "EQUALS"}]
}' \
--group-by-attribute "AwsAccountId"
Built-in Insights
Managed Insights :
- "AWS resources with the most findings"
- "S3 buckets with public write or read permissions"
- "AMIs that are generating the most findings"
- "IAM users with the most findings"
- "EC2 instances involved in known TTPs"
- "Resources with the most failed security checks"
Multi-Account Management
Organization Setup
┌─────────────────────────────────────────────────────────────────────────┐
│ Multi-Account Architecture │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Management Account │ │
│ │ (Delegated Admin for Security Hub) │ │
│ │ │ │
│ │ ┌───────────────────────────────────────────────────────────┐ │ │
│ │ │ Aggregated Security View │ │ │
│ │ │ ─ All findings from all accounts │ │ │
│ │ │ ─ Cross-account security score │ │ │
│ │ │ ─ Centralized compliance dashboard │ │ │
│ │ └───────────────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────┼─────────────┐ │
│ │ │ │ │
│ ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐ │
│ │ Member │ │ Member │ │ Member │ │
│ │ Account 1 │ │ Account 2 │ │ Account 3 │ │
│ │ (Dev) │ │ (Staging) │ │ (Prod) │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
Enable Organization Integration
# Designate delegated administrator (from management account)
aws securityhub enable-organization-admin-account \
--admin-account-id 111122223333
# From delegated admin - enable auto-enable for members
aws securityhub update-organization-configuration \
--auto-enable
# Enable specific standards across org
aws securityhub update-organization-configuration \
--auto-enable \
--organization-configuration '{
"ConfigurationType": "CENTRAL"
}'
Cross-Region Aggregation
# Designate aggregation region
aws securityhub create-finding-aggregator \
--region us-east-1 \
--region-linking-mode ALL_REGIONS
# Or specify regions
aws securityhub create-finding-aggregator \
--region us-east-1 \
--region-linking-mode SPECIFIED_REGIONS \
--regions us-west-2 eu-west-1 ap-southeast-1
SIEM Integration
Export to S3
# CloudFormation for S3 export
Resources :
SecurityHubExportRule :
Type : AWS::Events::Rule
Properties :
Name : securityhub-to-s3
EventPattern :
source :
- aws.securityhub
detail-type :
- Security Hub Findings - Imported
Targets :
- Arn : !GetAtt ExportFunction.Arn
Id : ExportToS3
SecurityHubFindingsBucket :
Type : AWS::S3::Bucket
Properties :
BucketName : !Sub ${AWS::AccountId}-securityhub-findings
LifecycleConfiguration :
Rules :
- Id : ArchiveOldFindings
Status : Enabled
Transitions :
- StorageClass : GLACIER
TransitionInDays : 90
Export to Splunk/SIEM
# splunk_exporter.py
import boto3
import json
import requests
from datetime import datetime
def lambda_handler ( event , context ):
splunk_url = os.environ[ 'SPLUNK_HEC_URL' ]
splunk_token = os.environ[ 'SPLUNK_HEC_TOKEN' ]
for finding in event[ 'detail' ][ 'findings' ]:
splunk_event = {
"time" : datetime.now().timestamp(),
"host" : "aws-security-hub" ,
"source" : "security-hub" ,
"sourcetype" : "aws:securityhub:finding" ,
"event" : finding
}
response = requests.post(
splunk_url,
headers = {
"Authorization" : f "Splunk { splunk_token } " ,
"Content-Type" : "application/json"
},
json = splunk_event
)
if response.status_code != 200 :
print ( f "Failed to send to Splunk: { response.text } " )
return { 'statusCode' : 200 }
Best Practices
Enable in All Regions Security Hub aggregates findings—enable everywhere
Use Organizations Centralized management with delegated admin
Automate Remediation Use EventBridge + Lambda for common fixes
Track Compliance Score Monitor security score trends over time
🎯 Interview Questions
Q1: How does Security Hub differ from GuardDuty?
GuardDuty = Threat detection
Analyzes data sources for active threats
Uses ML and threat intelligence
Generates findings for malicious activity
Security Hub = Aggregation + Compliance
Collects findings from GuardDuty and other services
Runs security standard checks (CIS, PCI, etc.)
Provides centralized dashboard and compliance scores
They work together: GuardDuty detects threats, Security Hub aggregates and tracks compliance.
Q2: How do you handle thousands of Security Hub findings?
Prioritization:
Focus on CRITICAL/HIGH severity first
Filter by compliance requirements (PCI, HIPAA)
Group by resource type or AWS account
Automation:
Auto-remediate common issues with Lambda
Suppress accepted risks with filters
Use custom actions for manual review
Process:
Set SLAs: Critical = 24h, High = 7d
Weekly review of suppressed findings
Track security score trends
Q3: How do you set up Security Hub for a multi-account organization?
Designate Admin : Use delegated administrator in security account
Enable Auto-Enable : New accounts automatically get Security Hub
Central Configuration : Push standards from admin account
Cross-Region : Set up finding aggregator to central region
SIEM Export : Stream findings to central SIEM
Hands-On Lab
Enable Security Hub
Enable Security Hub with AWS Foundational and CIS standards
Review Initial Score
Check your security score and review failing controls
Fix Top Issues
Remediate 5 high-severity findings manually
Create Automation
Build EventBridge + Lambda for one common finding type
Create Custom Insight
Build an insight showing findings by resource type
Next Module
AWS CloudTrail API logging and auditing for compliance and investigation