Repository: cloud-custodian/cloud-custodian

Issue:
VPC set-flow-log PolicyValidationError When Sending to S3
Trying to run the following policy to configure VPC flow logs across all VPCs to the same bucket. However, it fails with 

c7n.exceptions.PolicyValidationError: DeliverLogsPermissionArn required when creating flow-logs on ....

However, according to the awscli documentation, DeliverLogsPermissionArn is not to be set when delivering to S3. Seems that it is a bug for c7n to fail the validation here. 

https://docs.aws.amazon.com/cli/latest/reference/ec2/create-flow-logs.html

```
{'type': 'set-flow-log', 'LogDestinationType': 's3', 'LogDestination': 'arn:aws:s3:::my-vpcflowlogs', 'TrafficType': 'ALL'}]}
```

``` yaml
- name: VPC-001-Enable-VPC-Flow
  resource: aws.vpc
  comment: "CIS Amazon Web Services Foundations v1.1.0 (4.3)"
  filters:
    - not:
      - type: flow-logs
        enabled: true
  actions:
    - type: notify
      transport:
        type: sqs
        region: us-east-1
        queue: https://sqs.us-east-1.amazonaws.com/{account_id}/my_custodian_log
    - type: set-flow-log
      LogDestinationType: s3
      LogDestination: arn:aws:s3:::my-vpcflowlogs
      TrafficType: ALL
```


Discussion:
Thanks for reporting! Looks like there are some changes in the AWS API behavior on mandatory and optional attributes: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.create_flow_logs
I'll put out a PR shortly. 

Resolving patch:
diff --git a/c7n/resources/vpc.py b/c7n/resources/vpc.py
--- a/c7n/resources/vpc.py
+++ b/c7n/resources/vpc.py
@@ -1989,20 +1989,39 @@ class CreateFlowLogs(BaseAction):
         'eni': 'NetworkInterface'
     }
 
+    SchemaValidation = {
+        's3': {
+            'required': ['LogDestination'],
+            'absent': ['LogGroupName', 'DeliverLogsPermissionArn']
+        },
+        'cloud-watch-logs': {
+            'required': ['DeliverLogsPermissionArn'],
+            'one-of': ['LogGroupName', 'LogDestination'],
+        }
+    }
+
     def validate(self):
         self.state = self.data.get('state', True)
-        if self.state:
-            if not self.data.get('DeliverLogsPermissionArn'):
-                raise PolicyValidationError(
-                    'DeliverLogsPermissionArn required when '
-                    'creating flow-logs on %s' % (self.manager.data,))
-            if (not self.data.get('LogGroupName') and not self.data.get('LogDestination')):
+        if not self.state:
+            return
+        destination_type = self.data.get(
+            'LogDestinationType', 'cloud-watch-logs')
+        dvalidation = self.SchemaValidation[destination_type]
+        for r in dvalidation.get('required', ()):
+            if not self.data.get(r):
                 raise PolicyValidationError(
-                    'Either LogGroupName or LogDestination required')
-            if (self.data.get('LogDestinationType') == 's3' and
-               not self.data.get('LogDestination')):
+                    'Required %s missing for destination-type:%s' % (
+                        r, destination_type))
+        for r in dvalidation.get('absent', ()):
+            if r in self.data:
                 raise PolicyValidationError(
-                    'LogDestination required when LogDestinationType is s3')
+                    '%s is prohibited for destination-type:%s' % (
+                        r, destination_type))
+        if ('one-of' in dvalidation and
+                sum([1 for k in dvalidation['one-of'] if k in self.data]) != 1):
+            raise PolicyValidationError(
+                "Destination:%s Exactly one of %s required" % (
+                    destination_type, ", ".join(dvalidation['one-of'])))
         return self
 
     def delete_flow_logs(self, client, rids):


Test patch:
diff --git a/tests/test_vpc.py b/tests/test_vpc.py
--- a/tests/test_vpc.py
+++ b/tests/test_vpc.py
@@ -2590,6 +2590,42 @@ def test_vpc_flow_log_destination(self):
         self.assertEqual(resources[0]['c7n:flow-logs'][0]['LogDestination'],
                          'arn:aws:s3:::c7n-vpc-flow-logs')
 
+    def test_vpc_set_flow_logs_validation(self):
+        with self.assertRaises(PolicyValidationError) as e:
+            self.load_policy({
+                'name': 'flow-set-validate-1',
+                'resource': 'vpc',
+                'actions': [{
+                    'type': 'set-flow-log',
+                    'LogDestination': 'arn:aws:s3:::c7n-vpc-flow-logs/test/'
+                }]})
+        self.assertIn(
+            "DeliverLogsPermissionArn missing", str(e.exception))
+        with self.assertRaises(PolicyValidationError) as e:
+            self.load_policy({
+                'name': 'flow-set-validate-2',
+                'resource': 'vpc',
+                'actions': [{
+                    'type': 'set-flow-log',
+                    'DeliverLogsPermissionArn': 'arn:aws:iam',
+                    'LogGroupName': '/cloudwatch/logs',
+                    'LogDestination': 'arn:aws:s3:::c7n-vpc-flow-logs/test/'
+                }]})
+        self.assertIn("Exactly one of", str(e.exception))
+        with self.assertRaises(PolicyValidationError) as e:
+            self.load_policy({
+                'name': 'flow-set-validate-3',
+                'resource': 'vpc',
+                'actions': [{
+                    'type': 'set-flow-log',
+                    'LogDestinationType': 's3',
+                    'DeliverLogsPermissionArn': 'arn:aws:iam',
+                    'LogDestination': 'arn:aws:s3:::c7n-vpc-flow-logs/test/'
+                }]})
+        self.assertIn(
+            "DeliverLogsPermissionArn is prohibited for destination-type:s3",
+            str(e.exception))
+
     def test_vpc_set_flow_logs_s3(self):
         session_factory = self.replay_flight_data("test_vpc_set_flow_logs_s3")
         p = self.load_policy(
@@ -2604,8 +2640,6 @@ def test_vpc_set_flow_logs_s3(self):
                         "type": "set-flow-log",
                         "LogDestinationType": "s3",
                         "LogDestination": "arn:aws:s3:::c7n-vpc-flow-logs/test.log.gz",
-                        "DeliverLogsPermissionArn":
-                            "arn:aws:iam::644160558196:role/testing-vpc-flow-log-role",
                     }
                 ],
             },