Guide · AWS Security Hub · Compliance Standards
AWS Security Hub Compliance Standards — CIS, PCI DSS, FSBP, NIST for MCP Servers
Security Hub compliance standards run continuously as AWS Config rules against your account's resources, generating findings when a resource deviates from the standard's control requirements. For MCP server operators the practical starting point is the AWS Foundational Security Best Practices (FSBP) standard — it covers the AWS services most commonly used in MCP deployments (EC2, ECS, Lambda, S3, IAM, KMS) without the full audit rigor of CIS or PCI DSS. The critical operational detail: every enabled control in every standard runs as a separate Config rule with a name like SecurityHub-<ControlId>-<hash>. AWS Config charges $0.001 per configuration item recorded and $0.003 per Config rule evaluation per month after the free tier. Enabling all five available standards across 200+ controls in an account with 100+ resources can generate thousands of Config evaluations per month — always audit which controls are relevant before enabling a standard.
TL;DR
Enable FSBP first — best coverage for MCP infrastructure with least overhead. Add CIS v1.4 if you need compliance certification. Enable standards with batch-enable-standards, disable irrelevant controls with update-standards-control (or update-standards-control-associations in SECURITY_CONTROL mode), and monitor compliance score with list-standards-control-associations. Controls run as Config rules — each enabled control incurs Config evaluation charges. See Security Hub setup guide for initial configuration, automation rules guide for automatically suppressing low-signal controls, and cross-account guide for enabling standards across Organizations.
Available standards and Standard ARNs
Security Hub offers six standards. The ARN format includes the region — each standard must be enabled per-region.
# List all available standards in current region
aws securityhub describe-standards \
--query 'Standards[*].{Name:Name,Arn:StandardsArn,Status:EnabledByDefault}'
# Standard ARNs (us-east-1 — replace region for other regions):
# AWS Foundational Security Best Practices v1.0.0 (FSBP):
# arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0
#
# CIS AWS Foundations Benchmark v1.2.0 (legacy — prefer 1.4 or 3.0):
# arn:aws:securityhub:us-east-1::standards/cis-aws-foundations-benchmark/v/1.2.0
#
# CIS AWS Foundations Benchmark v1.4.0:
# arn:aws:securityhub:us-east-1::standards/cis-aws-foundations-benchmark/v/1.4.0
#
# CIS AWS Foundations Benchmark v3.0.0:
# arn:aws:securityhub:us-east-1::standards/cis-aws-foundations-benchmark/v/3.0.0
#
# PCI DSS v3.2.1:
# arn:aws:securityhub:us-east-1::standards/pci-dss/v/3.2.1
#
# NIST SP 800-53 Rev 5:
# arn:aws:securityhub:us-east-1::standards/nist-800-53/v/5.0.0
# Enable FSBP and CIS v1.4 (no default standards — selective choice):
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"},
{"StandardsArn": "arn:aws:securityhub:us-east-1::standards/cis-aws-foundations-benchmark/v/1.4.0"}
]'
# Check enabled standards and their status
aws securityhub get-enabled-standards
# Status: READY = controls running; INCOMPLETE = some controls failed to initialize
# StandardsSubscriptionArn returned — needed for control management
| Standard | Control count | Best for MCP use case | Config rules created |
|---|---|---|---|
| FSBP v1.0.0 | ~280 controls | General AWS best practices for all MCP deployments — start here | ~280 (one per control) |
| CIS v1.4.0 | ~55 controls | Baseline hygiene; needed for SOC 2 Type II or compliance certifications | ~55 |
| CIS v3.0.0 | ~58 controls | Updated CIS — use this instead of v1.4 for new deployments | ~58 |
| PCI DSS v3.2.1 | ~240 controls | Only if MCP server processes cardholder data | ~240 |
| NIST SP 800-53 Rev 5 | ~220 controls | Only for US government or FedRAMP workloads | ~220 |
Disabling irrelevant controls
After enabling a standard, disable controls that don't apply to your MCP server infrastructure. A FAILED finding on a disabled control does not affect your compliance score and does not generate chargeable Config evaluations.
# List all controls for a standard with their current status
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[*].{Id:ControlId,Title:Title,Status:ControlStatus,Severity:SeverityRating}'
# Disable a specific control (legacy STANDARD_CONTROL mode)
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 "MFA hardware tokens not applicable to service accounts used by MCP automation"
# In SECURITY_CONTROL mode (recommended), disable across all standards at once:
aws securityhub batch-update-standards-control-associations \
--standards-control-association-updates '[
{
"SecurityControlId": "IAM.6",
"StandardsArn": "arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0",
"AssociationStatus": "DISABLED",
"UpdatedReason": "Hardware MFA not applicable to machine accounts"
},
{
"SecurityControlId": "IAM.9",
"StandardsArn": "arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0",
"AssociationStatus": "DISABLED",
"UpdatedReason": "Virtual MFA on root account managed by Organizations SCP"
}
]'
# Get compliance score for a specific standard
aws securityhub get-enabled-standards \
--query 'StandardsSubscriptions[?StandardsArn==`arn:aws:securityhub:us-east-1::standards/aws-foundational-security-best-practices/v/1.0.0`].StandardsStatus'
Controls to commonly disable for MCP server accounts that use AWS Organizations service control policies (SCPs) to govern root account access:
| Control ID | Title | Why disable for MCP accounts |
|---|---|---|
| IAM.4 | IAM root user access key should not exist | Root access keys automatically absent in Organizations member accounts; will show as NOT_AVAILABLE not FAILED |
| IAM.6 | Hardware MFA should be enabled for root user | Root login blocked via SCP in Organizations; hardware MFA enrollment impossible when root login is blocked |
| IAM.9 | Virtual MFA should be enabled for root user | Same as IAM.6 — root blocked by SCP |
| CloudTrail.2 | CloudTrail should have encryption at-rest enabled | If your trail uses SSE-S3 (not KMS) by design for cost reasons; override after documenting rationale |
| Config.1 | AWS Config should be enabled | Only if you use Config via Security Hub exclusively and have it enabled — this control is satisfied automatically when Security Hub enables its Config rules |
| EC2.10 | Amazon VPC security groups should not allow ingress from 0.0.0.0/0 to port 22 | If MCP server uses SSM Session Manager exclusively and has no SSH port — control will show FAILED on any SG with port 22 open, even if SSH daemon is not running |
Key FSBP controls for MCP server deployments
FSBP covers the AWS services MCP servers most commonly use. These are the highest-signal controls for a typical MCP deployment on ECS, Lambda, or EC2.
# Query findings for specific control IDs to assess current compliance
aws securityhub get-findings \
--filters '{
"ComplianceSecurityControlId": [
{"Value": "EC2.2", "Comparison": "EQUALS"},
{"Value": "EC2.19", "Comparison": "EQUALS"},
{"Value": "Lambda.1", "Comparison": "EQUALS"},
{"Value": "ECS.2", "Comparison": "EQUALS"}
],
"ComplianceStatus": [{"Value": "FAILED", "Comparison": "EQUALS"}],
"RecordState": [{"Value": "ACTIVE", "Comparison": "EQUALS"}]
}' \
--query 'Findings[*].{Control:Compliance.SecurityControlId,Resource:Resources[0].Id,Status:Compliance.Status}'
| Control | What it checks | MCP relevance | Severity |
|---|---|---|---|
| EC2.2 | VPC default security group restricts all traffic | HIGH — MCP servers should never use the default SG | MEDIUM |
| EC2.6 | VPC flow logging enabled | HIGH — required for network threat detection via GuardDuty | MEDIUM |
| EC2.19 | Security groups should not allow unrestricted access to high-risk ports | HIGH — MCP server SGs should restrict ingress to known ports | CRITICAL |
| Lambda.1 | Lambda function policy should prohibit public access | HIGH — Lambda-based MCPs should not be publicly invokable except via API Gateway | CRITICAL |
| Lambda.2 | Lambda functions should use supported runtimes | MEDIUM — outdated Node.js/Python runtimes introduce CVEs in MCP function code | MEDIUM |
| ECS.2 | ECS services should not have public IP addresses assigned automatically | HIGH — ECS-based MCP servers should route traffic through a load balancer | HIGH |
| ECS.10 | ECS Fargate tasks should use the latest Fargate platform version | MEDIUM — older Fargate versions may have container runtime CVEs | MEDIUM |
| S3.2 | S3 buckets should prohibit public read access | HIGH — MCP server data buckets must not be publicly readable | CRITICAL |
| KMS.4 | AWS KMS key rotation should be enabled | MEDIUM — encrypt MCP server data at rest with rotating keys | MEDIUM |
| IAM.1 | IAM policies should not allow full "*:*" administrative privileges | CRITICAL — MCP server IAM roles should follow least-privilege | HIGH |
Control evaluation types and timing
Security Hub controls run as Config rules with two evaluation modes: periodic (runs on a schedule) and change-triggered (runs when the relevant resource is created or modified). Understanding the mode matters for how quickly a finding appears after you fix a misconfiguration.
# Find out if a control is periodic or change-triggered
aws configservice describe-config-rules \
--config-rule-names "SecurityHub-EC2.2-a1b2c3d4e5" \
--query 'ConfigRules[0].{Source:Source.SourceDetails[0].MessageType,Frequency:MaximumExecutionFrequency}'
# Periodic controls run on these frequencies:
# One_Hour | Three_Hours | Six_Hours | Twelve_Hours | TwentyFour_Hours
# Most CIS and FSBP controls run every 12 or 24 hours for periodic checks
# Force a re-evaluation on a specific rule (for change-triggered rules):
aws configservice start-config-rules-evaluation \
--config-rule-names "SecurityHub-IAM.1-f6g7h8i9j0"
# After fixing a control violation, findings update on next evaluation cycle
# For periodic controls: may take up to 24 hours to show PASSED
# For change-triggered controls: typically updates within 5-15 minutes of resource change
# Check what Config rules Security Hub has created in your account
aws configservice describe-config-rules \
--query 'ConfigRules[?contains(ConfigRuleName, `SecurityHub`)].{Name:ConfigRuleName,State:ConfigRuleState}' \
| head -30
After remediating a failing control (e.g., enabling VPC flow logs for EC2.6), the finding does not immediately update to PASSED. Change-triggered controls re-evaluate within minutes of the resource change. Periodic controls (common for account-level checks like root MFA, GuardDuty enablement) re-evaluate on their fixed schedule — up to 24 hours. Use start-config-rules-evaluation to trigger an immediate re-evaluation without waiting for the next scheduled cycle.
Failure modes reference
| Failure | Symptom | Fix |
|---|---|---|
| Standard stuck in INCOMPLETE status | get-enabled-standards shows StandardsStatus=INCOMPLETE for days | AWS Config not enabled in the region; Security Hub requires Config to create its rules — enable Config with a delivery channel |
| Compliance score not improving after fixing resources | Fixed misconfiguration but compliance score stays the same | Periodic control — re-evaluate manually via start-config-rules-evaluation or wait up to 24 hours for next cycle |
| Unexpected Config charges after enabling standards | AWS bill shows Config rule evaluation charges within hours of enabling | Each enabled control = one Config rule; 280 FSBP controls × 100 resources × monthly evaluations can exceed free tier quickly — disable controls not relevant to your stack |
| update-standards-control returns error in SECURITY_CONTROL mode | Cannot disable control via legacy API | In SECURITY_CONTROL mode, use batch-update-standards-control-associations instead of update-standards-control; the legacy API rejects calls when ControlFindingGenerator=SECURITY_CONTROL |
| Control shows NOT_AVAILABLE instead of PASSED or FAILED | Control present in standard but showing NOT_AVAILABLE status | The relevant AWS service is not enabled or has no resources of the relevant type in this region — e.g., EKS controls on an account with no EKS clusters; safe to disable these controls or ignore them |
| Same control finding appears in multiple standards | One S3 bucket generates findings for both FSBP and CIS | ControlFindingGenerator set to STANDARD_CONTROL (legacy); switch to SECURITY_CONTROL via update-security-hub-configuration to generate one finding per control per resource across all standards |