> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Fms webacl rulegroup association remediation

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        Below are concise, step‑by‑step console instructions to fix the finding “FMS Web ACL should have rule group association” in AWS (for a Web ACL managed by AWS Firewall Manager / AWS WAF).

        ### 1. Identify the FMS Web ACL with the Finding

        1. Open **AWS Management Console**.
        2. Go to **Security Hub** (or the service that raised the finding, if different).
        3. Open the specific finding:
           * Look for a finding mentioning something like `FMS Web ACL Should Have Rule Group Association` or similar.
           * In the finding details, note:
             * The **Web ACL name** and **ID**.
             * The **Region**.
             * The **resource type** (e.g., CloudFront distribution, Application Load Balancer, API Gateway).

        ### 2. Go to the Web ACL in AWS WAF

        1. Switch to the Region from the finding (for CloudFront Web ACLs, use **us-east-1**).
        2. In the console, go to **AWS WAF & Shield**.
        3. In the left menu, choose **Web ACLs**.
        4. Find and select the Web ACL identified in the finding (match by name/ID).

        ### 3. Create or Choose a Rule Group

        If you already have a rule group you want to associate, skip to Step 4.

        To create a new rule group:

        1. In AWS WAF, in the left menu, select **Rule groups**.
        2. Click **Create rule group**.
        3. Configure:
           * **Name**: e.g., `fms-required-rule-group`.
           * **CloudWatch metric name**: any valid name.
           * **Region**: same as Web ACL (or us-east-1 for CloudFront).
           * **Capacity**: set an appropriate WCU number based on your planned rules.
        4. Under **Rules**, click **Add rules** and define at least one rule (e.g., IP match, rate-based, etc.).
        5. Click **Create rule group** to save.

        ### 4. Associate the Rule Group with the Web ACL

        1. Return to **Web ACLs**.
        2. Click the target **Web ACL**.
        3. Choose the **Rules** tab (or **Rules** section within the Web ACL editor).
        4. Click **Add rules** → **Add my own rules and rule groups**.
        5. In the **Rule groups** section:
           * Select the relevant **Rule group** (managed by you or AWS managed rule groups, if appropriate).
           * Set an **Action** override if needed (e.g., Count/Block/Allow, if allowed by the UI).
        6. Arrange rule order (priority) if there are multiple rules/rule groups.
        7. Click **Save** or **Save changes** at the bottom.

        ### 5. (If Using AWS Firewall Manager Policy) Ensure Policy Includes a Rule Group

        If the Web ACL is managed by Firewall Manager, you typically should not manually edit the Web ACL; instead:

        1. Open **AWS Firewall Manager** in the console.
        2. Go to **Security policies**.
        3. Find and select the policy that manages this Web ACL.
        4. Click **Edit policy**.
        5. In the **Policy rules** or **Add AWS WAF rules** section:
           * Add the desired **Rule groups** to the policy (e.g., your custom rule group or AWS managed rule groups).
        6. Save the policy.

        Firewall Manager will push the updated rule groups to all member Web ACLs governed by that policy.

        ### 6. Verify Remediation

        1. In **AWS WAF**, open the Web ACL and confirm at least one **Rule group** is listed in the Rules.
        2. Wait for Security Hub (or the originating service) to re‑evaluate:
           * Usually within a few minutes to a few hours, the finding should move to **Resolved** / **PASSED** state if everything is correct.

        This addresses the requirement that the FMS-managed Web ACL must have at least one rule group associated.
      </Accordion>

      <Accordion title="Using CLI">
        In AWS there is no WAF scope called “CloudWatch,” so I’ll assume you mean an AWS WAFv2 Web ACL managed by Firewall Manager (FMS) that currently has no rule groups associated. The fix is to update that Web ACL (or its FMS policy) to include at least one rule group.

        Below is a minimal, CLI‑only approach using WAFv2 (scope `REGIONAL` or `CLOUDFRONT`); adapt names/ARNs as needed.

        ***

        ### 1. Identify the Web ACL missing rule groups

        ```bash theme={null}
        aws wafv2 list-web-acls \
          --scope REGIONAL \
          --region us-east-1
        ```

        Note the `Id` and `Name` of the target Web ACL.

        Then get full details:

        ```bash theme={null}
        aws wafv2 get-web-acl \
          --name "<WEB_ACL_NAME>" \
          --scope REGIONAL \
          --id "<WEB_ACL_ID>" \
          --region us-east-1
        ```

        Check the `Rules` array; it is likely empty (`[]`).

        You’ll also need the Web ACL’s `LockToken` from this output for the update.

        ***

        ### 2. Choose or create a rule group

        #### Option A – Use an AWS Managed Rule Group

        For example, the AWS managed “CommonRuleSet”:

        * Vendor: `AWS`
        * Name: `AWSManagedRulesCommonRuleSet`

        You don’t create this; you only reference it.

        #### Option B – Use your own existing rule group

        List your rule groups if you have custom ones:

        ```bash theme={null}
        aws wafv2 list-rule-groups \
          --scope REGIONAL \
          --region us-east-1
        ```

        Pick the rule group `ARN` from the output.

        ***

        ### 3. Build the new rule set JSON

        Create a file `rules.json` with at least one rule referencing a rule group.

        **Example using an AWS managed rule group:**

        ```json theme={null}
        [
          {
            "Name": "AWSCommonRules",
            "Priority": 1,
            "Statement": {
              "ManagedRuleGroupStatement": {
                "VendorName": "AWS",
                "Name": "AWSManagedRulesCommonRuleSet"
              }
            },
            "OverrideAction": {
              "None": {}
            },
            "VisibilityConfig": {
              "SampledRequestsEnabled": true,
              "CloudWatchMetricsEnabled": true,
              "MetricName": "AWSCommonRulesMetric"
            }
          }
        ]
        ```

        If using a custom rule group instead:

        ```json theme={null}
        [
          {
            "Name": "CustomRGAssociation",
            "Priority": 1,
            "Statement": {
              "RuleGroupReferenceStatement": {
                "ARN": "arn:aws:wafv2:us-east-1:123456789012:regional/rulegroup/MyRuleGroup/abcd1234-5678-90ab-cdef-EXAMPLE"
              }
            },
            "OverrideAction": {
              "None": {}
            },
            "VisibilityConfig": {
              "SampledRequestsEnabled": true,
              "CloudWatchMetricsEnabled": true,
              "MetricName": "CustomRGMetric"
            }
          }
        ]
        ```

        ***

        ### 4. Update the Web ACL to associate the rule group

        From step 1 you have:

        * `Name`
        * `Id`
        * `LockToken`
        * Existing `DefaultAction` and `VisibilityConfig` (must be preserved)

        First, capture the existing Web ACL config (excluding `Rules`):

        ```bash theme={null}
        aws wafv2 get-web-acl \
          --name "<WEB_ACL_NAME>" \
          --scope REGIONAL \
          --id "<WEB_ACL_ID>" \
          --region us-east-1 > web-acl-current.json
        ```

        Open `web-acl-current.json` and note:

        * `"DefaultAction"` block
        * `"VisibilityConfig"` block
        * `"Description"` (optional)
        * `"LockToken"`

        Now run `update-web-acl`, providing the new rules:

        ```bash theme={null}
        aws wafv2 update-web-acl \
          --name "<WEB_ACL_NAME>" \
          --scope REGIONAL \
          --id "<WEB_ACL_ID>" \
          --lock-token "<LOCK_TOKEN_FROM_GET_WEB_ACL>" \
          --region us-east-1 \
          --default-action '{
            "Allow": {}
          }' \
          --visibility-config '{
            "SampledRequestsEnabled": true,
            "CloudWatchMetricsEnabled": true,
            "MetricName": "MyWebAclMetrics"
          }' \
          --rules file://rules.json
        ```

        Replace `DefaultAction` and `VisibilityConfig` with the values from your current Web ACL instead of the example above.

        ***

        ### 5. (If using Firewall Manager) Update via FMS Policy instead

        If the Web ACL is managed by Firewall Manager, best practice is to modify the FMS policy, not the Web ACL directly:

        1. Get the policy:

        ```bash theme={null}
        aws fms list-policies
        aws fms get-policy --policy-id "<POLICY_ID>" > fms-policy.json
        ```

        2. In `fms-policy.json`, under `SecurityServicePolicyData.ManagedServiceData`, you’ll find a JSON string describing the WAF configuration. Edit that JSON to add the rule groups (similar to step 3).

        3. Put the updated policy:

        ```bash theme={null}
        aws fms put-policy \
          --policy file://fms-policy.json \
          --region us-east-1
        ```

        This will regenerate/update the underlying Web ACLs with rule group associations.

        ***

        After these steps, the FMS-managed Web ACL will have at least one rule group associated, satisfying the “FMS Web ACL Should Have Rule Group Association” requirement.
      </Accordion>

      <Accordion title="Using Python">
        Below are concrete, step‑by‑step remediation instructions and a Python (boto3) example to ensure a Firewall Manager (FMS)–managed WAFv2 Web ACL has at least one rule group associated.

        ***

        ## 1. Understand the Requirement

        “**FMS Web ACL Should Have Rule Group Association**” means:

        * The Web ACLs that are managed by **AWS Firewall Manager** must include at least one **Rule Group** (AWS managed or customer managed).
        * For WAFv2, this means the Web ACL’s `Rules` list must contain at least one `RuleGroupReferenceStatement`.

        You can remediate in two main ways:

        1. **Update the WAFv2 Web ACL directly** via `wafv2.update_web_acl` to add a rule group.
        2. **Update the Firewall Manager policy** that configures those Web ACLs so that the rule groups are automatically applied everywhere.

        If these Web ACLs are created/owned by FMS, the proper long‑term fix is to update the **FMS policy**.

        ***

        ## 2. Prerequisites

        * Python 3.x installed.
        * `boto3` installed:
          ```bash theme={null}
          pip install boto3
          ```
        * AWS credentials configured (`aws configure` or environment variables).
        * The ARN of at least one **Rule Group** you want to associate:
          * Example (regional):
            * `arn:aws:wafv2:us-east-1:111122223333:regional/rulegroup/my-rule-group/12345678-aaaa-bbbb-cccc-1234567890ab`
          * Or AWS Managed Rule Group:
            * Use `RuleGroupReferenceStatement` with `VendorName` and `Name` for managed rule groups (e.g., `AWS`, `AWSManagedRulesCommonRuleSet`).

        ***

        ## 3. Option A – Update Web ACLs Directly via WAFv2

        Use this if you already know the Web ACL ARN or have them from your scanner.

        ### Step 3.1: Python script to add a Rule Group to a Web ACL

        ```python theme={null}
        import boto3

        # CONFIGURE THESE
        REGION = "us-east-1"
        WEB_ACL_NAME = "your-fms-managed-web-acl-name"
        WEB_ACL_SCOPE = "REGIONAL"     # or "CLOUDFRONT"
        RULE_GROUP_ARN = "arn:aws:wafv2:us-east-1:111122223333:regional/rulegroup/my-rule-group/12345678-aaaa-bbbb-cccc-1234567890ab"
        NEW_RULE_NAME = "AttachRuleGroup"

        waf = boto3.client("wafv2", region_name=REGION)

        def ensure_rule_group_associated():
            # 1. Get current Web ACL
            response = waf.list_web_acls(Scope=WEB_ACL_SCOPE, Limit=100)
            web_acl_summaries = response.get("WebACLs", [])
            web_acl_id = None
            web_acl_arn = None

            for w in web_acl_summaries:
                if w["Name"] == WEB_ACL_NAME:
                    web_acl_id = w["Id"]
                    web_acl_arn = w["ARN"]
                    break

            if not web_acl_id:
                raise Exception(f"Web ACL {WEB_ACL_NAME} not found in {WEB_ACL_SCOPE}")

            web_acl = waf.get_web_acl(
                Name=WEB_ACL_NAME,
                Scope=WEB_ACL_SCOPE,
                Id=web_acl_id
            )["WebACL"]

            rules = web_acl.get("Rules", [])

            # 2. Check if any rule group is already associated
            has_rule_group = any(
                "RuleGroupReferenceStatement" in r.get("Statement", {})
                or "ManagedRuleGroupStatement" in r.get("Statement", {})
                for r in rules
            )

            if has_rule_group:
                print(f"Web ACL {WEB_ACL_NAME} already has a rule group associated.")
                return

            # 3. Add a new rule referencing the desired Rule Group
            new_rule = {
                "Name": NEW_RULE_NAME,
                "Priority": (max([r["Priority"] for r in rules]) + 1) if rules else 0,
                "Statement": {
                    "RuleGroupReferenceStatement": {
                        "ARN": RULE_GROUP_ARN
                    }
                },
                "OverrideAction": {
                    "None": {}
                },
                "VisibilityConfig": {
                    "SampledRequestsEnabled": True,
                    "CloudWatchMetricsEnabled": True,
                    "MetricName": NEW_RULE_NAME
                }
            }

            rules.append(new_rule)

            # 4. Update the Web ACL with the new rule
            waf.update_web_acl(
                Name=WEB_ACL_NAME,
                Scope=WEB_ACL_SCOPE,
                Id=web_acl_id,
                DefaultAction=web_acl["DefaultAction"],
                Description=web_acl.get("Description", ""),
                Rules=rules,
                VisibilityConfig=web_acl["VisibilityConfig"],
                LockToken=web_acl["LockToken"]
            )

            print(f"Associated rule group {RULE_GROUP_ARN} with Web ACL {WEB_ACL_NAME} ({web_acl_arn}).")

        if __name__ == "__main__":
            ensure_rule_group_associated()
        ```

        **What it does:**

        1. Finds the Web ACL by name and scope.
        2. Checks if any existing rule references a Rule Group or Managed Rule Group.
        3. If not, appends a new `RuleGroupReferenceStatement` rule.
        4. Calls `update_web_acl` with the new rules list and the current `LockToken`.

        ***

        ## 4. Option B – Fix via Firewall Manager Policy (Recommended for FMS)

        If the Web ACL is managed by Firewall Manager, you should adjust the **FMS policy** so all future and current Web ACLs have rule groups.

        ### Step 4.1: Inspect FMS policies in Python

        ```python theme={null}
        import boto3
        import json

        fms = boto3.client("fms", region_name="us-east-1")  # FMS is global, region is mostly for endpoint

        def list_waf_policies():
            policies = []
            next_token = None

            while True:
                args = {"MaxResults": 100}
                if next_token:
                    args["NextToken"] = next_token

                resp = fms.list_policies(**args)
                policies.extend(resp.get("PolicyList", []))
                next_token = resp.get("NextToken")
                if not next_token:
                    break

            return [p for p in policies if p["SecurityServiceType"] == "WAFV2"]

        def show_policy_managed_data(policy_id):
            resp = fms.get_policy(PolicyId=policy_id)
            policy = resp["Policy"]
            managed_data = json.loads(policy["SecurityServicePolicyData"]["ManagedServiceData"])
            print(json.dumps(managed_data, indent=2))

        if __name__ == "__main__":
            waf_policies = list_waf_policies()
            for p in waf_policies:
                print(f"Found WAFv2 policy: {p['PolicyName']} ({p['PolicyId']})")
                show_policy_managed_data(p["PolicyId"])
        ```

        This shows you the JSON `ManagedServiceData` definition that FMS uses to create Web ACLs, including any rule groups.

        ### Step 4.2: Update a policy to add rule groups

        You will see something similar in `ManagedServiceData`:

        ```json theme={null}
        {
          "type": "WAFV2",
          "preProcessRuleGroups": [],
          "postProcessRuleGroups": [],
          "defaultAction": { "type": "ALLOW" }
        }
        ```

        To ensure rule groups are always associated, add entries to `preProcessRuleGroups` or `postProcessRuleGroups`:

        ```json theme={null}
        {
          "type": "WAFV2",
          "preProcessRuleGroups": [
            {
              "ruleGroupArn": "arn:aws:wafv2:us-east-1:111122223333:regional/rulegroup/my-rule-group/12345678-aaaa-bbbb-cccc-1234567890ab",
              "overrideAction": { "type": "NONE" },
              "name": "MyPreRuleGroup",
              "priority": 1
            }
          ],
          "postProcessRuleGroups": [],
          "defaultAction": { "type": "ALLOW" }
        }
        ```

        #### Python example to update a specific FMS policy:

        ```python theme={null}
        import boto3
        import json

        fms = boto3.client("fms", region_name="us-east-1")

        POLICY_ID = "your-fms-waf-policy-id"
        RULE_GROUP_ARN = "arn:aws:wafv2:us-east-1:111122223333:regional/rulegroup/my-rule-group/12345678-aaaa-bbbb-cccc-1234567890ab"

        def add_rule_group_to_fms_policy():
            resp = fms.get_policy(PolicyId=POLICY_ID)
            policy = resp["Policy"]
            managed_data = json.loads(policy["SecurityServicePolicyData"]["ManagedServiceData"])

            pre_groups = managed_data.get("preProcessRuleGroups", [])
            post_groups = managed_data.get("postProcessRuleGroups", [])

            # Check if rule group already present
            all_group_arns = [g.get("ruleGroupArn") for g in pre_groups + post_groups]
            if RULE_GROUP_ARN in all_group_arns:
                print("Rule group already present in policy.")
                return

            # Add to preProcessRuleGroups
            new_group = {
                "ruleGroupArn": RULE_GROUP_ARN,
                "overrideAction": { "type": "NONE" },
                "name": "MyPreRuleGroup",
                "priority": (max([g["priority"] for g in pre_groups], default=0) + 1)
            }
            pre_groups.append(new_group)

            managed_data["preProcessRuleGroups"] = pre_groups
            managed_data["postProcessRuleGroups"] = post_groups

            policy["SecurityServicePolicyData"]["ManagedServiceData"] = json.dumps(managed_data)

            # Update policy
            fms.put_policy(
                Policy=policy,
                PolicyOption=resp.get("PolicyOption", {})
            )

            print(f"Updated FMS policy {POLICY_ID} to include rule group {RULE_GROUP_ARN}.")

        if __name__ == "__main__":
            add_rule_group_to_fms_policy()
        ```

        ***

        ## 5. About “CloudWatch” in Your Question

        CloudWatch is only indirectly involved (metrics, logs).\
        The actual remediation is done through:

        * `wafv2` API (for Web ACL rules).
        * `fms` API (for Firewall Manager policies).

        CloudWatch configuration (metrics/logs) is controlled via `VisibilityConfig` in WAF rules and Web ACLs, not where you attach rule groups.

        ***

        If you tell me:

        * Whether the Web ACL is regional or for CloudFront, and
        * Whether you want to use AWS Managed Rule Groups or your own rule group ARNs,

        I can adjust the Python snippet to exactly match your setup.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        resource "aws_fms_policy" "FMS_WEB_ACL_POLICY" {
          name                   = "FMS Web ACL Policy"          # replace with your policy name
          exclude_resource_tags  = false
          remediation_enabled    = true                          # ENABLE AUTOMATIC REMEDIATION (RemediationEnabled = true)
          resource_type          = "AWS::ElasticLoadBalancingV2::LoadBalancer" # replace with your target type

          security_service_policy_data {
            type = "WAFV2"

            # Replace MANAGED_SERVICE_DATA_JSON with your current policy JSON
            # from aws fms get-policy's Policy.SecurityServicePolicyData.ManagedServiceData
            managed_service_data = jsonencode({
              type = "WAFV2"
              preProcessRuleGroups = [
                {
                  ruleGroupType = "RuleGroup"
                  # priority is derived from order: index 0 => priority 0, index 1 => priority 1, etc.
                  ruleGroups = [
                    {
                      vendorName = "AWS"
                      name       = "AWSManagedRulesCommonRuleSet"
                    },
                    {
                      vendorName = "AWS"
                      name       = "AWSManagedRulesKnownBadInputsRuleSet"
                    }
                  ]
                }
              ]
              defaultAction = {
                type = "BLOCK"
              }
            })
          }

          # Add include_map / exclude_map / resource_tags as in your existing policy
        }
        ```

        Changing `remediation_enabled` from `false` (or omitted) to `true` does not force replacement; the policy is updated in place but, as with `put-policy`, AWS treats this as a full-policy update so review all other arguments carefully.

        Verification: `terraform plan` should show `remediation_enabled: false => true` (or `null => true`) on `aws_fms_policy.FMS_WEB_ACL_POLICY` with no `-/+` replacement of the resource.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
