Repository: cloud-custodian/cloud-custodian

Issue:
AWS: ALB is WAF-enabled support any waf
I am trying to use this policy to identify Internet-facing ALBs that are not associated with a WAF web ACL:
```
policies:
  - name: alb-without-waf
    description: |
      Application Load Balancers should have a WAF web ACL associated
    resource: app-elb
    filters:
       - type: value
         key: Scheme
         value: internal
         op: not-equal
       - type: waf-enabled
         state: false
```

However, a custodian dry-run fails with:
```
  File "/usr/local/lib/python3.7/site-packages/c7n/resources/appelb.py", line 221, in process
    raise ValueError("Invalid target acl:%s, acl not found" % target_acl)
ValueError: Invalid target acl:None, acl not found
```

I've stepped through the code while doing a dry-run and found that when the process() method for the WafEnabled class (defined in appelb.py) is called, self.data only contains this:

`{'type': 'waf-enabled', 'state': False}`

However, line 199 expects a web-acl to be part of self.data:

`target_acl = self.data.get('web-acl')`

This eventually causes the ValueError, because line 216 tries to set target_acl_id based on the results of a get for the target_acl:

`target_acl_id = name_id_map.get(target_acl, target_acl)`

And because web-acl was not in self.data, target_acl is None, so target_acl_id is None, which leads to the ValueError as a result of line 220 failing:

```
if target_acl_id not in name_id_map.values():
            raise ValueError("Invalid target acl:%s, acl not found" % target_acl)
```

I validated that explicitly setting a web-acl (with a `self.data['web-acl'] = 'mywebaclname'` prior to line 199) enables this to work correctly, at least for those ALBs that are associated with web ACL mywebaclname.


Discussion:
Correction, behavior is as-expected as the schema for the waf-enabled filter for app-elb indicates that web-acl is a required string.  Is there syntax to check that ANY web-acl is associated with the ALB, not a specific web-acl?

Resolving patch:
diff --git a/c7n/resources/appelb.py b/c7n/resources/appelb.py
--- a/c7n/resources/appelb.py
+++ b/c7n/resources/appelb.py
@@ -217,7 +217,7 @@ def process(self, resources, event=None):
 
         # generally frown on runtime validation errors, but also frown on
         # api calls during validation.
-        if target_acl_id not in name_id_map.values():
+        if target_acl and target_acl_id not in name_id_map.values():
             raise ValueError("Invalid target acl:%s, acl not found" % target_acl)
 
         arn_key = self.manager.resource_type.id


Test patch:
diff --git a/tests/test_appelb.py b/tests/test_appelb.py
--- a/tests/test_appelb.py
+++ b/tests/test_appelb.py
@@ -379,6 +379,19 @@ def test_appelb_delete_force(self):
         resources = p.run()
         self.assertEqual(len(resources), 1)
 
+    def test_appelb_waf_any(self):
+        factory = self.replay_flight_data("test_appelb_waf")
+        p = self.load_policy({
+            "name": "appelb-waf",
+            "resource": "app-elb",
+            "filters": [
+                {"type": "waf-enabled", "state": False}]},
+            session_factory=factory,
+        )
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+        self.assertEqual(resources[0]['LoadBalancerName'], 'testing')
+
     def test_appelb_waf(self):
         factory = self.replay_flight_data("test_appelb_waf")