AnalysisType: policy
Filename: aws_network_acl_restricts_insecure_protocols.py
PolicyID: "AWS.NetworkACL.RestrictsInsecureProtocols"
DisplayName: "AWS Network ACL Restricts Insecure Protocols"
Enabled: false
ResourceTypes:
- AWS.EC2.NetworkACL
Tags:
- AWS
- PCI
- Command and Control:Non-Application Layer Protocol
Reports:
PCI:
- 8.2.1
MITRE ATT&CK:
- TA0011:T1095
Severity: Low
Description: >
This policy validates that Network ACLs block the usage of ports typically associated with insecure or unencrypted protocols.
Runbook: Add Network ACL entries to block ports typically associated with insecure protocols.
Reference: https://docs.aws.amazon.com/vpc/latest/userguide/vpc-recommended-nacl-rules.html
Tests:
- Name: Network ACL Restricts Insecure Protocols
ExpectedResult: true
Resource:
{
"AccountId": "123456789012",
"Region": "ap-southeast-2",
"ARN": "arn:aws:ec2:ap-southeast-2:123456789012:network-acl/acl-111222333",
"ID": "acl-111222333",
"Tags": { "environment": "pci" },
"ResourceID": "arn:aws:ec2:ap-southeast-2:123456789012:network-acl/acl-111222333",
"ResourceType": "AWS.EC2.NetworkACL",
"TimeCreated": null,
"Associations":
[
{
"NetworkAclAssociationId": "aclassoc-111222333",
"NetworkAclId": "acl-111222333",
"SubnetId": "subnet-111222333",
},
],
"Entries":
[
{
"CidrBlock": "8.8.8.8/32",
"Egress": false,
"IcmpTypeCode": null,
"Ipv6CidrBlock": null,
"PortRange": { "From": 22, "To": 22 },
"Protocol": "6",
"RuleAction": "allow",
"RuleNumber": 100,
},
{
"CidrBlock": "0.0.0.0/0",
"Egress": true,
"IcmpTypeCode": null,
"Ipv6CidrBlock": null,
"PortRange": { "From": 22, "To": 22 },
"Protocol": "6",
"RuleAction": "allow",
"RuleNumber": 100,
},
],
"IsDefault": true,
"NetworkAclId": "acl-111222333",
"OwnerId": "123456789012",
"VpcId": "vpc-6aa60b12",
}
- Name: Insecure Ports Not Restricted
ExpectedResult: false
Resource:
{
"AccountId": "123456789012",
"Region": "ap-southeast-2",
"ARN": "arn:aws:ec2:ap-southeast-2:123456789012:network-acl/acl-111222333",
"ID": "acl-111222333",
"Tags": { "environment": "pci" },
"ResourceID": "arn:aws:ec2:ap-southeast-2:123456789012:network-acl/acl-111222333",
"ResourceType": "AWS.EC2.NetworkACL",
"TimeCreated": null,
"Associations":
[
{
"NetworkAclAssociationId": "aclassoc-111222333",
"NetworkAclId": "acl-111222333",
"SubnetId": "subnet-111222333",
},
],
"Entries":
[
{
"CidrBlock": "0.0.0.0/0",
"Egress": false,
"IcmpTypeCode": null,
"Ipv6CidrBlock": null,
"PortRange": { "From": 21, "To": 21 },
"Protocol": "-1",
"RuleAction": "allow",
"RuleNumber": 100,
},
],
"IsDefault": true,
"NetworkAclId": "acl-111222333",
"OwnerId": "123456789012",
"VpcId": "vpc-6aa60b12",
}
- Name: All Ports Allowed
ExpectedResult: false
Resource:
{
"OwnerId": "123456789012",
"Region": "us-west-2",
"Associations":
[
{
"NetworkAclId": "acl-1",
"NetworkAclAssociationId": "aclassoc-1",
"SubnetId": "subnet-1",
},
],
"Id": "acl-1",
"Entries":
[
{
"CidrBlock": "0.0.0.0/0",
"Egress": false,
"RuleNumber": 100,
"Ipv6CidrBlock": null,
"Protocol": "-1",
"PortRange": null,
"IcmpTypeCode": null,
"RuleAction": "allow",
},
{
"RuleNumber": 32767,
"Ipv6CidrBlock": null,
"Protocol": "-1",
"PortRange": null,
"IcmpTypeCode": null,
"RuleAction": "deny",
"CidrBlock": "0.0.0.0/0",
"Egress": false,
},
],
"VpcId": "vpc-1",
"IsDefault": true,
"Tags": { "environment": "pci" },
"AccountId": "123456789012",
"ResourceType": "AWS.EC2.NetworkACL",
"ResourceId": "arn:aws:ec2:us-west-2:123456789012:network-acl/acl-1",
"Arn": "arn:aws:ec2:us-west-2:123456789012:network-acl/acl-1",
"TimeCreated": null,
}
# ------ paired body: aws_network_acl_restricts_insecure_protocols.py ------
# This is a list of default ports for insecure protocols. As AWS Network ACLs and Security Groups
# are not application layer aware, this is the closest approximation that can be made to blocking
# insecure protocols. Application layer firewalls can provide stronger protections.
INSECURE_PORTS = {
21, # FTP command channel
25, # Unencrypted pop3 outgoing
23, # Telnet
80, # HTTP
110, # Unencrypted pop3 incoming
587, # Unencrypted pop3 outgoing
}
def policy(resource):
for entry in resource["Entries"]:
# Look for ingress rules from any IP.
# This could be modified in the future to inspect the size
# of the source network with the ipaddress.ip_network.num_addresses call.
if entry["Egress"]:
continue
# This indicates that all protocols are allowed, and the port range is ignored
if entry["Protocol"] == "-1" or not entry["PortRange"]:
return False
if any(
entry["PortRange"]["From"] <= port <= entry["PortRange"]["To"]
for port in INSECURE_PORTS
):
return False
return True