Repository: cloud-custodian/cloud-custodian

Issue:
rds-cluster-snapshot
**Is your feature request related to a problem? Please describe.**
No, It's an enhancement

**Describe the solution you'd like**
Need Cross-account filters on AWS RDS Cluster Snapshots.

**Describe alternatives you've considered**
I modified custodian code until it gets fixed.

**Additional context**

from c7n.filters import CrossAccountAccessFilter

@RDSClusterSnapshot.filter_registry.register('cross-account')
class CrossAccountAccess(CrossAccountAccessFilter):

    permissions = ('rds:DescribeDBClusterSnapshotAttributes',)

    def process(self, resources, event=None):
        self.accounts = self.get_accounts()
        results = []
        with self.executor_factory(max_workers=2) as w:
            futures = []
            for resource_set in chunks(resources, 20):
                futures.append(w.submit(
                    self.process_resource_set, resource_set))
            for f in as_completed(futures):
                if f.exception():
                    self.log.error(
                        "Exception checking cross account access\n %s" % (
                            f.exception()))
                    continue
                results.extend(f.result())
        return results

    def process_resource_set(self, resource_set):
        client = local_session(self.manager.session_factory).client('rds')
        results = []
        for r in resource_set:
            attrs = {t['AttributeName']: t['AttributeValues']
             #for t in client.describe_db_cluster_snapshot_attributes(
             for t in self.manager.retry(
                client.describe_db_cluster_snapshot_attributes,
                DBClusterSnapshotIdentifier=r['DBClusterSnapshotIdentifier'])[
                    'DBClusterSnapshotAttributesResult']['DBClusterSnapshotAttributes']}
            r['c7n:attributes'] = attrs
            shared_accounts = set(attrs.get('restore', []))
            delta_accounts = shared_accounts.difference(self.accounts)
            if delta_accounts:
                r['c7n:CrossAccountViolations'] = list(delta_accounts)
                results.append(r)
        return results


Discussion:

Patch:
diff --git a/c7n/resources/asg.py b/c7n/resources/asg.py
index 80ebf7e4e..be7a1a2c3 100644
--- a/c7n/resources/asg.py
+++ b/c7n/resources/asg.py
@@ -121,12 +121,12 @@ class LaunchInfo:
 
         lid = asg.get('LaunchTemplate')
         if lid is not None:
-            return (lid['LaunchTemplateId'], lid['Version'])
+            return (lid['LaunchTemplateId'], lid.get('Version', '$Default'))
 
         if 'MixedInstancesPolicy' in asg:
             mip_spec = asg['MixedInstancesPolicy'][
                 'LaunchTemplate']['LaunchTemplateSpecification']
-            return (mip_spec['LaunchTemplateId'], mip_spec['Version'])
+            return (mip_spec['LaunchTemplateId'], mip_spec.get('Version', '$Default'))
 
         # we've noticed some corner cases where the asg name is the lc name, but not
         # explicitly specified as launchconfiguration attribute.
diff --git a/c7n/resources/cloudfront.py b/c7n/resources/cloudfront.py
index b01157497..823fe4561 100644
--- a/c7n/resources/cloudfront.py
+++ b/c7n/resources/cloudfront.py
@@ -19,6 +19,7 @@ from c7n.manager import resources
 from c7n.query import QueryResourceManager, DescribeSource, TypeInfo
 from c7n.tags import universal_augment
 from c7n.utils import local_session, type_schema, get_retry
+from c7n.filters import ValueFilter
 from .aws import shape_validate
 from c7n.exceptions import PolicyValidationError
 
@@ -149,6 +150,55 @@ class IsWafEnabled(Filter):
         return results
 
 
+@Distribution.filter_registry.register('distribution-config')
+class DistributionConfig(ValueFilter):
+    """Check for Cloudfront distribution config values
+
+    :example:
+
+    .. code-block:: yaml
+
+            policies:
+              - name: logging-enabled
+                resource: distribution
+                filters:
+                  - type: distribution-config
+                    key: Logging.Enabled
+                    value: true
+   """
+
+    schema = type_schema('distribution-config', rinherit=ValueFilter.schema)
+    schema_alias = False
+    permissions = ('cloudfront:GetDistributionConfig',)
+    annotation_key = 'c7n:distribution-config'
+    annotate = False
+
+    def process(self, resources, event=None):
+
+        self.augment([r for r in resources if self.annotation_key not in r])
+        return super().process(resources, event)
+
+    def augment(self, resources):
+
+        client = local_session(self.manager.session_factory).client(
+            'cloudfront', region_name=self.manager.config.region)
+
+        for r in resources:
+            try:
+                r[self.annotation_key] = client.get_distribution_config(Id=r['Id']) \
+                    .get('DistributionConfig')
+            except (client.exceptions.NoSuchDistribution):
+                r[self.annotation_key] = {}
+            except Exception as e:
+                self.log.warning(
+                    "Exception trying to get Distribution Config: %s error: %s",
+                    r['ARN'], e)
+                raise e
+
+    def __call__(self, r):
+        return super(DistributionConfig, self).__call__(r[self.annotation_key])
+
+
 @Distribution.filter_registry.register('mismatch-s3-origin')
 class MismatchS3Origin(Filter):
     """Check for existence of S3 bucket referenced by Cloudfront,
diff --git a/c7n/resources/ec2.py b/c7n/resources/ec2.py
index 623cda485..186adae6f 100644
--- a/c7n/resources/ec2.py
+++ b/c7n/resources/ec2.py
@@ -2112,7 +2112,7 @@ class LaunchTemplate(query.QueryResourceManager):
                 continue
             templates.setdefault(
                 (t['LaunchTemplateId'],
-                 t.get('Version', None)), []).append(a['AutoScalingGroupName'])
+                 t.get('Version', '$Default')), []).append(a['AutoScalingGroupName'])
         return templates
 
 
diff --git a/c7n/resources/rdscluster.py b/c7n/resources/rdscluster.py
index be13f343e..1e12256ce 100644
--- a/c7n/resources/rdscluster.py
+++ b/c7n/resources/rdscluster.py
@@ -16,11 +16,11 @@ import logging
 from concurrent.futures import as_completed
 
 from c7n.actions import BaseAction
-from c7n.filters import AgeFilter
+from c7n.filters import AgeFilter, CrossAccountAccessFilter
 from c7n.filters.offhours import OffHour, OnHour
 import c7n.filters.vpc as net_filters
 from c7n.manager import resources
-from c7n.query import QueryResourceManager, TypeInfo
+from c7n.query import QueryResourceManager, TypeInfo, DescribeSource
 from c7n import tags
 from .aws import shape_validate
 from c7n.exceptions import PolicyValidationError
@@ -342,7 +342,6 @@ class RDSClusterSnapshot(QueryResourceManager):
     """
 
     class resource_type(TypeInfo):
-
         service = 'rds'
         arn_type = 'cluster-snapshot'
         arn_separator = ':'
@@ -352,9 +351,62 @@ class RDSClusterSnapshot(QueryResourceManager):
         name = id = 'DBClusterSnapshotIdentifier'
         date = 'SnapshotCreateTime'
         universal_tagging = object()
+        config_type = 'AWS::RDS::DBClusterSnapshot'
         permissions_enum = ('rds:DescribeDBClusterSnapshots',)
 
-    augment = tags.universal_augment
+    def get_source(self, source_type):
+        if source_type == 'describe':
+            return DescribeClusterSnapshot(self)
+        return super().get_source(source_type)
+
+
+class DescribeClusterSnapshot(DescribeSource):
+
+    def get_resources(self, resource_ids, cache=True):
+        client = local_session(self.manager.session_factory).client('rds')
+        return self.manager.retry(
+            client.describe_db_cluster_snapshots,
+            Filters=[{
+                'Name': 'db-cluster-snapshot-id',
+                'Values': resource_ids}]).get('DBClusterSnapshots', ())
+
+    def augment(self, resources):
+        return tags.universal_augment(self.manager, resources)
+
+
+@RDSClusterSnapshot.filter_registry.register('cross-account')
+class CrossAccountSnapshot(CrossAccountAccessFilter):
+
+    permissions = ('rds:DescribeDBClusterSnapshotAttributes',)
+
+    def process(self, resources, event=None):
+        self.accounts = self.get_accounts()
+        results = []
+        with self.executor_factory(max_workers=2) as w:
+            futures = []
+            for resource_set in chunks(resources, 20):
+                futures.append(w.submit(
+                    self.process_resource_set, resource_set))
+            for f in as_completed(futures):
+                results.extend(f.result())
+        return results
+
+    def process_resource_set(self, resource_set):
+        client = local_session(self.manager.session_factory).client('rds')
+        results = []
+        for r in resource_set:
+            attrs = {t['AttributeName']: t['AttributeValues']
+             for t in self.manager.retry(
+                client.describe_db_cluster_snapshot_attributes,
+                     DBClusterSnapshotIdentifier=r['DBClusterSnapshotIdentifier'])[
+                         'DBClusterSnapshotAttributesResult']['DBClusterSnapshotAttributes']}
+            r['c7n:attributes'] = attrs
+            shared_accounts = set(attrs.get('restore', []))
+            delta_accounts = shared_accounts.difference(self.accounts)
+            if delta_accounts:
+                r['c7n:CrossAccountViolations'] = list(delta_accounts)
+                results.append(r)
+        return results
 
 
 @RDSClusterSnapshot.filter_registry.register('age')
diff --git a/c7n/resources/vpc.py b/c7n/resources/vpc.py
index e2a9cc27c..71dcc564e 100644
--- a/c7n/resources/vpc.py
+++ b/c7n/resources/vpc.py
@@ -2200,7 +2200,7 @@ class CreateFlowLogs(BaseAction):
                 DeliverLogsPermissionArn: arn:iam:role
                 LogGroupName: /custodian/vpc/flowlogs/
     """
-    permissions = ('ec2:CreateFlowLogs',)
+    permissions = ('ec2:CreateFlowLogs', 'logs:CreateLogGroup',)
     schema = {
         'type': 'object',
         'additionalProperties': False,
@@ -2297,7 +2297,8 @@ class CreateFlowLogs(BaseAction):
         params['ResourceType'] = self.RESOURCE_ALIAS[model.arn_type]
         params['TrafficType'] = self.data.get('TrafficType', 'ALL').upper()
         params['MaxAggregationInterval'] = self.data.get('MaxAggregationInterval', 600)
-
+        if self.data.get('LogDestinationType', 'cloud-watch-logs') == 'cloud-watch-logs':
+            self.process_log_group(self.data.get('LogGroupName'))
         try:
             results = client.create_flow_logs(**params)
 
@@ -2312,3 +2313,10 @@ class CreateFlowLogs(BaseAction):
                     e.response['Error']['Message'])
             else:
                 raise
+
+    def process_log_group(self, logroup):
+        client = local_session(self.manager.session_factory).client('logs')
+        try:
+            client.create_log_group(logGroupName=logroup)
+        except client.exceptions.ResourceAlreadyExistsException:
+            pass


Test patch:
diff --git a/tests/data/placebo/test_distribution_check_logging_enabled/cloudfront.GetDistributionConfig_1.json b/tests/data/placebo/test_distribution_check_logging_enabled/cloudfront.GetDistributionConfig_1.json
new file mode 100644
index 000000000..f1a67cb62
--- /dev/null
+++ b/tests/data/placebo/test_distribution_check_logging_enabled/cloudfront.GetDistributionConfig_1.json
@@ -0,0 +1,17 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {},
+        "ETag": "E2V8K6F94HTIC5",
+        "DistributionConfig": {
+            "Comment": "",
+            "Enabled": true,
+            "Logging": {
+                "Enabled": true,
+                "IncludeCookies": true,
+                "Bucket": "test.s3.amazonaws.com",
+                "Prefix": ""
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_distribution_check_logging_enabled/cloudfront.ListDistributions_1.json b/tests/data/placebo/test_distribution_check_logging_enabled/cloudfront.ListDistributions_1.json
new file mode 100644
index 000000000..0ea654760
--- /dev/null
+++ b/tests/data/placebo/test_distribution_check_logging_enabled/cloudfront.ListDistributions_1.json
@@ -0,0 +1,20 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {},
+        "DistributionList": {
+            "Marker": "",
+            "MaxItems": 100,
+            "IsTruncated": false,
+            "Quantity": 1,
+            "Items": [
+                {
+                    "Id": "E1FBPN9VF9FG4X",
+                    "ARN": "arn:aws:cloudfront::123456789012:distribution/E1FBPN9VF9FG4X",
+                    "Status": "InProgress",
+                    "Comment": ""
+                }
+            ]
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_distribution_check_logging_enabled/tagging.GetResources_1.json b/tests/data/placebo/test_distribution_check_logging_enabled/tagging.GetResources_1.json
new file mode 100644
index 000000000..8b704d185
--- /dev/null
+++ b/tests/data/placebo/test_distribution_check_logging_enabled/tagging.GetResources_1.json
@@ -0,0 +1,8 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_rds_cluster_snapshot_cross_account/rds.DescribeDBClusterSnapshotAttributes_1.json b/tests/data/placebo/test_rds_cluster_snapshot_cross_account/rds.DescribeDBClusterSnapshotAttributes_1.json
new file mode 100644
index 000000000..e78337351
--- /dev/null
+++ b/tests/data/placebo/test_rds_cluster_snapshot_cross_account/rds.DescribeDBClusterSnapshotAttributes_1.json
@@ -0,0 +1,17 @@
+{
+    "status_code": 200,
+    "data": {
+        "DBClusterSnapshotAttributesResult": {
+            "DBClusterSnapshotIdentifier": "test-cluster-final-snapshot",
+            "DBClusterSnapshotAttributes": [
+                {
+                    "AttributeName": "restore",
+                    "AttributeValues": [
+                        "12345678910"
+                    ]
+                }
+            ]
+        },
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_rds_cluster_snapshot_cross_account/rds.DescribeDBClusterSnapshots_1.json b/tests/data/placebo/test_rds_cluster_snapshot_cross_account/rds.DescribeDBClusterSnapshots_1.json
new file mode 100644
index 000000000..528306d2d
--- /dev/null
+++ b/tests/data/placebo/test_rds_cluster_snapshot_cross_account/rds.DescribeDBClusterSnapshots_1.json
@@ -0,0 +1,54 @@
+{
+    "status_code": 200,
+    "data": {
+        "DBClusterSnapshots": [
+            {
+                "AvailabilityZones": [
+                    "us-east-1a",
+                    "us-east-1b",
+                    "us-east-1c",
+                    "us-east-1d",
+                    "us-east-1e",
+                    "us-east-1f"
+                ],
+                "DBClusterSnapshotIdentifier": "test-cluster-final-snapshot",
+                "DBClusterIdentifier": "test-cluster",
+                "SnapshotCreateTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 2,
+                    "day": 19,
+                    "hour": 15,
+                    "minute": 37,
+                    "second": 8,
+                    "microsecond": 707000
+                },
+                "Engine": "docdb",
+                "AllocatedStorage": 0,
+                "Status": "available",
+                "Port": 0,
+                "VpcId": "vpc-d2d616b5",
+                "ClusterCreateTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 1,
+                    "day": 15,
+                    "hour": 19,
+                    "minute": 18,
+                    "second": 24,
+                    "microsecond": 830000
+                },
+                "MasterUsername": "admintest",
+                "EngineVersion": "3.6.0",
+                "LicenseModel": "docdb",
+                "SnapshotType": "manual",
+                "PercentProgress": 100,
+                "StorageEncrypted": true,
+                "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/b10f842a-feb7-4318-92d5-0640a75b7688",
+                "DBClusterSnapshotArn": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:test-cluster-final-snapshot",
+                "IAMDatabaseAuthenticationEnabled": false
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_rds_cluster_snapshot_cross_account/tagging.GetResources_1.json b/tests/data/placebo/test_rds_cluster_snapshot_cross_account/tagging.GetResources_1.json
new file mode 100644
index 000000000..41baa5bbe
--- /dev/null
+++ b/tests/data/placebo/test_rds_cluster_snapshot_cross_account/tagging.GetResources_1.json
@@ -0,0 +1,9 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [
+        ],
+        "ResponseMetadata": {}
+    }
+}
diff --git a/tests/data/placebo/test_rds_cluster_snapshot_get_resources/rds.DescribeDBClusterSnapshots_1.json b/tests/data/placebo/test_rds_cluster_snapshot_get_resources/rds.DescribeDBClusterSnapshots_1.json
new file mode 100644
index 000000000..59da79bbe
--- /dev/null
+++ b/tests/data/placebo/test_rds_cluster_snapshot_get_resources/rds.DescribeDBClusterSnapshots_1.json
@@ -0,0 +1,97 @@
+{
+    "status_code": 200,
+    "data": {
+        "DBClusterSnapshots": [
+            {
+                "AvailabilityZones": [
+                    "us-east-1a",
+                    "us-east-1b",
+                    "us-east-1d"
+                ],
+                "DBClusterSnapshotIdentifier": "rds:database-1-2020-04-27-05-58",
+                "DBClusterIdentifier": "database-1",
+                "SnapshotCreateTime": {
+                    "__class__": "datetime",
+                    "year": 2020,
+                    "month": 4,
+                    "day": 27,
+                    "hour": 5,
+                    "minute": 58,
+                    "second": 55,
+                    "microsecond": 964000
+                },
+                "Engine": "aurora-postgresql",
+                "AllocatedStorage": 0,
+                "Status": "available",
+                "Port": 0,
+                "VpcId": "vpc-d2d616b5",
+                "ClusterCreateTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 10,
+                    "day": 20,
+                    "hour": 10,
+                    "minute": 53,
+                    "second": 28,
+                    "microsecond": 740000
+                },
+                "MasterUsername": "postgres",
+                "EngineVersion": "10.serverless_7",
+                "LicenseModel": "postgresql-license",
+                "SnapshotType": "automated",
+                "PercentProgress": 100,
+                "StorageEncrypted": true,
+                "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/b10f842a-feb7-4318-92d5-0640a75b7688",
+                "DBClusterSnapshotArn": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:rds:database-1-2020-04-27-05-58",
+                "IAMDatabaseAuthenticationEnabled": false
+            },
+            {
+                "AvailabilityZones": [
+                    "us-east-1a",
+                    "us-east-1b",
+                    "us-east-1c",
+                    "us-east-1d",
+                    "us-east-1e",
+                    "us-east-1f"
+                ],
+                "DBClusterSnapshotIdentifier": "test-cluster-final-snapshot",
+                "DBClusterIdentifier": "test-cluster",
+                "SnapshotCreateTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 2,
+                    "day": 19,
+                    "hour": 15,
+                    "minute": 37,
+                    "second": 8,
+                    "microsecond": 707000
+                },
+                "Engine": "docdb",
+                "AllocatedStorage": 0,
+                "Status": "available",
+                "Port": 0,
+                "VpcId": "vpc-d2d616b5",
+                "ClusterCreateTime": {
+                    "__class__": "datetime",
+                    "year": 2019,
+                    "month": 1,
+                    "day": 15,
+                    "hour": 19,
+                    "minute": 18,
+                    "second": 24,
+                    "microsecond": 830000
+                },
+                "MasterUsername": "admintest",
+                "EngineVersion": "3.6.0",
+                "LicenseModel": "docdb",
+                "SnapshotType": "manual",
+                "PercentProgress": 100,
+                "StorageEncrypted": true,
+                "KmsKeyId": "arn:aws:kms:us-east-1:644160558196:key/b10f842a-feb7-4318-92d5-0640a75b7688",
+                "DBClusterSnapshotArn": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:test-cluster-final-snapshot",
+                "IAMDatabaseAuthenticationEnabled": false
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_rds_cluster_snapshot_get_resources/tagging.GetResources_1.json b/tests/data/placebo/test_rds_cluster_snapshot_get_resources/tagging.GetResources_1.json
new file mode 100644
index 000000000..cbaa7d79e
--- /dev/null
+++ b/tests/data/placebo/test_rds_cluster_snapshot_get_resources/tagging.GetResources_1.json
@@ -0,0 +1,81 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [
+            {
+                "ResourceARN": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:rds:database-1-2020-04-21-05-58",
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "kapil"
+                    }
+                ]
+            },
+            {
+                "ResourceARN": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:rds:database-1-2020-04-23-05-59",
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "kapil"
+                    }
+                ]
+            },
+            {
+                "ResourceARN": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:rds:database-1-2020-04-22-05-58",
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "kapil"
+                    }
+                ]
+            },
+            {
+                "ResourceARN": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:rds:database-1-2020-04-27-05-58",
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "kapil"
+                    }
+                ]
+            },
+            {
+                "ResourceARN": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:rds:database-1-2020-04-26-05-58",
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "kapil"
+                    }
+                ]
+            },
+            {
+                "ResourceARN": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:verify",
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "kapil"
+                    }
+                ]
+            },
+            {
+                "ResourceARN": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:rds:database-1-2020-04-25-05-58",
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "kapil"
+                    }
+                ]
+            },
+            {
+                "ResourceARN": "arn:aws:rds:us-east-1:644160558196:cluster-snapshot:rds:database-1-2020-04-24-05-58",
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "kapil"
+                    }
+                ]
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_vpc_create_flow_logs/ec2.CreateFlowLogs_1.json b/tests/data/placebo/test_vpc_create_flow_logs/ec2.CreateFlowLogs_1.json
index 36eebc958..df7ff1126 100644
--- a/tests/data/placebo/test_vpc_create_flow_logs/ec2.CreateFlowLogs_1.json
+++ b/tests/data/placebo/test_vpc_create_flow_logs/ec2.CreateFlowLogs_1.json
@@ -1,22 +1,11 @@
 {
-    "status_code": 200, 
+    "status_code": 200,
     "data": {
-        "Unsuccessful": [], 
-        "ResponseMetadata": {
-            "RetryAttempts": 0, 
-            "HTTPStatusCode": 200, 
-            "RequestId": "f1bbb838-5fed-41bc-832f-9ec5b65cc34f", 
-            "HTTPHeaders": {
-                "transfer-encoding": "chunked", 
-                "vary": "Accept-Encoding", 
-                "server": "AmazonEC2", 
-                "content-type": "text/xml;charset=UTF-8", 
-                "date": "Fri, 06 Apr 2018 16:51:45 GMT"
-            }
-        }, 
+        "ClientToken": "6zPNON5jQ9rEuL4pDVwzJlm70HqAQcYDkaOEHQr9gos=",
         "FlowLogIds": [
-            "fl-f076b299"
-        ], 
-        "ClientToken": "zc3APQuNTpR/2VUebosuWy3DOrWJhkyq7pcWIVGeKkc="
+            "fl-041cdc74dc6435446"
+        ],
+        "Unsuccessful": [],
+        "ResponseMetadata": {}
     }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_vpc_create_flow_logs/ec2.CreateFlowLogs_2.json b/tests/data/placebo/test_vpc_create_flow_logs/ec2.CreateFlowLogs_2.json
new file mode 100644
index 000000000..9165c511d
--- /dev/null
+++ b/tests/data/placebo/test_vpc_create_flow_logs/ec2.CreateFlowLogs_2.json
@@ -0,0 +1,11 @@
+{
+    "status_code": 200,
+    "data": {
+        "ClientToken": "JuutuXS0nHXAfsQ1lOWaMAL6+tpqT5mqHMnEGPdD90I=",
+        "FlowLogIds": [
+            "fl-0c28f7d7b5cd29477"
+        ],
+        "Unsuccessful": [],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_1.json b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_1.json
index be05be388..eeb65125b 100644
--- a/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_1.json
+++ b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_1.json
@@ -1,18 +1,7 @@
 {
-    "status_code": 200, 
+    "status_code": 200,
     "data": {
-        "FlowLogs": [], 
-        "ResponseMetadata": {
-            "RetryAttempts": 0, 
-            "HTTPStatusCode": 200, 
-            "RequestId": "a0cd7ea9-229e-4d62-9ab9-fbb6793c95e6", 
-            "HTTPHeaders": {
-                "transfer-encoding": "chunked", 
-                "vary": "Accept-Encoding", 
-                "server": "AmazonEC2", 
-                "content-type": "text/xml;charset=UTF-8", 
-                "date": "Fri, 06 Apr 2018 16:51:44 GMT"
-            }
-        }
+        "FlowLogs": [],
+        "ResponseMetadata": {}
     }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_2.json b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_2.json
index cc37c1a43..3eea8c26a 100644
--- a/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_2.json
+++ b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_2.json
@@ -1,37 +1,31 @@
 {
-    "status_code": 200, 
+    "status_code": 200,
     "data": {
         "FlowLogs": [
             {
-                "ResourceId": "vpc-7af45101", 
                 "CreationTime": {
-                    "hour": 16, 
-                    "__class__": "datetime", 
-                    "month": 4, 
-                    "second": 46, 
-                    "microsecond": 20000, 
-                    "year": 2018, 
-                    "day": 6, 
-                    "minute": 51
-                }, 
-                "LogGroupName": "/custodian/vpc_logs/", 
-                "TrafficType": "ALL", 
-                "FlowLogStatus": "ACTIVE", 
-                "FlowLogId": "fl-f076b299", 
-                "DeliverLogsPermissionArn": "arn:aws:iam::644160558196:role/flowlogsRole"
+                    "__class__": "datetime",
+                    "year": 2020,
+                    "month": 4,
+                    "day": 27,
+                    "hour": 4,
+                    "minute": 33,
+                    "second": 16,
+                    "microsecond": 30000
+                },
+                "DeliverLogsPermissionArn": "arn:aws:iam::644160558196:role/flowlogsRole",
+                "DeliverLogsStatus": "SUCCESS",
+                "FlowLogId": "fl-041cdc74dc6435446",
+                "FlowLogStatus": "ACTIVE",
+                "LogGroupName": "/custodian/vpc_log/",
+                "ResourceId": "vpc-d2d616b5",
+                "TrafficType": "ALL",
+                "LogDestinationType": "cloud-watch-logs",
+                "LogFormat": "${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status}",
+                "Tags": [],
+                "MaxAggregationInterval": 600
             }
-        ], 
-        "ResponseMetadata": {
-            "RetryAttempts": 0, 
-            "HTTPStatusCode": 200, 
-            "RequestId": "844aacb9-04d2-42de-b5db-9cb92b5f2793", 
-            "HTTPHeaders": {
-                "transfer-encoding": "chunked", 
-                "vary": "Accept-Encoding", 
-                "server": "AmazonEC2", 
-                "content-type": "text/xml;charset=UTF-8", 
-                "date": "Fri, 06 Apr 2018 16:51:46 GMT"
-            }
-        }
+        ],
+        "ResponseMetadata": {}
     }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_3.json b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_3.json
new file mode 100644
index 000000000..3eea8c26a
--- /dev/null
+++ b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_3.json
@@ -0,0 +1,31 @@
+{
+    "status_code": 200,
+    "data": {
+        "FlowLogs": [
+            {
+                "CreationTime": {
+                    "__class__": "datetime",
+                    "year": 2020,
+                    "month": 4,
+                    "day": 27,
+                    "hour": 4,
+                    "minute": 33,
+                    "second": 16,
+                    "microsecond": 30000
+                },
+                "DeliverLogsPermissionArn": "arn:aws:iam::644160558196:role/flowlogsRole",
+                "DeliverLogsStatus": "SUCCESS",
+                "FlowLogId": "fl-041cdc74dc6435446",
+                "FlowLogStatus": "ACTIVE",
+                "LogGroupName": "/custodian/vpc_log/",
+                "ResourceId": "vpc-d2d616b5",
+                "TrafficType": "ALL",
+                "LogDestinationType": "cloud-watch-logs",
+                "LogFormat": "${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status}",
+                "Tags": [],
+                "MaxAggregationInterval": 600
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_4.json b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_4.json
new file mode 100644
index 000000000..f30a03afc
--- /dev/null
+++ b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeFlowLogs_4.json
@@ -0,0 +1,31 @@
+{
+    "status_code": 200,
+    "data": {
+        "FlowLogs": [
+            {
+                "CreationTime": {
+                    "__class__": "datetime",
+                    "year": 2020,
+                    "month": 4,
+                    "day": 27,
+                    "hour": 4,
+                    "minute": 33,
+                    "second": 17,
+                    "microsecond": 121000
+                },
+                "DeliverLogsPermissionArn": "arn:aws:iam::644160558196:role/flowlogsRole",
+                "DeliverLogsStatus": "SUCCESS",
+                "FlowLogId": "fl-0c28f7d7b5cd29477",
+                "FlowLogStatus": "ACTIVE",
+                "LogGroupName": "/custodian/vpc_log/",
+                "ResourceId": "vpc-03005fb9b8740263d",
+                "TrafficType": "ALL",
+                "LogDestinationType": "cloud-watch-logs",
+                "LogFormat": "${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status}",
+                "Tags": [],
+                "MaxAggregationInterval": 600
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeVpcs_1.json b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeVpcs_1.json
index 68d186edb..ea32baa71 100644
--- a/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeVpcs_1.json
+++ b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeVpcs_1.json
@@ -1,42 +1,60 @@
 {
-    "status_code": 200, 
+    "status_code": 200,
     "data": {
         "Vpcs": [
             {
-                "VpcId": "vpc-7af45101", 
-                "InstanceTenancy": "default", 
+                "CidrBlock": "10.205.0.0/18",
+                "DhcpOptionsId": "dopt-24ff1940",
+                "State": "available",
+                "VpcId": "vpc-03005fb9b8740263d",
+                "OwnerId": "644160558196",
+                "InstanceTenancy": "default",
+                "CidrBlockAssociationSet": [
+                    {
+                        "AssociationId": "vpc-cidr-assoc-0f6765530d80dc044",
+                        "CidrBlock": "10.205.0.0/18",
+                        "CidrBlockState": {
+                            "State": "associated"
+                        }
+                    }
+                ],
+                "IsDefault": false,
                 "Tags": [
                     {
-                        "Value": "FlowLogTest", 
-                        "Key": "Name"
+                        "Key": "Owner",
+                        "Value": "c7n"
+                    },
+                    {
+                        "Key": "Name",
+                        "Value": "testing-vpc"
                     }
-                ], 
+                ]
+            },
+            {
+                "CidrBlock": "172.31.0.0/16",
+                "DhcpOptionsId": "dopt-24ff1940",
+                "State": "available",
+                "VpcId": "vpc-d2d616b5",
+                "OwnerId": "644160558196",
+                "InstanceTenancy": "default",
                 "CidrBlockAssociationSet": [
                     {
-                        "AssociationId": "vpc-cidr-assoc-7c1eb811", 
-                        "CidrBlock": "10.0.16.0/24", 
+                        "AssociationId": "vpc-cidr-assoc-33669f5a",
+                        "CidrBlock": "172.31.0.0/16",
                         "CidrBlockState": {
                             "State": "associated"
                         }
                     }
-                ], 
-                "State": "available", 
-                "DhcpOptionsId": "dopt-4d4c3035", 
-                "CidrBlock": "10.0.16.0/24", 
-                "IsDefault": false
-            }
-        ], 
-        "ResponseMetadata": {
-            "RetryAttempts": 0, 
-            "HTTPStatusCode": 200, 
-            "RequestId": "e667839a-e438-453c-877a-4c75c0c26add", 
-            "HTTPHeaders": {
-                "transfer-encoding": "chunked", 
-                "vary": "Accept-Encoding", 
-                "server": "AmazonEC2", 
-                "content-type": "text/xml;charset=UTF-8", 
-                "date": "Fri, 06 Apr 2018 16:51:44 GMT"
+                ],
+                "IsDefault": true,
+                "Tags": [
+                    {
+                        "Key": "Name",
+                        "Value": "FlowLogTest"
+                    }
+                ]
             }
-        }
+        ],
+        "ResponseMetadata": {}
     }
 }
\ No newline at end of file
diff --git a/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeVpcs_2.json b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeVpcs_2.json
new file mode 100644
index 000000000..ea32baa71
--- /dev/null
+++ b/tests/data/placebo/test_vpc_create_flow_logs/ec2.DescribeVpcs_2.json
@@ -0,0 +1,60 @@
+{
+    "status_code": 200,
+    "data": {
+        "Vpcs": [
+            {
+                "CidrBlock": "10.205.0.0/18",
+                "DhcpOptionsId": "dopt-24ff1940",
+                "State": "available",
+                "VpcId": "vpc-03005fb9b8740263d",
+                "OwnerId": "644160558196",
+                "InstanceTenancy": "default",
+                "CidrBlockAssociationSet": [
+                    {
+                        "AssociationId": "vpc-cidr-assoc-0f6765530d80dc044",
+                        "CidrBlock": "10.205.0.0/18",
+                        "CidrBlockState": {
+                            "State": "associated"
+                        }
+                    }
+                ],
+                "IsDefault": false,
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "c7n"
+                    },
+                    {
+                        "Key": "Name",
+                        "Value": "testing-vpc"
+                    }
+                ]
+            },
+            {
+                "CidrBlock": "172.31.0.0/16",
+                "DhcpOptionsId": "dopt-24ff1940",
+                "State": "available",
+                "VpcId": "vpc-d2d616b5",
+                "OwnerId": "644160558196",
+                "InstanceTenancy": "default",
+                "CidrBlockAssociationSet": [
+                    {
+                        "AssociationId": "vpc-cidr-assoc-33669f5a",
+                        "CidrBlock": "172.31.0.0/16",
+                        "CidrBlockState": {
+                            "State": "associated"
+                        }
+                    }
+                ],
+                "IsDefault": true,
+                "Tags": [
+                    {
+                        "Key": "Name",
+                        "Value": "FlowLogTest"
+                    }
+                ]
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_vpc_create_flow_logs/logs.CreateLogGroup_1.json b/tests/data/placebo/test_vpc_create_flow_logs/logs.CreateLogGroup_1.json
new file mode 100644
index 000000000..5b2170a07
--- /dev/null
+++ b/tests/data/placebo/test_vpc_create_flow_logs/logs.CreateLogGroup_1.json
@@ -0,0 +1,6 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_vpc_create_flow_logs/logs.CreateLogGroup_2.json b/tests/data/placebo/test_vpc_create_flow_logs/logs.CreateLogGroup_2.json
new file mode 100644
index 000000000..a3f39d880
--- /dev/null
+++ b/tests/data/placebo/test_vpc_create_flow_logs/logs.CreateLogGroup_2.json
@@ -0,0 +1,10 @@
+{
+    "status_code": 400,
+    "data": {
+        "Error": {
+            "Message": "The specified log group already exists",
+            "Code": "ResourceAlreadyExistsException"
+        },
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/test_cloudfront.py b/tests/test_cloudfront.py
index 7af5039fa..ac91dcffd 100644
--- a/tests/test_cloudfront.py
+++ b/tests/test_cloudfront.py
@@ -14,6 +14,7 @@
 import jmespath
 from .common import BaseTest
 from c7n.utils import local_session
+from unittest.mock import MagicMock
 
 
 class CloudFrontWaf(BaseTest):
@@ -217,6 +218,65 @@ class CloudFront(BaseTest):
         self.assertEqual(len(resources), 1)
         self.assertEqual(resources[0]['c7n:mismatched-s3-origin'][0], 'c7n-idontexist')
 
+    def test_distribution_check_logging_enabled(self):
+        factory = self.replay_flight_data("test_distribution_check_logging_enabled")
+
+        p = self.load_policy(
+            {
+                "name": "test_distribution_logging_enabled",
+                "resource": "distribution",
+                "filters": [
+                    {
+                        "type": "distribution-config",
+                        "key": "Logging.Enabled",
+                        "value": True
+                    }
+                ]
+            },
+            session_factory=factory,
+        )
+
+        resources = p.run()
+
+        self.assertEqual(len(resources), 1)
+        self.assertEqual(resources[0]['c7n:distribution-config']['Logging']['Enabled'], True)
+
+    def test_distribution_check_logging_enabled_error(self):
+        factory = self.replay_flight_data("test_distribution_check_logging_enabled")
+
+        client = factory().client("cloudfront")
+        mock_factory = MagicMock()
+        mock_factory.region = 'us-east-1'
+        mock_factory().client(
+            'cloudfront').exceptions.NoSuchDistribution = (
+                client.exceptions.NoSuchDistribution)
+
+        mock_factory().client('cloudfront').get_distribution_config.side_effect = (
+            client.exceptions.NoSuchDistribution(
+                {'Error': {'Code': 'xyz'}},
+                operation_name='get_distribution_config'))
+        p = self.load_policy(
+            {
+                "name": "test_distribution_logging_enabled",
+                "resource": "distribution",
+                "filters": [
+                    {
+                        "type": "distribution-config",
+                        "key": "Logging.Enabled",
+                        "value": True
+                    }
+                ]
+            },
+            session_factory=mock_factory,
+        )
+
+        try:
+            p.resource_manager.filters[0].process(
+                [{'Id': 'abc'}])
+        except client.exceptions.NoSuchDistribution:
+            self.fail('should not raise')
+        mock_factory().client('cloudfront').get_distribution_config.assert_called_once()
+
     def test_distribution_tag(self):
         factory = self.replay_flight_data("test_distrbution_tag")
 
diff --git a/tests/test_rdscluster.py b/tests/test_rdscluster.py
index 9ee261881..e2682b96e 100644
--- a/tests/test_rdscluster.py
+++ b/tests/test_rdscluster.py
@@ -380,6 +380,41 @@ class RDSClusterSnapshotTest(BaseTest):
         resources = p.run()
         self.assertEqual(len(resources), 2)
 
+    def test_rdscluster_snapshot_get_resources(self):
+        session_factory = self.replay_flight_data('test_rds_cluster_snapshot_get_resources')
+        p = self.load_policy(
+            {
+                'name': 'rdscluster-get',
+                'resource': 'aws.rds-cluster-snapshot'
+            },
+            session_factory=session_factory)
+        resources = p.resource_manager.get_resources([
+            'test-cluster-final-snapshot',
+            'invalid',
+            'rds:database-1-2020-04-27-05-58'])
+        self.assertEqual(len(resources), 2)
+        self.assertEqual(
+            {'rds:database-1-2020-04-27-05-58', 'test-cluster-final-snapshot'},
+            {r['DBClusterSnapshotIdentifier'] for r in resources})
+        self.assertEqual(
+            {len(r['Tags']) for r in resources},
+            {1, 0})
+
+    def test_rdscluster_snapshot_cross_account(self):
+        session_factory = self.replay_flight_data('test_rds_cluster_snapshot_cross_account')
+        p = self.load_policy(
+            {
+                'name': 'rdscluster-snapshot-xaccount',
+                'resource': 'aws.rds-cluster-snapshot',
+                'filters': [
+                    {'type': 'cross-account'}]
+            },
+            session_factory=session_factory)
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+        self.assertEqual(resources[0]['DBClusterSnapshotIdentifier'], 'test-cluster-final-snapshot')
+        self.assertEqual(resources[0]['c7n:CrossAccountViolations'], ['12345678910'])
+
     def test_rdscluster_snapshot_simple_filter(self):
         session_factory = self.replay_flight_data("test_rdscluster_snapshot_simple")
         p = self.load_policy(
diff --git a/tests/test_vpc.py b/tests/test_vpc.py
index e6646f0de..c7936f7ef 100644
--- a/tests/test_vpc.py
+++ b/tests/test_vpc.py
@@ -2725,6 +2725,7 @@ class FlowLogsTest(BaseTest):
 
     def test_vpc_create_flow_logs(self):
         session_factory = self.replay_flight_data("test_vpc_create_flow_logs")
+        # creates log group
         p = self.load_policy(
             {
                 "name": "c7n-create-vpc-flow-logs",
@@ -2737,7 +2738,7 @@ class FlowLogsTest(BaseTest):
                     {
                         "type": "set-flow-log",
                         "DeliverLogsPermissionArn": "arn:aws:iam::644160558196:role/flowlogsRole",
-                        "LogGroupName": "/custodian/vpc_logs/",
+                        "LogGroupName": "/custodian/vpc_log/",
                         "TrafficType": "ALL",
                     }
                 ],
@@ -2746,14 +2747,40 @@ class FlowLogsTest(BaseTest):
         )
         resources = p.run()
         self.assertEqual(len(resources), 1)
-        self.assertEqual(resources[0]["VpcId"], "vpc-7af45101")
+        self.assertEqual(resources[0]["VpcId"], "vpc-d2d616b5")
         client = session_factory(region="us-east-1").client("ec2")
         logs = client.describe_flow_logs(
             Filters=[{"Name": "resource-id", "Values": [resources[0]["VpcId"]]}]
-        )[
-            "FlowLogs"
-        ]
+        )["FlowLogs"]
         self.assertEqual(logs[0]["ResourceId"], resources[0]["VpcId"])
+        # p1 has same log group name
+        p1 = self.load_policy(
+            {
+                "name": "c7n-create-vpc-flow-logs",
+                "resource": "vpc",
+                "filters": [
+                    {"tag:Name": "testing-vpc"},
+                    {"type": "flow-logs", "enabled": False}
+                ],
+                "actions": [
+                    {
+                        "type": "set-flow-log",
+                        "DeliverLogsPermissionArn": "arn:aws:iam::644160558196:role/flowlogsRole",
+                        "LogGroupName": "/custodian/vpc_log/",
+                        "TrafficType": "ALL",
+                    }
+                ],
+            },
+            session_factory=session_factory,
+        )
+        res = p1.run()
+        self.assertEqual(len(res), 1)
+        self.assertEqual(res[0]["VpcId"], "vpc-03005fb9b8740263d")
+        client = session_factory(region="us-east-1").client("ec2")
+        lgs = client.describe_flow_logs(
+            Filters=[{"Name": "resource-id", "Values": [res[0]["VpcId"]]}]
+        )["FlowLogs"]
+        self.assertEqual(lgs[0]["ResourceId"], res[0]["VpcId"])
 
     def test_vpc_flow_log_destination(self):
         session_factory = self.replay_flight_data('test_vpc_flow_filter_destination')