NetworkingIntermediate15 min read

    AWS VPC Security Best Practices

    Tarek Cheikh

    Founder & AWS Security Expert

    View Security Card

    Your Amazon Virtual Private Cloud (VPC) is the network foundation of every AWS workload. Every EC2 instance, RDS database, Lambda function, and container runs inside a VPC. If the network layer is misconfigured, attackers can move laterally, exfiltrate data, or reach resources that should never be publicly accessible -- regardless of how well you have configured IAM or encryption.

    In 2025, multiple incidents demonstrated the risk of poorly secured VPCs. A misconfigured security group exposing port 22 to the internet led to a full EC2 compromise and lateral movement across an organization's production environment. Separately, attackers leveraged overly permissive egress rules to exfiltrate sensitive data via DNS tunneling before GuardDuty alerted the team. AWS responded by launching VPC Block Public Access (November 2024) and VPC Encryption Controls (November 2025) -- two features that make it dramatically easier to enforce network-level security at scale.

    This guide covers 12 battle-tested VPC security best practices, each with real AWS CLI commands, audit procedures, and the latest 2024-2026 updates from AWS.

    1. Enforce Least Privilege on Security Groups

    Security groups are stateful firewalls attached to ENIs (Elastic Network Interfaces). They are the primary network access control for EC2 instances, RDS databases, ECS tasks, Lambda functions, and most other VPC resources. A single overly permissive rule can expose critical infrastructure to the entire internet.

    Key Rules

    • Never allow 0.0.0.0/0 or ::/0 on ingress. Restrict source CIDRs to known ranges. Use security group references for internal communication.
    • Restrict ports to exact needs. Do not allow port ranges like 0-65535. Open only the specific ports your application requires (e.g., 443 for HTTPS, 5432 for PostgreSQL).
    • Add descriptions to every rule. Descriptions are immutable audit trails -- use them to document who requested the rule and why.
    • Prefer security group references over CIDR blocks for internal traffic. This way, rules automatically adapt as instances scale.
    # Create a security group with a meaningful description
    aws ec2 create-security-group   --group-name web-server-sg   --description "Web servers - HTTPS only from ALB"   --vpc-id vpc-0123456789abcdef0
    
    # Add a rule referencing the ALB security group (not a CIDR)
    aws ec2 authorize-security-group-ingress   --group-id sg-0123456789abcdef0   --protocol tcp --port 443   --source-group sg-0fedcba9876543210   --description "HTTPS from ALB security group - JIRA-1234"
    
    # Audit: find security groups with 0.0.0.0/0 ingress
    aws ec2 describe-security-groups   --query "SecurityGroups[?IpPermissions[?contains(IpRanges[].CidrIp, '0.0.0.0/0')]].[GroupId,GroupName]"   --output table

    Security Hub Controls: [EC2.18] Security groups should only allow unrestricted incoming traffic for authorized ports. [EC2.19] Security groups should not allow unrestricted access to high-risk ports. [EC2.2] VPC default security group should not allow inbound or outbound traffic.

    CIS Benchmark: Control 5.2 (no ingress from 0.0.0.0/0 to port 22), Control 5.3 (no ingress from 0.0.0.0/0 to port 3389).

    2. Lock Down the Default Security Group

    Every VPC comes with a default security group that allows all inbound traffic from members of the same group and all outbound traffic. If resources are accidentally launched without specifying a security group, they inherit these permissive defaults. CIS Benchmark Control 5.4 requires that the default security group restricts all traffic.

    Implementation

    • Remove all inbound and outbound rules from the default security group in every VPC.
    • Never attach the default security group to any resource. Always create and assign custom security groups.
    • Use AWS Config to continuously monitor for violations.
    # Get the default security group for each VPC
    aws ec2 describe-security-groups   --filters "Name=group-name,Values=default"   --query "SecurityGroups[].[VpcId,GroupId]" --output table
    
    # Remove all inbound rules from default security group
    aws ec2 revoke-security-group-ingress   --group-id sg-DEFAULT   --ip-permissions "$(aws ec2 describe-security-groups     --group-ids sg-DEFAULT     --query 'SecurityGroups[0].IpPermissions' --output json)"
    
    # Remove all outbound rules from default security group
    aws ec2 revoke-security-group-egress   --group-id sg-DEFAULT   --ip-permissions "$(aws ec2 describe-security-groups     --group-ids sg-DEFAULT     --query 'SecurityGroups[0].IpPermissionsEgress' --output json)"
    
    # Verify it is empty
    aws ec2 describe-security-groups --group-ids sg-DEFAULT   --query "SecurityGroups[0].[IpPermissions,IpPermissionsEgress]"

    AWS Config Rule: vpc-default-security-group-closed -- automatically flags any default security group with active rules.

    CIS Benchmark: Control 5.4 (default security group restricts all traffic).

    3. Enable VPC Flow Logs Everywhere

    VPC Flow Logs capture metadata about IP traffic flowing through your network interfaces. Without flow logs, you have zero visibility into network-level activity -- you cannot detect port scans, lateral movement, or data exfiltration. CIS Benchmark Control 3.7 requires flow logging on all VPCs.

    Where to Send Flow Logs

    • CloudWatch Logs: Best for real-time alerting and metric filters. Higher cost at scale.
    • S3: Best for long-term storage, Athena queries, and GuardDuty analysis. Lower cost.
    • Kinesis Data Firehose: Best for streaming to third-party SIEMs (Splunk, Datadog).
    # Enable VPC Flow Logs to S3 (recommended for cost and analysis)
    aws ec2 create-flow-logs   --resource-type VPC   --resource-ids vpc-0123456789abcdef0   --traffic-type ALL   --log-destination-type s3   --log-destination arn:aws:s3:::my-flowlogs-bucket/vpc-logs/   --max-aggregation-interval 60   --log-format '${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status} ${vpc-id} ${subnet-id} ${az-id} ${sublocation-type} ${sublocation-id} ${pkt-srcaddr} ${pkt-dstaddr} ${region} ${pkt-src-aws-service} ${pkt-dst-aws-service} ${flow-direction} ${traffic-path} ${tcp-flags}'
    
    # Enable VPC Flow Logs to CloudWatch for real-time alerting
    aws ec2 create-flow-logs   --resource-type VPC   --resource-ids vpc-0123456789abcdef0   --traffic-type REJECT   --log-destination-type cloud-watch-logs   --log-group-name /vpc/flowlogs   --deliver-logs-permission-arn arn:aws:iam::123456789012:role/VPCFlowLogsRole
    
    # Verify flow logs are enabled for all VPCs
    aws ec2 describe-flow-logs   --query "FlowLogs[].[FlowLogId,ResourceId,LogDestinationType,TrafficType]"   --output table

    Athena Query: Detect Rejected Traffic Patterns

    SELECT srcaddr, dstaddr, dstport, protocol, COUNT(*) AS hits
    FROM vpc_flow_logs
    WHERE action = 'REJECT'
      AND start > to_unixtime(current_timestamp - interval '24' hour)
    GROUP BY srcaddr, dstaddr, dstport, protocol
    ORDER BY hits DESC
    LIMIT 20;

    Security Hub Control: [EC2.6] VPC flow logging should be enabled in all VPCs.

    CIS Benchmark: Control 3.7 (VPC flow logging enabled in all VPCs).

    4. Use VPC Endpoints to Reduce Internet Exposure

    Without VPC endpoints, traffic to AWS services (S3, DynamoDB, STS, CloudWatch, etc.) traverses the public internet via NAT Gateways or Internet Gateways. This creates unnecessary exposure and data transfer costs. VPC endpoints keep traffic on the AWS backbone network.

    Types of Endpoints

    • Gateway endpoints (free): S3 and DynamoDB only. Added to route tables -- no ENI required.
    • Interface endpoints (PrivateLink): All other services. Creates an ENI in your subnet with a private IP.
    # Create an S3 Gateway endpoint (free)
    aws ec2 create-vpc-endpoint   --vpc-id vpc-0123456789abcdef0   --service-name com.amazonaws.eu-west-1.s3   --route-table-ids rtb-0123456789abcdef0
    
    # Create an STS Interface endpoint (PrivateLink)
    aws ec2 create-vpc-endpoint   --vpc-id vpc-0123456789abcdef0   --vpc-endpoint-type Interface   --service-name com.amazonaws.eu-west-1.sts   --subnet-ids subnet-0123456789abcdef0 subnet-0fedcba9876543210   --security-group-ids sg-0123456789abcdef0   --private-dns-enabled

    Endpoint Policies

    VPC endpoint policies restrict which principals and resources can be accessed through the endpoint. This is a critical component of the AWS data perimeter framework.

    {
      "Version": "2012-10-17",
      "Statement": [{
        "Sid": "AllowOnlyMyOrg",
        "Effect": "Allow",
        "Principal": "*",
        "Action": "s3:*",
        "Resource": ["arn:aws:s3:::my-org-*", "arn:aws:s3:::my-org-*/*"],
        "Condition": {
          "StringEquals": {
            "aws:PrincipalOrgID": "o-EXAMPLE"
          }
        }
      }]
    }

    Priority endpoints to deploy: S3, DynamoDB, STS, KMS, CloudWatch Logs, ECR (dkr + api), Secrets Manager, SSM, and EC2 Messages.

    5. Enable VPC Block Public Access

    Launched in November 2024, VPC Block Public Access (BPA) is a declarative, account-level control that authoritatively blocks internet traffic to and from your VPCs via Internet Gateways and Egress-only Internet Gateways. Unlike security groups and NACLs which require correct configuration on every resource, BPA is a single toggle that overrides all other network settings.

    Modes

    • Bidirectional: Blocks all inbound and outbound internet traffic. Strongest protection for internal workloads.
    • Ingress-only: Blocks inbound internet traffic but allows outbound via NAT Gateways and Egress-only Internet Gateways.

    Exclusions

    You can exclude specific VPCs or subnets that legitimately need internet access (e.g., public ALB subnets). This allows you to enforce BPA across your entire account while maintaining connectivity for front-end resources.

    # Enable VPC Block Public Access at the account level (bidirectional)
    aws ec2 modify-vpc-block-public-access-options   --internet-gateway-block-mode block-bidirectional
    
    # Enable ingress-only mode (allow NAT Gateway egress)
    aws ec2 modify-vpc-block-public-access-options   --internet-gateway-block-mode block-ingress
    
    # Exclude a specific subnet for public ALB
    aws ec2 create-vpc-block-public-access-exclusion   --internet-gateway-exclusion-mode allow-bidirectional   --subnet-id subnet-0123456789abcdef0
    
    # Check current BPA status
    aws ec2 describe-vpc-block-public-access-options
    
    # List exclusions
    aws ec2 describe-vpc-block-public-access-exclusions

    Integration: BPA integrates with AWS Network Access Analyzer for impact analysis before enabling, and with VPC Flow Logs for ongoing visibility. There is no additional charge for using BPA.

    Best practice: Enable BPA in ingress-only mode as a baseline for all accounts in your organization. Use SCP-based guardrails to prevent member accounts from disabling BPA.

    6. Enforce Encryption in Transit with VPC Encryption Controls

    Launched at re:Invent 2025, VPC Encryption Controls make it easy to audit and enforce encryption in transit within and across VPCs. This addresses a long-standing blind spot: while most organizations enforce encryption at the application layer, they have had no way to verify or enforce it at the network layer.

    Operational Modes

    • Monitor mode: Enriches VPC Flow Logs with an encryption-status field showing whether traffic is cleartext, encrypted via Nitro hardware, encrypted at the application layer, or both. Use this first to identify unencrypted flows.
    • Enforce mode: Automatically applies AES-256 hardware-based encryption on traffic between supported resources (Fargate, NLB, ALB, Transit Gateways, and Nitro instances). Plaintext traffic is blocked.
    # Enable VPC Encryption Controls in monitor mode
    aws ec2 create-vpc-encryption-control   --vpc-id vpc-0123456789abcdef0   --mode monitor
    
    # Query Flow Logs for unencrypted traffic
    # The encryption-status field shows: cleartext | nitro | app-layer | both
    
    # After reviewing, switch to enforce mode
    aws ec2 modify-vpc-encryption-control   --vpc-id vpc-0123456789abcdef0   --mode enforce

    2025-2026 Update: VPC Encryption Controls were free during the introductory period (November 2025 - February 2026). Beginning March 2026, AWS charges a fixed hourly rate per VPC with encryption controls enabled.

    Best practice: Start in monitor mode to identify plaintext traffic. Fix application-layer encryption gaps. Then switch to enforce mode to guarantee all in-transit traffic is encrypted.

    7. Layer NACLs for Subnet-Level Defense

    Network Access Control Lists (NACLs) are stateless firewalls at the subnet level. Unlike security groups, NACLs evaluate both inbound and outbound rules independently and process rules in order by number. They provide a second layer of defense below security groups.

    When to Use NACLs

    • Explicit deny lists: Block known malicious CIDRs or regions at the subnet level.
    • Subnet isolation: Prevent entire subnets from communicating with each other (e.g., isolate database subnets from public subnets).
    • Compliance requirements: Some frameworks require defense-in-depth with multiple network controls.
    # Create a NACL for database subnets
    aws ec2 create-network-acl   --vpc-id vpc-0123456789abcdef0   --tag-specifications 'ResourceType=network-acl,Tags=[{Key=Name,Value=db-subnet-nacl}]'
    
    # Allow inbound PostgreSQL only from app subnets
    aws ec2 create-network-acl-entry   --network-acl-id acl-0123456789abcdef0   --rule-number 100 --protocol tcp --port-range From=5432,To=5432   --cidr-block 10.0.1.0/24 --rule-action allow --ingress
    
    # Deny all other inbound traffic
    aws ec2 create-network-acl-entry   --network-acl-id acl-0123456789abcdef0   --rule-number 200 --protocol -1   --cidr-block 0.0.0.0/0 --rule-action deny --ingress
    
    # Allow outbound ephemeral ports for return traffic (stateless!)
    aws ec2 create-network-acl-entry   --network-acl-id acl-0123456789abcdef0   --rule-number 100 --protocol tcp --port-range From=1024,To=65535   --cidr-block 10.0.1.0/24 --rule-action allow --egress

    Caveat: NACLs are stateless. You must explicitly allow return traffic (ephemeral ports 1024-65535) on the opposite direction. Forgetting this is the most common NACL misconfiguration.

    CIS Benchmark: Control 5.1 (ensure NACLs do not allow ingress from 0.0.0.0/0 to administration ports).

    8. Deploy AWS Network Firewall for Centralized Filtering

    AWS Network Firewall is a managed, stateful firewall with IDS/IPS capabilities powered by Suricata rules. It provides deep packet inspection, domain-based filtering, and centralized egress control -- capabilities that security groups and NACLs cannot offer.

    Architecture

    • Centralized egress: Route all outbound traffic through a dedicated inspection VPC using Transit Gateway. This gives you a single choke point for egress filtering.
    • Domain filtering: Allow outbound HTTPS only to approved domains (e.g., *.amazonaws.com, api.github.com). Block all other egress at the domain level.
    • IDS/IPS: Deploy Suricata-compatible rules to detect and block known attack patterns, malware callbacks, and C2 communications.
    # Create a Network Firewall rule group for domain filtering
    aws network-firewall create-rule-group   --rule-group-name allow-approved-domains   --type STATEFUL   --capacity 100   --rule-group '{
        "RulesSource": {
          "RulesSourceList": {
            "Targets": [".amazonaws.com", "api.github.com", ".datadog.com"],
            "TargetTypes": ["TLS_SNI", "HTTP_HOST"],
            "GeneratedRulesType": "ALLOWLIST"
          }
        }
      }'
    
    # Create the firewall policy
    aws network-firewall create-firewall-policy   --firewall-policy-name egress-policy   --firewall-policy '{
        "StatelessDefaultActions": ["aws:forward_to_sfe"],
        "StatelessFragmentDefaultActions": ["aws:forward_to_sfe"],
        "StatefulRuleGroupReferences": [
          {"ResourceArn": "arn:aws:network-firewall:eu-west-1:123456789012:stateful-rulegroup/allow-approved-domains"}
        ]
      }'
    
    # Create the firewall
    aws network-firewall create-firewall   --firewall-name central-egress-fw   --vpc-id vpc-INSPECTION   --subnet-mappings SubnetId=subnet-FW1 SubnetId=subnet-FW2   --firewall-policy-arn arn:aws:network-firewall:eu-west-1:123456789012:firewall-policy/egress-policy

    Best practice: Start with an allow-list approach for egress domains. Log all denied traffic to S3 for analysis. Use AWS Firewall Manager to deploy firewall policies across all accounts in your organization.

    9. Secure VPC Peering and Transit Gateway

    VPC Peering and Transit Gateway enable communication between VPCs, but they introduce lateral movement risk if routing is overly permissive. A key property of VPC peering is that it is non-transitive -- if VPC A peers with VPC B and VPC B peers with VPC C, VPC A cannot reach VPC C through B. Transit Gateway, however, enables hub-and-spoke routing that can be transitive if route tables are not properly isolated.

    VPC Peering Security

    • Restrict route table entries. Only add routes for the specific CIDR ranges needed, not the entire peered VPC CIDR.
    • Disable DNS resolution across peering unless explicitly required.
    • Use security groups to restrict which resources can communicate across the peering connection.

    Transit Gateway Security

    • Use separate route tables to isolate environments (production, staging, development). Never share a single route table across all attachments.
    • Disable route propagation and use static routes for fine-grained control.
    • Use AWS RAM (Resource Access Manager) to share Transit Gateways across accounts within your organization only.
    # Create isolated route tables for Transit Gateway
    aws ec2 create-transit-gateway-route-table   --transit-gateway-id tgw-0123456789abcdef0   --tag-specifications 'ResourceType=transit-gateway-route-table,Tags=[{Key=Name,Value=production-rt}]'
    
    aws ec2 create-transit-gateway-route-table   --transit-gateway-id tgw-0123456789abcdef0   --tag-specifications 'ResourceType=transit-gateway-route-table,Tags=[{Key=Name,Value=development-rt}]'
    
    # Associate production VPCs with the production route table only
    aws ec2 associate-transit-gateway-route-table   --transit-gateway-route-table-id tgw-rtb-PROD   --transit-gateway-attachment-id tgw-attach-PROD-VPC
    
    # Audit: check for overly broad peering routes
    aws ec2 describe-route-tables   --query "RouteTables[].Routes[?VpcPeeringConnectionId!=null].[DestinationCidrBlock,VpcPeeringConnectionId]"   --output table

    CIS Benchmark: Control 5.5 (routing tables for VPC peering are least access).

    10. Enable GuardDuty for VPC Threat Detection

    Amazon GuardDuty automatically ingests VPC Flow Logs, DNS logs, and CloudTrail events to detect threats. It identifies port scanning, brute-force attempts, cryptocurrency mining, DNS exfiltration, and communication with known malicious IPs -- all without deploying any agents.

    Key VPC-Related Finding Types

    • Trojan:EC2/DNSDataExfiltration: An EC2 instance is using DNS queries to exfiltrate data to an attacker-controlled domain.
    • Recon:EC2/PortProbeUnprotectedPort: An unprotected port on an EC2 instance is being probed by a known malicious IP.
    • UnauthorizedAccess:EC2/TorRelay: An EC2 instance is acting as a Tor relay node.
    • Backdoor:EC2/C&CActivity.B: An EC2 instance is communicating with a known command-and-control server.
    • CryptoCurrency:EC2/BitcoinTool.B: An EC2 instance is mining cryptocurrency.
    # Enable GuardDuty in the current region
    aws guardduty create-detector --enable --finding-publishing-frequency FIFTEEN_MINUTES
    
    # Enable GuardDuty across all regions
    for region in $(aws ec2 describe-regions --query "Regions[].RegionName" --output text); do
      aws guardduty create-detector --enable --region "$region" 2>/dev/null
      echo "Enabled GuardDuty in $region"
    done
    
    # Integrate with Route 53 DNS Firewall for automated blocking
    # GuardDuty findings feed into DNS Firewall managed domain lists
    aws route53resolver create-firewall-rule   --firewall-rule-group-id rslvr-frg-EXAMPLE   --firewall-domain-list-id rslvr-fdl-EXAMPLE   --priority 100 --action BLOCK   --block-response NXDOMAIN   --name block-guardduty-threats

    Best practice: Enable GuardDuty in every region, even regions you do not actively use. Attackers frequently spin up resources in unused regions. Use GuardDuty Extended Threat Detection (launched 2025) for multi-stage attack sequence detection.

    11. Implement the Data Perimeter Framework

    The AWS data perimeter framework uses three dimensions to control access: trusted identities, trusted resources, and expected networks. VPCs are the foundation of the network perimeter dimension. By combining VPC endpoints with endpoint policies, SCPs, and resource control policies (RCPs), you can ensure that data only flows between authorized principals and resources.

    Three Perimeter Dimensions

    • Identity perimeter: Only trusted identities (principals in your organization) can access resources. Enforced via SCPs and resource policies.
    • Resource perimeter: Only trusted resources (in your accounts) can be accessed. Enforced via VPC endpoint policies and SCPs.
    • Network perimeter: Resources can only be accessed from expected networks (your VPCs). Enforced via resource policies with aws:SourceVpc and aws:SourceVpce conditions.
    {
      "Version": "2012-10-17",
      "Statement": [{
        "Sid": "EnforceNetworkPerimeter",
        "Effect": "Deny",
        "Principal": "*",
        "Action": "s3:*",
        "Resource": ["arn:aws:s3:::sensitive-data-*", "arn:aws:s3:::sensitive-data-*/*"],
        "Condition": {
          "StringNotEqualsIfExists": {
            "aws:SourceVpc": "vpc-0123456789abcdef0"
          },
          "BoolIfExists": {
            "aws:ViaAWSService": "false"
          }
        }
      }]
    }

    Scaling with aws:VpceOrgID

    The aws:VpceOrgID condition key (2025 update) allows you to write network perimeter policies that apply to all VPC endpoints in your organization, without listing individual VPC endpoint IDs.

    {
      "Condition": {
        "StringNotEqualsIfExists": {
          "aws:SourceOrgID": "o-EXAMPLE"
        }
      }
    }

    Best practice: Implement the data perimeter incrementally. Start by deploying VPC endpoints for critical services (S3, STS, KMS). Add endpoint policies. Then layer SCPs and resource policies. Monitor with CloudTrail and Access Analyzer.

    12. Automate Continuous Compliance

    Manual audits do not scale. Use AWS Security Hub, AWS Config, and automated remediation to continuously monitor and enforce VPC security posture across your organization.

    Security Hub Controls for VPC

    • [EC2.2]: VPC default security group should not allow inbound or outbound traffic
    • [EC2.6]: VPC flow logging should be enabled in all VPCs
    • [EC2.18]: Security groups should only allow unrestricted incoming traffic for authorized ports
    • [EC2.19]: Security groups should not allow unrestricted access to high-risk ports
    • [EC2.21]: Network ACLs should not allow ingress from 0.0.0.0/0 to port 22 or port 3389
    • [EC2.13]: Security groups should not allow ingress from 0.0.0.0/0 or ::/0 to port 22
    • [EC2.14]: Security groups should not allow ingress from 0.0.0.0/0 or ::/0 to port 3389
    # Enable CIS Benchmark v5.0 in Security Hub
    aws securityhub batch-enable-standards   --standards-subscription-requests '[{
        "StandardsArn": "arn:aws:securityhub:::standards/cis-aws-foundations-benchmark/v/5.0.0"
      }]'
    
    # Deploy AWS Config conformance pack for VPC controls
    aws configservice put-conformance-pack   --conformance-pack-name vpc-security-pack   --template-body file://vpc-conformance-pack.yaml
    
    # Automated remediation: auto-revoke 0.0.0.0/0 rules
    # Create a Config remediation action
    aws configservice put-remediation-configurations   --remediation-configurations '[{
        "ConfigRuleName": "restricted-ssh",
        "TargetType": "SSM_DOCUMENT",
        "TargetId": "AWS-DisablePublicAccessForSecurityGroup",
        "Automatic": true,
        "MaximumAutomaticAttempts": 3,
        "RetryAttemptSeconds": 60,
        "Parameters": {
          "GroupId": {"ResourceValue": {"Value": "RESOURCE_ID"}}
        }
      }]'
    
    # Query Security Hub for failed VPC controls
    aws securityhub get-findings   --filters '{
        "ComplianceStatus": [{"Value": "FAILED", "Comparison": "EQUALS"}],
        "ProductFields": [{"Key": "ControlId", "Value": "EC2.2", "Comparison": "EQUALS"}]
      }'   --query "Findings[].[Title,Resources[0].Id]" --output table

    Automated Remediation Architecture

    Use EventBridge rules to trigger Lambda functions on Security Hub findings. For example, automatically revoke any security group rule that allows 0.0.0.0/0 ingress on SSH or RDP, and notify the team via SNS.

    # Create EventBridge rule for Security Hub findings
    aws events put-rule   --name auto-remediate-open-sg   --event-pattern '{
        "source": ["aws.securityhub"],
        "detail-type": ["Security Hub Findings - Imported"],
        "detail": {
          "findings": {
            "Compliance": {"Status": ["FAILED"]},
            "ProductFields": {"ControlId": ["EC2.13", "EC2.14"]}
          }
        }
      }'

    Best practice: Start with detective controls (monitoring and alerting). Once you are confident in the detection logic, enable automated remediation for high-confidence, low-risk actions like revoking 0.0.0.0/0 SSH rules.


    Common Misconfigurations

    Misconfiguration Risk Detection
    Security group allows 0.0.0.0/0 on SSH (port 22) Brute-force attacks, unauthorized access Security Hub [EC2.13], CIS 5.2
    Default security group has active rules Accidental exposure of new resources Security Hub [EC2.2], CIS 5.4
    VPC Flow Logs disabled No network visibility for incident response Security Hub [EC2.6], CIS 3.7
    No VPC endpoints for S3/STS Traffic traverses public internet unnecessarily Network Access Analyzer
    Overly permissive VPC peering routes Lateral movement across environments CIS 5.5, route table audit
    No egress filtering Data exfiltration via DNS, HTTPS to attacker domains Network Firewall logs, GuardDuty DNS findings

    Quick Reference Checklist

    # Practice Priority
    1Enforce least privilege on security groupsCritical
    2Lock down default security groupCritical
    3Enable VPC Flow Logs everywhereCritical
    4Deploy VPC Endpoints for AWS servicesHigh
    5Enable VPC Block Public AccessHigh
    6Enforce encryption in transitHigh
    7Layer NACLs for subnet-level defenseMedium
    8Deploy AWS Network FirewallHigh
    9Secure VPC Peering and Transit GatewayHigh
    10Enable GuardDuty for VPC threat detectionCritical
    11Implement data perimeter frameworkMedium
    12Automate continuous complianceHigh

    Related Resources

    Go Deeper: The State of AWS Security 2026

    This article is just the start. Get the full picture with our free whitepaper - 8 chapters covering IAM, S3, VPC, monitoring, agentic AI security, compliance, and a prioritized action plan with 50+ CLI commands.

    VPCSecurity GroupsNACLsFlow LogsVPC EndpointsNetwork FirewallTransit GatewayGuardDutyData Perimeter