Repository: cloud-custodian/cloud-custodian

Issue:
update nacls with aws cidrs on changes
- [ ] via subscription to sns per https://aws.amazon.com/blogs/aws/subscribe-to-aws-public-ip-address-changes-via-amazon-sns/
- [ ] pull cidrs from https://ip-ranges.amazonaws.com/ip-ranges.json
- [ ] and then update nacls



Discussion:
i could see someone wanting either update or alert if the nacls prevent access & it shouldnt, or both

is there a way to know which service maps to which CIDR? Or do you want to open to all AWS CIDRs?

@andrey81inmd the json has the service or just base amazon ranges:

ex.

```
{
ip_prefix: "52.46.0.0/18",
region: "GLOBAL",
service: "CLOUDFRONT"
},
```

Is that sufficient?
but yea, i see s3 isnt called out

@jdamick yeah I was looking for s3 specifically... that's the only one that has VPC endpoint right now, so that's the only one you'd need NACLs for, unless your instance can talk directly to internet

there's three blocks of classifications EC2, Amazon, CloudFront, in this context we need to open up Amazon.

@jdamick they can configure the policy's actions to notify and/or update as they prefer in config. 


Resolving patch:
diff --git a/c7n/resources/vpc.py b/c7n/resources/vpc.py
--- a/c7n/resources/vpc.py
+++ b/c7n/resources/vpc.py
@@ -17,6 +17,8 @@
 import operator
 import zlib
 
+import jmespath
+
 from c7n.actions import BaseAction, ModifyVpcSecurityGroupsAction
 from c7n.filters import (
     DefaultVpcBase, Filter, FilterValidationError, ValueFilter)
@@ -24,7 +26,8 @@
 from c7n.filters.revisions import Diff
 from c7n.query import QueryResourceManager
 from c7n.manager import resources
-from c7n.utils import local_session, type_schema, get_retry, camelResource
+from c7n.utils import (
+    local_session, type_schema, get_retry, camelResource, parse_cidr)
 
 
 @resources.register('vpc')
@@ -516,7 +519,7 @@ class Stale(Filter):
     schema = type_schema('stale')
     permissions = ('ec2:DescribeStaleSecurityGroups',)
 
-    def process(self, resources, events):
+    def process(self, resources, event=None):
         client = local_session(self.manager.session_factory).client('ec2')
         vpc_ids = set([r['VpcId'] for r in resources if 'VpcId' in r])
         group_map = {r['GroupId']: r for r in resources}
@@ -1057,10 +1060,81 @@ class resource_type(object):
 
 @NetworkAcl.filter_registry.register('subnet')
 class AclSubnetFilter(net_filters.SubnetFilter):
+    """Filter network acls by the attributes of their attached subnets.
+
+    :example:
+
+        .. code-block: yaml
+
+            policies:
+              - name: subnet-acl
+                resource: network-acl
+                filters:
+                  - type: subnet
+                    key: "tag:Location"
+                    value: Public
+    """
 
     RelatedIdsExpression = "Associations[].SubnetId"
 
 
+@NetworkAcl.filter_registry.register('s3-cidr')
+class AclAwsS3Cidrs(Filter):
+    """Filter network acls by those that allow access to s3 cidrs.
+
+    Defaults to filtering those nacls that do not allow s3 communication.
+
+    :example:
+
+        Find all nacls that do not allow communication with s3.
+
+        .. code-block: yaml
+
+            policies:
+              - name: s3-not-allowed-nacl
+                resource: network-acl
+                filters:
+                  - s3-cidr
+    """
+    # TODO allow for port specification as range
+    schema = type_schema(
+        's3-cidr',
+        egress={'type': 'boolean', 'default': True},
+        ingress={'type': 'boolean', 'default': True},
+        present={'type': 'boolean', 'default': False})
+
+    permissions = ('ec2:DescribePrefixLists',)
+
+    def process(self, resources, event=None):
+        ec2 = local_session(self.manager.session_factory).client('ec2')
+        cidrs = jmespath.search(
+            "PrefixLists[].Cidrs[]", ec2.describe_prefix_lists())
+        cidrs = [parse_cidr(cidr) for cidr in cidrs]
+        results = []
+
+        check_egress = self.data.get('egress', True)
+        check_ingress = self.data.get('ingress', True)
+        present = self.data.get('present', False)
+
+        for r in resources:
+            matched = {cidr: None for cidr in cidrs}
+            for entry in r['Entries']:
+                if entry['Egress'] and not check_egress:
+                    continue
+                if not entry['Egress'] and not check_ingress:
+                    continue
+                entry_cidr = parse_cidr(entry['CidrBlock'])
+                for c in matched:
+                    if c in entry_cidr and matched[c] is None:
+                        matched[c] = (
+                            entry['RuleAction'] == 'allow' and True or False)
+            if present and all(matched.values()):
+                results.append(r)
+            elif not present and not all(matched.values()):
+                results.append(r)
+        return results
+
+
 @resources.register('network-addr')
 class Address(QueryResourceManager):
 
@@ -1156,4 +1230,3 @@ class resource_type(object):
         date = None
         dimension = None
 
-


Test patch:
diff --git a/tests/data/placebo/test_network_acl_s3_missing/ec2.CreateVpc_1.json b/tests/data/placebo/test_network_acl_s3_missing/ec2.CreateVpc_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_network_acl_s3_missing/ec2.CreateVpc_1.json
@@ -0,0 +1,27 @@
+{
+    "status_code": 200, 
+    "data": {
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "6def564c-5422-4fda-adb5-27b0fe806e33", 
+            "HTTPHeaders": {
+                "transfer-encoding": "chunked", 
+                "vary": "Accept-Encoding", 
+                "server": "AmazonEC2", 
+                "content-type": "text/xml;charset=UTF-8", 
+                "date": "Sun, 26 Feb 2017 17:18:07 GMT"
+            }
+        }, 
+        "Vpc": {
+            "VpcId": "vpc-ea9cf38d", 
+            "InstanceTenancy": "default", 
+            "Tags": [], 
+            "Ipv6CidrBlockAssociationSet": [], 
+            "State": "pending", 
+            "DhcpOptionsId": "dopt-78ab4f1c", 
+            "CidrBlock": "10.4.0.0/16", 
+            "IsDefault": false
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_network_acl_s3_missing/ec2.DeleteNetworkAclEntry_1.json b/tests/data/placebo/test_network_acl_s3_missing/ec2.DeleteNetworkAclEntry_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_network_acl_s3_missing/ec2.DeleteNetworkAclEntry_1.json
@@ -0,0 +1,17 @@
+{
+    "status_code": 200, 
+    "data": {
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "ee0d7b3f-6ff3-4868-9f31-a0df65fb0908", 
+            "HTTPHeaders": {
+                "transfer-encoding": "chunked", 
+                "vary": "Accept-Encoding", 
+                "server": "AmazonEC2", 
+                "content-type": "text/xml;charset=UTF-8", 
+                "date": "Sun, 26 Feb 2017 17:18:07 GMT"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_network_acl_s3_missing/ec2.DeleteVpc_1.json b/tests/data/placebo/test_network_acl_s3_missing/ec2.DeleteVpc_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_network_acl_s3_missing/ec2.DeleteVpc_1.json
@@ -0,0 +1,17 @@
+{
+    "status_code": 200, 
+    "data": {
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "54b46ceb-6752-41e5-b0a8-26cdc000532e", 
+            "HTTPHeaders": {
+                "transfer-encoding": "chunked", 
+                "vary": "Accept-Encoding", 
+                "server": "AmazonEC2", 
+                "content-type": "text/xml;charset=UTF-8", 
+                "date": "Sun, 26 Feb 2017 17:18:09 GMT"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_network_acl_s3_missing/ec2.DescribeNetworkAcls_1.json b/tests/data/placebo/test_network_acl_s3_missing/ec2.DescribeNetworkAcls_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_network_acl_s3_missing/ec2.DescribeNetworkAcls_1.json
@@ -0,0 +1,56 @@
+{
+    "status_code": 200, 
+    "data": {
+        "NetworkAcls": [
+            {
+                "Associations": [], 
+                "NetworkAclId": "acl-a0772fc7", 
+                "VpcId": "vpc-ea9cf38d", 
+                "Tags": [], 
+                "Entries": [
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "deny"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "deny"
+                    }
+                ], 
+                "IsDefault": true
+            }
+        ], 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "d4a0331d-1e72-491d-8d6e-421b88639bf1", 
+            "HTTPHeaders": {
+                "transfer-encoding": "chunked", 
+                "vary": "Accept-Encoding", 
+                "server": "AmazonEC2", 
+                "content-type": "text/xml;charset=UTF-8", 
+                "date": "Sun, 26 Feb 2017 17:18:07 GMT"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_network_acl_s3_missing/ec2.DescribeNetworkAcls_2.json b/tests/data/placebo/test_network_acl_s3_missing/ec2.DescribeNetworkAcls_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_network_acl_s3_missing/ec2.DescribeNetworkAcls_2.json
@@ -0,0 +1,132 @@
+{
+    "status_code": 200, 
+    "data": {
+        "NetworkAcls": [
+            {
+                "Associations": [], 
+                "NetworkAclId": "acl-a0772fc7", 
+                "VpcId": "vpc-ea9cf38d", 
+                "Tags": [], 
+                "Entries": [
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "deny"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "deny"
+                    }
+                ], 
+                "IsDefault": true
+            }, 
+            {
+                "Associations": [
+                    {
+                        "SubnetId": "subnet-5fb47507", 
+                        "NetworkAclId": "acl-33266757", 
+                        "NetworkAclAssociationId": "aclassoc-8650e1ff"
+                    }, 
+                    {
+                        "SubnetId": "subnet-63c97615", 
+                        "NetworkAclId": "acl-33266757", 
+                        "NetworkAclAssociationId": "aclassoc-7853e201"
+                    }, 
+                    {
+                        "SubnetId": "subnet-15452171", 
+                        "NetworkAclId": "acl-33266757", 
+                        "NetworkAclAssociationId": "aclassoc-7953e200"
+                    }
+                ], 
+                "NetworkAclId": "acl-33266757", 
+                "VpcId": "vpc-4a9ff72e", 
+                "Tags": [], 
+                "Entries": [
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "deny"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "deny"
+                    }
+                ], 
+                "IsDefault": true
+            }, 
+            {
+                "Associations": [], 
+                "NetworkAclId": "acl-01471966", 
+                "VpcId": "vpc-5ef49939", 
+                "Tags": [], 
+                "Entries": [
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "deny"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "deny"
+                    }
+                ], 
+                "IsDefault": true
+            }
+        ], 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "10366450-c0f8-4073-ba20-00f85d1c22f4", 
+            "HTTPHeaders": {
+                "transfer-encoding": "chunked", 
+                "vary": "Accept-Encoding", 
+                "server": "AmazonEC2", 
+                "content-type": "text/xml;charset=UTF-8", 
+                "date": "Sun, 26 Feb 2017 17:18:08 GMT"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_network_acl_s3_missing/ec2.DescribePrefixLists_1.json b/tests/data/placebo/test_network_acl_s3_missing/ec2.DescribePrefixLists_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_network_acl_s3_missing/ec2.DescribePrefixLists_1.json
@@ -0,0 +1,28 @@
+{
+    "status_code": 200, 
+    "data": {
+        "PrefixLists": [
+            {
+                "PrefixListName": "com.amazonaws.us-west-2.s3", 
+                "Cidrs": [
+                    "54.231.160.0/19", 
+                    "52.218.128.0/17", 
+                    "52.92.32.0/22"
+                ], 
+                "PrefixListId": "pl-68a54001"
+            }
+        ], 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "4a969693-a0fa-4fa8-973c-ca3db1014a08", 
+            "HTTPHeaders": {
+                "transfer-encoding": "chunked", 
+                "vary": "Accept-Encoding", 
+                "server": "AmazonEC2", 
+                "content-type": "text/xml;charset=UTF-8", 
+                "date": "Sun, 26 Feb 2017 17:18:08 GMT"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_network_acl_s3_present/ec2.CreateVpc_1.json b/tests/data/placebo/test_network_acl_s3_present/ec2.CreateVpc_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_network_acl_s3_present/ec2.CreateVpc_1.json
@@ -0,0 +1,27 @@
+{
+    "status_code": 200, 
+    "data": {
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "8c800f8d-5609-4361-82e4-0ff764251716", 
+            "HTTPHeaders": {
+                "transfer-encoding": "chunked", 
+                "vary": "Accept-Encoding", 
+                "server": "AmazonEC2", 
+                "content-type": "text/xml;charset=UTF-8", 
+                "date": "Sun, 26 Feb 2017 17:17:42 GMT"
+            }
+        }, 
+        "Vpc": {
+            "VpcId": "vpc-e69cf381", 
+            "InstanceTenancy": "default", 
+            "Tags": [], 
+            "Ipv6CidrBlockAssociationSet": [], 
+            "State": "pending", 
+            "DhcpOptionsId": "dopt-78ab4f1c", 
+            "CidrBlock": "10.4.0.0/16", 
+            "IsDefault": false
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_network_acl_s3_present/ec2.DeleteVpc_1.json b/tests/data/placebo/test_network_acl_s3_present/ec2.DeleteVpc_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_network_acl_s3_present/ec2.DeleteVpc_1.json
@@ -0,0 +1,17 @@
+{
+    "status_code": 200, 
+    "data": {
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "c91d76c2-1dde-4597-90d1-98bb984afab0", 
+            "HTTPHeaders": {
+                "transfer-encoding": "chunked", 
+                "vary": "Accept-Encoding", 
+                "server": "AmazonEC2", 
+                "content-type": "text/xml;charset=UTF-8", 
+                "date": "Sun, 26 Feb 2017 17:17:44 GMT"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_network_acl_s3_present/ec2.DescribeNetworkAcls_1.json b/tests/data/placebo/test_network_acl_s3_present/ec2.DescribeNetworkAcls_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_network_acl_s3_present/ec2.DescribeNetworkAcls_1.json
@@ -0,0 +1,139 @@
+{
+    "status_code": 200, 
+    "data": {
+        "NetworkAcls": [
+            {
+                "Associations": [], 
+                "NetworkAclId": "acl-de772fb9", 
+                "VpcId": "vpc-e69cf381", 
+                "Tags": [], 
+                "Entries": [
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "deny"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "deny"
+                    }
+                ], 
+                "IsDefault": true
+            }, 
+            {
+                "Associations": [
+                    {
+                        "SubnetId": "subnet-5fb47507", 
+                        "NetworkAclId": "acl-33266757", 
+                        "NetworkAclAssociationId": "aclassoc-8650e1ff"
+                    }, 
+                    {
+                        "SubnetId": "subnet-63c97615", 
+                        "NetworkAclId": "acl-33266757", 
+                        "NetworkAclAssociationId": "aclassoc-7853e201"
+                    }, 
+                    {
+                        "SubnetId": "subnet-15452171", 
+                        "NetworkAclId": "acl-33266757", 
+                        "NetworkAclAssociationId": "aclassoc-7953e200"
+                    }
+                ], 
+                "NetworkAclId": "acl-33266757", 
+                "VpcId": "vpc-4a9ff72e", 
+                "Tags": [], 
+                "Entries": [
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "deny"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "deny"
+                    }
+                ], 
+                "IsDefault": true
+            }, 
+            {
+                "Associations": [], 
+                "NetworkAclId": "acl-01471966", 
+                "VpcId": "vpc-5ef49939", 
+                "Tags": [], 
+                "Entries": [
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": true, 
+                        "RuleAction": "deny"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 100, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "allow"
+                    }, 
+                    {
+                        "CidrBlock": "0.0.0.0/0", 
+                        "RuleNumber": 32767, 
+                        "Protocol": "-1", 
+                        "Egress": false, 
+                        "RuleAction": "deny"
+                    }
+                ], 
+                "IsDefault": true
+            }
+        ], 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "ac8fb334-f8de-4715-92ad-8f4e511ef124", 
+            "HTTPHeaders": {
+                "transfer-encoding": "chunked", 
+                "vary": "Accept-Encoding", 
+                "server": "AmazonEC2", 
+                "content-type": "text/xml;charset=UTF-8", 
+                "date": "Sun, 26 Feb 2017 17:17:43 GMT"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_network_acl_s3_present/ec2.DescribePrefixLists_1.json b/tests/data/placebo/test_network_acl_s3_present/ec2.DescribePrefixLists_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_network_acl_s3_present/ec2.DescribePrefixLists_1.json
@@ -0,0 +1,28 @@
+{
+    "status_code": 200, 
+    "data": {
+        "PrefixLists": [
+            {
+                "PrefixListName": "com.amazonaws.us-west-2.s3", 
+                "Cidrs": [
+                    "54.231.160.0/19", 
+                    "52.218.128.0/17", 
+                    "52.92.32.0/22"
+                ], 
+                "PrefixListId": "pl-68a54001"
+            }
+        ], 
+        "ResponseMetadata": {
+            "RetryAttempts": 0, 
+            "HTTPStatusCode": 200, 
+            "RequestId": "4b0abfec-979f-4330-a17b-d474ea4bc703", 
+            "HTTPHeaders": {
+                "transfer-encoding": "chunked", 
+                "vary": "Accept-Encoding", 
+                "server": "AmazonEC2", 
+                "content-type": "text/xml;charset=UTF-8", 
+                "date": "Sun, 26 Feb 2017 17:17:44 GMT"
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/test_vpc.py b/tests/test_vpc.py
--- a/tests/test_vpc.py
+++ b/tests/test_vpc.py
@@ -66,6 +66,46 @@ def test_flow_logs(self):
         self.assertEqual(len(resources), 1)
 
 
+class NetworkAclTest(BaseTest):
+
+    def test_s3_cidr_network_acl_present(self):
+        factory = self.replay_flight_data('test_network_acl_s3_present')
+        client = factory().client('ec2')
+        vpc_id = client.create_vpc(CidrBlock="10.4.0.0/16")['Vpc']['VpcId']
+        self.addCleanup(client.delete_vpc, VpcId=vpc_id)
+        p = self.load_policy({
+            'name': 'nacl-check',
+            'resource': 'network-acl',
+            'filters': [
+                {'VpcId': vpc_id},
+                {'type': 's3-cidr', 'present': True}]},
+            session_factory=factory)
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+
+    def test_s3_cidr_network_acl_not_present(self):
+        factory = self.replay_flight_data(
+            'test_network_acl_s3_missing')
+        client = factory().client('ec2')
+        vpc_id = client.create_vpc(CidrBlock="10.4.0.0/16")['Vpc']['VpcId']
+        self.addCleanup(client.delete_vpc, VpcId=vpc_id)
+        acls = client.describe_network_acls(
+            Filters=[{'Name': 'vpc-id', 'Values': [vpc_id]}])['NetworkAcls']
+
+        client.delete_network_acl_entry(
+            NetworkAclId=acls[0]['NetworkAclId'],
+            RuleNumber=acls[0]['Entries'][0]['RuleNumber'],
+            Egress=True)
+
+        p = self.load_policy({
+            'name': 'nacl-check',
+            'resource': 'network-acl',
+            'filters': [
+                {'VpcId': vpc_id}, 's3-cidr']},
+            session_factory=factory)
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+
 
 class NetworkInterfaceTest(BaseTest):