Security Hub & standards
Aggregate, normalize, and score against CIS/FSBP.
A building manager with twenty buildings has a choice. Walk every lobby by hand and read each alarm panel one at a time, hoping you reach the one that's actually on fire before it spreads. Or wire every panel back to a single wall of screens in one room and watch them all at once. Security Hub is that room. Turn on GuardDuty, Inspector, Macie, IAM Access Analyzer, and Config across a real AWS estate and each one shouts from its own console, in its own format, separately, in every account and region you run. Nobody watches thirty consoles. Security Hub is the inbox that collects every alarm from every building and lays them out in one place, in one shape.
One inbox, one form
You don't wire the fire panel into a random tenant's apartment. You put it in a dedicated security office. AWS works the same way. You pick one account, usually a purpose-built security account, and designate it as the delegated administrator for Security Hub. Then you tell the organization to auto-enable every current account and every future one. Coverage stops being a checklist somebody forgets on the next new account and becomes a property of the org itself. The enable calls print nothing on success, so you confirm the wiring with a list call.
aws securityhub enable-organization-admin-account --admin-account-id 333333333333aws securityhub update-organization-configuration --auto-enable --auto-enable-standards DEFAULTaws organizations list-delegated-administrators --service-principal securityhub.amazonaws.com{"DelegatedAdministrators": [{"Id": "333333333333","Arn": "arn:aws:organizations::111111111111:account/o-a1b2c3d4e5/333333333333","Email": "[email protected]","Name": "Security-Tooling","Status": "ACTIVE","JoinedMethod": "CREATED"}]}
Enrolling every account still leaves you looking region by region. A finding raised in us-west-2 lands in the us-west-2 console and stays there. A finding aggregator links your regions into one home region so the security office sees everything without switching tabs. This is the part people miss. Cross-account coverage is the delegated admin. Cross-region coverage is the aggregator. Two different switches, and turning on one does not turn on the other.
aws securityhub create-finding-aggregator --region-linking-mode ALL_REGIONS{"FindingAggregatorArn": "arn:aws:securityhub:us-east-1:333333333333:finding-aggregator/9d1e7a4c-2f6b-4a0e-b8c1-7c3f2a5d9e01","FindingAggregationRegion": "us-east-1","RegionLinkingMode": "ALL_REGIONS","Regions": []}
Now hand it a benchmark to grade against. FSBP is AWS's own Foundational Security Best Practices. CIS, from the Center for Internet Security, is the independent industry baseline that auditors know and trust. Subscribing to a standard runs hundreds of automated checks continuously and scores your posture, telling you which control is failing in which account. Each control has a stable id like EC2.13 or IAM.1, so a failing check points at an exact fix rather than a vague warning, and Security Hub folds the same control failing from several providers into one row instead of five.
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"}]'{"StandardsSubscriptions": [{"StandardsSubscriptionArn": "arn:aws:securityhub:us-east-1:333333333333:subscription/aws-foundational-security-best-practices/v/1.0.0","StandardsArn": "arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0","StandardsInput": {},"StandardsStatus": "PENDING"}]}
Reading an actual finding
Every provider files its complaint on the same form, and that form is the AWS Security Finding Format, or ASFF. It's the reason a partner scanner's alert and an AWS service's alert can sit side by side in the same list. Read one and you can read them all. Pull the high-severity, untriaged findings and look at the shape.
aws securityhub get-findings \--filters '{"SeverityLabel":[{"Value":"HIGH","Comparison":"EQUALS"}],"WorkflowStatus":[{"Value":"NEW","Comparison":"EQUALS"}]}' \--max-results 1{"Findings": [{"SchemaVersion": "2018-10-08","Id": "arn:aws:securityhub:us-east-1:444455556666:security-control/EC2.13/finding/6f1a2b3c-8d90-4e12-a5f7-0c9b1d2e3f4a","ProductArn": "arn:aws:securityhub:us-east-1::product/aws/securityhub","ProductName": "Security Hub","CompanyName": "AWS","GeneratorId": "security-control/EC2.13","AwsAccountId": "444455556666","Types": ["Software and Configuration Checks/Industry and Regulatory Standards"],"CreatedAt": "2026-07-14T02:31:07.004Z","UpdatedAt": "2026-07-16T06:12:44.118Z","Severity": { "Label": "HIGH", "Normalized": 70, "Original": "HIGH" },"Title": "EC2.13 Security groups should not allow ingress from 0.0.0.0/0 or ::/0 to port 22","Description": "This control checks whether an Amazon EC2 security group allows ingress from 0.0.0.0/0 or ::/0 to port 22. The control fails if the security group allows ingress from 0.0.0.0/0 or ::/0 to port 22.","Remediation": {"Recommendation": {"Text": "Remove the rule that allows 0.0.0.0/0 to port 22 and scope ingress to known CIDRs.","Url": "https://docs.aws.amazon.com/console/securityhub/EC2.13/remediation"}},"Resources": [{"Type": "AwsEc2SecurityGroup","Id": "arn:aws:ec2:us-east-1:444455556666:security-group/sg-0abc1234def567890","Partition": "aws","Region": "us-east-1","Details": {"AwsEc2SecurityGroup": {"GroupName": "prod-web-sg","VpcId": "vpc-0a1b2c3d","IpPermissions": [{ "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "IpRanges": [{ "CidrIp": "0.0.0.0/0" }] }]}}}],"Compliance": {"Status": "FAILED","SecurityControlId": "EC2.13","AssociatedStandards": [{ "StandardsId": "standards/aws-foundational-security-best-practices/v/1.0.0" }]},"Workflow": { "Status": "NEW" },"RecordState": "ACTIVE"}],"NextToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJI..."}
Five fields carry the weight. Resources tells you exactly which door is open: a security group with 0.0.0.0/0 allowed to port 22, which means anyone on the public internet can reach the remote-login service (SSH, the tool admins use to sign into a Linux box) on that machine. Compliance ties it back to the benchmark, here a FAILED status against FSBP control EC2.13. Severity carries a Normalized number (70) that every provider maps onto, so you can sort a GuardDuty finding next to a Config one on the same scale. Workflow is where the finding sits in your process: NEW means no human has touched it, and you move it to NOTIFIED, RESOLVED, or SUPPRESSED as it travels. RecordState ACTIVE means the underlying problem is still real. Fix the rule and Security Hub archives the finding on the next check.
A score is a floor, not a finish line
A 96 percent FSBP score feels great and proves less than you'd hope. It means the checks Security Hub can evaluate mostly pass. It says nothing about the risks no benchmark inspects: a valid role that's quietly over-permissioned, or data moving somewhere it shouldn't. Hold the number as a floor while you build the threat-specific detections that no standard covers. And a finding sitting in a console nobody watches changes nothing on its own. The payoff comes when you route the HIGH and NEW findings out through EventBridge into ticketing and automated response, which is exactly where the next lesson picks up.
Try this
Work through “A score is a floor, not a finish line” yourself on a sandbox you can throw away, following the commands above in order. Then break one step deliberately and re-run, so you have seen the failure before it finds you.
Takeaway
The trap worth remembering here: auto-enable can switch on more than you meant to bill for. Check that on your own systems before you need to, because it is cheaper to find on a quiet afternoon than during an incident.