Skip to main content

Network Security

TSC mapping: CC6.6 (Logical access restrictions from outside system boundaries), CC6.7 (Data transmission controls)

Network controls are a heavily-evidenced area for SOC 2. Auditors will review VPC designs, security group rules, and WAF configurations. The key principle: deny by default, allow by exception.


1. VPC Design — Defence in Depth

Delete the default VPC

The default VPC has permissive settings and should not be used for production workloads. Auditors flag its existence in active regions.

# List default VPCs across all regions
aws ec2 describe-vpcs \
--filters Name=isDefault,Values=true \
--query 'Vpcs[*].[VpcId,OwnerId]' \
--output table

# Delete the default VPC (after removing its subnets, IGW, etc.)
aws ec2 delete-vpc --vpc-id vpc-xxxxxxxxxxxxxxxxx
VPC: 10.0.0.0/16
├── Public subnets (10.0.0.0/20, 10.0.16.0/20) ← Load balancers only
├── Private subnets (10.0.128.0/20, 10.0.144.0/20) ← Application layer
└── Data subnets (10.0.192.0/20, 10.0.208.0/20) ← RDS, ElastiCache

Key rules:

  • Application servers must be in private subnets with no direct internet access.
  • Outbound internet access from private subnets goes through NAT Gateway, not an IGW.
  • Data layer subnets have no route to the internet at all.

AWS Config rule:

RuleWhat it checks
vpc-flow-logs-enabledFlow Logs enabled for all VPCs

Reference: Amazon VPC documentation →


2. Security Groups — Least Privilege

Security groups are stateful firewalls. SOC 2 auditors specifically look for 0.0.0.0/0 inbound rules on administrative ports.

Audit for unrestricted access

# Find security groups allowing inbound SSH (port 22) from anywhere
aws ec2 describe-security-groups \
--filters "Name=ip-permission.from-port,Values=22" \
"Name=ip-permission.cidr,Values=0.0.0.0/0" \
--query 'SecurityGroups[*].[GroupId,GroupName]' \
--output table

# Find security groups allowing inbound RDP (port 3389) from anywhere
aws ec2 describe-security-groups \
--filters "Name=ip-permission.from-port,Values=3389" \
"Name=ip-permission.cidr,Values=0.0.0.0/0" \
--query 'SecurityGroups[*].[GroupId,GroupName]' \
--output table

Revoke an overly permissive rule

aws ec2 revoke-security-group-ingress \
--group-id sg-xxxxxxxxxxxxxxxxx \
--protocol tcp \
--port 22 \
--cidr 0.0.0.0/0
Load Balancer SG:
Inbound: 443 from 0.0.0.0/0 (HTTPS only)
80 from 0.0.0.0/0 (redirect to HTTPS)
Outbound: 8080 to App SG

App SG:
Inbound: 8080 from Load Balancer SG
Outbound: 5432 to DB SG
443 to 0.0.0.0/0 (external API calls, via NAT)

DB SG:
Inbound: 5432 from App SG
Outbound: (no outbound needed)

AWS Config rules:

RuleWhat it checks
restricted-sshNo SG allows unrestricted SSH inbound
restricted-common-portsNo SG allows unrestricted access on common admin ports
vpc-sg-open-only-to-authorized-portsOnly specific ports allowed from internet

3. Network ACLs

NACLs are stateless and operate at the subnet level — a second layer of defence behind security groups.

Recommended NACL rules for private subnets:

Rule #TypeProtocolPortSourceAllow/Deny
100InboundTCP1024-655350.0.0.0/0ALLOW (return traffic)
200InboundTCP44310.0.0.0/16ALLOW (internal HTTPS)
32766InboundAllAll0.0.0.0/0DENY
100OutboundTCP4430.0.0.0/0ALLOW
200OutboundTCP1024-655350.0.0.0/0ALLOW (ephemeral ports)
32766OutboundAllAll0.0.0.0/0DENY

4. VPC Flow Logs

Flow Logs capture source/destination IPs, ports, protocols, and allow/deny decisions for all traffic through every ENI. Required for CC7.2 (monitoring) evidence and feeds GuardDuty threat detection.

# Enable for all VPCs in a region (run per region)
for vpc in $(aws ec2 describe-vpcs --query 'Vpcs[*].VpcId' --output text); do
aws ec2 create-flow-logs \
--resource-type VPC \
--resource-ids $vpc \
--traffic-type ALL \
--log-destination-type cloud-watch-logs \
--log-group-name /aws/vpc/flowlogs \
--deliver-logs-permission-arn arn:aws:iam::<account>:role/flowlogs-role
echo "Enabled flow logs for $vpc"
done

Verify:

aws ec2 describe-flow-logs \
--filter "Name=resource-id,Values=vpc-xxxxxxxxxxxxxxxxx" \
--query 'FlowLogs[*].[FlowLogId,FlowLogStatus,LogDestinationType]'

Reference: VPC Flow Logs documentation →


5. AWS WAF — Web Application Firewall

WAF protects public-facing load balancers, API Gateways, and CloudFront distributions from OWASP Top 10 attacks. Required for CC6.6 (external threat protection).

# Create a WAF Web ACL with the AWS Managed Rule Groups
aws wafv2 create-web-acl \
--name soc2-web-acl \
--scope REGIONAL \
--default-action Allow={} \
--rules '[
{
"Name": "AWSManagedRulesCommonRuleSet",
"Priority": 1,
"OverrideAction": {"None": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "CommonRuleSet"
},
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesCommonRuleSet"
}
}
},
{
"Name": "AWSManagedRulesKnownBadInputsRuleSet",
"Priority": 2,
"OverrideAction": {"None": {}},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "KnownBadInputs"
},
"Statement": {
"ManagedRuleGroupStatement": {
"VendorName": "AWS",
"Name": "AWSManagedRulesKnownBadInputsRuleSet"
}
}
}
]' \
--visibility-config \
SampledRequestsEnabled=true,CloudWatchMetricsEnabled=true,MetricName=soc2-web-acl \
--region us-east-1

# Associate with an ALB
aws wafv2 associate-web-acl \
--web-acl-arn arn:aws:wafv2:<region>:<account>:regional/webacl/soc2-web-acl/<id> \
--resource-arn arn:aws:elasticloadbalancing:<region>:<account>:loadbalancer/app/<name>/<id>

Enable WAF logging to S3 or CloudWatch:

aws wafv2 put-logging-configuration \
--logging-configuration \
ResourceArn=arn:aws:wafv2:<region>:<account>:regional/webacl/soc2-web-acl/<id>,\
LogDestinationConfigs=arn:aws:firehose:<region>:<account>:deliverystream/aws-waf-logs-soc2

Reference: AWS WAF documentation →


6. Encryption in Transit

Enforce TLS on all public-facing and internal service communication. This is required for CC6.7.

Enforce HTTPS on S3

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyNonHTTPS",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}

Enforce TLS 1.2+ on ALB

# Set the SSL policy on an HTTPS listener
aws elbv2 modify-listener \
--listener-arn arn:aws:elasticloadbalancing:...:listener/app/... \
--ssl-policy ELBSecurityPolicy-TLS13-1-2-2021-06

Use AWS Certificate Manager for public certificates

# Request a public certificate (auto-renewed)
aws acm request-certificate \
--domain-name "api.example.com" \
--validation-method DNS \
--subject-alternative-names "*.example.com"

AWS Config rules:

RuleWhat it checks
alb-http-to-https-redirection-checkALB HTTP listeners redirect to HTTPS
acm-certificate-expiration-checkACM certs expire in more than 90 days
elb-tls-https-listeners-onlyELB listeners use only HTTPS/TLS

Reference: AWS WAF documentation → · Amazon VPC documentation →


SOC 2 Evidence for Network Security

Evidence itemHow to collect
VPC and subnet configurationaws ec2 describe-vpcs, aws ec2 describe-subnets
Security group rulesaws ec2 describe-security-groups
Flow Logs configurationaws ec2 describe-flow-logs
WAF Web ACL rulesaws wafv2 list-web-acls + get-web-acl
ALB TLS policyaws elbv2 describe-listeners
Config rule compliance (network rules)AWS Config console → Compliance by rule
ACM certificate listaws acm list-certificates