AWS Security Hub Centralized Findings Management at Scale

Deploying AWS Security Hub across multi-account organizations with custom insights, automated remediation, and finding aggregation strategies

#aws#security-hub#security#compliance
Cover image for the article: AWS Security Hub Centralized Findings Management at Scale

Introduction

AWS Security Hub aggregates security findings from 50+ AWS services and third-party tools into a single pane of glass. In organizations with 100+ accounts, Security Hub processes thousands of findings daily across Inspector, GuardDuty, Config, IAM Access Analyzer, Macie, and partner integrations. The challenge is not collecting findings but building effective workflows that turn findings into action.

This article covers the deployment architecture, finding prioritization frameworks, and automation patterns that make Security Hub operationally effective rather than just another noisy dashboard.

Security Hub Architecture

Chart

Finding Sources

SourceFinding TypesVolume (per 100 accounts)Default Enabled
AWS ConfigCompliance violations2,000-5,000/weekVia standards
InspectorVulnerabilities (CVE)3,000-8,000/weekManual
GuardDutyThreat intelligence50-200/weekManual
IAM Access AnalyzerPublic/cross-account access100-500/weekManual
MacieSensitive data exposure200-1,000/weekManual
Firewall ManagerSecurity group violations500-2,000/weekManual
Third-party (Prowler, etc.)Best practice deviations1,000-5,000/weekManual

Multi-Account Deployment

Organization-Wide Enablement

# Designate delegated administrator
aws securityhub enable-organization-admin-account \
  --admin-account-id 111111111111

# From admin account: configure auto-enable for new accounts
aws securityhub update-organization-configuration \
  --auto-enable \
  --auto-enable-standards

# Enable specific standards across organization
aws securityhub batch-enable-standards \
  --standards-subscription-requests '[
    {
      "StandardsArn": "arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/3.0.0"
    },
    {
      "StandardsArn": "arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0"
    }
  ]'

Cross-Region Aggregation

# Enable finding aggregation from all regions to us-east-1
aws securityhub create-finding-aggregator \
  --region us-east-1 \
  --region-linking-mode ALL_REGIONS

# Or specify regions explicitly
aws securityhub create-finding-aggregator \
  --region us-east-1 \
  --region-linking-mode SPECIFIED_REGIONS \
  --regions '["eu-west-1", "ap-southeast-1", "us-west-2"]'

Terraform Configuration

# Admin account configuration
resource "aws_securityhub_account" "admin" {}

resource "aws_securityhub_organization_admin_account" "admin" {
  admin_account_id = var.security_account_id
}

resource "aws_securityhub_organization_configuration" "org" {
  auto_enable           = true
  auto_enable_standards = "DEFAULT"

  depends_on = [aws_securityhub_organization_admin_account.admin]
}

resource "aws_securityhub_finding_aggregator" "all_regions" {
  linking_mode = "ALL_REGIONS"
}

# Enable standards
resource "aws_securityhub_standards_subscription" "cis" {
  standards_arn = "arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/3.0.0"
}

resource "aws_securityhub_standards_subscription" "fsbp" {
  standards_arn = "arn:aws:securityhub:${var.region}::standards/aws-foundational-security-best-practices/v/1.0.0"
}

Security Standards Comparison

StandardControlsFocus AreaRecommended For
AWS FSBP300+AWS-specific best practicesAll AWS accounts
CIS v3.060+Industry baselineCompliance-driven orgs
PCI DSS130+Payment card securityE-commerce/fintech
NIST 800-53200+Government/regulatedFederal/defense

Control Failure Distribution (Typical Enterprise)

SeverityFSBP FailuresCIS FailuresCombined
Critical15-255-1020-35
High80-15030-50110-200
Medium200-40050-100250-500
Low100-20020-40120-240
Total400-775105-200500-975

Custom Insights for Prioritization

Custom insights aggregate findings into actionable views:

# Top accounts with critical findings
aws securityhub create-insight \
  --name "Critical Findings by Account" \
  --filters '{
    "SeverityLabel": [{"Value": "CRITICAL", "Comparison": "EQUALS"}],
    "WorkflowStatus": [{"Value": "NEW", "Comparison": "EQUALS"}],
    "RecordState": [{"Value": "ACTIVE", "Comparison": "EQUALS"}]
  }' \
  --group-by-attribute "AwsAccountId"

# Unresolved findings older than 30 days
aws securityhub create-insight \
  --name "Aging Critical Findings" \
  --filters '{
    "SeverityLabel": [{"Value": "CRITICAL", "Comparison": "EQUALS"}, {"Value": "HIGH", "Comparison": "EQUALS"}],
    "WorkflowStatus": [{"Value": "NEW", "Comparison": "EQUALS"}],
    "CreatedAt": [{"DateRange": {"Value": 30, "Unit": "DAYS"}}]
  }' \
  --group-by-attribute "ResourceType"

# Public-facing resource findings
aws securityhub create-insight \
  --name "Public Resource Exposure" \
  --filters '{
    "Type": [{"Value": "Software and Configuration Checks", "Comparison": "PREFIX"}],
    "Title": [
      {"Value": "public", "Comparison": "PREFIX"},
      {"Value": "unrestricted", "Comparison": "PREFIX"}
    ],
    "RecordState": [{"Value": "ACTIVE", "Comparison": "EQUALS"}]
  }' \
  --group-by-attribute "AwsAccountId"

Automated Remediation

EventBridge Rule for Critical Findings

{
  "source": ["aws.securityhub"],
  "detail-type": ["Security Hub Findings - Imported"],
  "detail": {
    "findings": {
      "Severity": {
        "Label": ["CRITICAL"]
      },
      "Workflow": {
        "Status": ["NEW"]
      },
      "Compliance": {
        "Status": ["FAILED"]
      },
      "ProductFields": {
        "StandardsControlArn": [{
          "prefix": "arn:aws:securityhub"
        }]
      }
    }
  }
}

Auto-Remediation Lambda

import boto3
import json

# Map control IDs to remediation functions
REMEDIATION_MAP = {
    'S3.2': remediate_s3_public_read,
    'S3.3': remediate_s3_public_write,
    'EC2.2': remediate_default_sg,
    'EC2.19': remediate_sg_unrestricted,
    'IAM.3': remediate_iam_key_rotation,
    'RDS.2': remediate_rds_public,
}

def handler(event, context):
    finding = event['detail']['findings'][0]
    control_id = extract_control_id(finding)

    if control_id in REMEDIATION_MAP:
        remediation_fn = REMEDIATION_MAP[control_id]
        result = remediation_fn(finding)

        # Update finding workflow status
        securityhub = boto3.client('securityhub')
        securityhub.batch_update_findings(
            FindingIdentifiers=[{
                'Id': finding['Id'],
                'ProductArn': finding['ProductArn']
            }],
            Workflow={'Status': 'RESOLVED'},
            Note={
                'Text': f'Auto-remediated: {result}',
                'UpdatedBy': 'security-automation'
            }
        )
    else:
        # Create ticket for manual remediation
        create_jira_ticket(finding)

def remediate_s3_public_read(finding):
    """Block public access on S3 bucket."""
    s3 = boto3.client('s3')
    bucket_name = finding['Resources'][0]['Id'].split(':')[-1]

    s3.put_public_access_block(
        Bucket=bucket_name,
        PublicAccessBlockConfiguration={
            'BlockPublicAcls': True,
            'IgnorePublicAcls': True,
            'BlockPublicPolicy': True,
            'RestrictPublicBuckets': True
        }
    )
    return f"Blocked public access on {bucket_name}"

def remediate_default_sg(finding):
    """Remove all rules from default security group."""
    ec2 = boto3.client('ec2')
    sg_id = finding['Resources'][0]['Id'].split('/')[-1]

    # Revoke all ingress rules
    sg = ec2.describe_security_groups(GroupIds=[sg_id])['SecurityGroups'][0]
    if sg['IpPermissions']:
        ec2.revoke_security_group_ingress(
            GroupId=sg_id,
            IpPermissions=sg['IpPermissions']
        )
    return f"Cleared rules from default SG {sg_id}"

Finding Suppression Strategy

Suppress findings that represent accepted risks to reduce noise:

# Suppress findings for approved exceptions
aws securityhub batch-update-findings \
  --finding-identifiers '[
    {"Id": "arn:aws:securityhub:us-east-1:123456789012:finding/abc-123", "ProductArn": "arn:aws:securityhub:us-east-1::product/aws/securityhub"}
  ]' \
  --workflow '{"Status": "SUPPRESSED"}' \
  --note '{"Text": "Accepted risk: Legacy system migration planned Q3 2026", "UpdatedBy": "security-team"}'

Metrics and KPIs

KPITargetMeasurementFrequency
Critical MTTR< 24 hoursFinding created to resolvedDaily
High MTTR< 7 daysFinding created to resolvedWeekly
Security score> 85%Security Hub scoreWeekly
Auto-remediation rate> 40%Auto-resolved / totalMonthly
Finding aging (critical)0 findings > 72hOpen critical findingsDaily
Suppression ratio< 15%Suppressed / total activeMonthly

Key Takeaways

  • Enable Security Hub organization-wide with finding aggregation to create a single security view across all accounts and regions.
  • Start with AWS FSBP standard as it provides the most comprehensive coverage of AWS-specific security best practices with 300+ controls.
  • Build custom insights for actionable prioritization focusing on critical findings by account, aging findings, and public resource exposure.
  • Automate remediation for common findings (S3 public access, default security groups, unrestricted SSH) to reduce MTTR from days to minutes.
  • Suppress accepted risks systematically with documented justification to reduce alert fatigue while maintaining audit trails.
  • Target 85%+ security score as a KPI and track critical finding MTTR under 24 hours for mature security operations.
  • Integrate with ticketing systems for findings that require human judgment, ensuring nothing falls through the cracks between automated and manual remediation.

Comments

    No comments yet. Be the first to share your thoughts.