Last updated on: 2023-10-18 04:01:19.

Scenario #6: Manage an F5 BIG-IP Advanced WAF Policy with Policy Builder on multiple devices

The goal of this lab is to manage Policy Builder Suggestions an F5 BIG-IP Advanced WAF Policy from on multiple devices or clusters. Use cases include:

  • Multiple devices serving and protecting the same application in multiple datacenters, application spanning across multiple clouds, and other similar environments. By nature, each standalone device or clusters can see different traffic patterns; therefore, you can have different suggestions. The goal is to consolidate the suggestions, before enforcing them.
  • Production BIG-IP systems protecting the application; therefore, seeing the real life traffic flow for seeding the Policy Builder, but first validating all changes in the test environment, before enforcing the policy in your production environment.

Note

These two use cases are not mutually exclusive and you can manage both within a single workflow.

Pre-requisites

On the BIG-IP:

  • BIG-IP version 16.1 or newer
  • Advanced WAF Provisioned
  • Credentials with REST API access
  • An Advanced WAF Policy with Policy Builder enabled and Manual traffic Learning

On Terraform:

Policy Creation

Create 4 files:

  • variables.tf
  • inputs.auto.tfvars
  • main.tf
  • outputs.tf
variables.tf
1
2
3
4
5
variable prod_dc1_bigip {}
variable prod_cloud_bigip {}
variable qa_bigip {}
variable username {}
variable password {}

inputs.auto.tfvars
1
2
3
4
5
prod_dc1_bigip   = "10.1.1.8"
prod_cloud_bigip = "10.1.1.7"
qa_bigip         = "10.1.1.9"
username         = "admin"
password         = "WhatisYourPassword?"

main.tf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
terraform {
  required_providers {
    bigip = {
      source                         = "F5Networks/bigip"
      version                        = "1.15"
    }
  }
}

provider "bigip" {
  alias                      = "prod1"
  address                    = var.prod_dc1_bigip
  username                   = var.username
  password                   = var.password
}

provider "bigip" {
  alias                      = "prod2"
  address                    = var.prod_cloud_bigip
  username                   = var.username
  password                   = var.password
}

provider "bigip" {
  alias                      = "qa"
  address                    = var.qa_bigip
  username                   = var.username
  password                   = var.password
}

resource "bigip_waf_policy" "P1S6" {
    provider                 = bigip.prod1
    application_language     = "utf-8"
    partition                            = "Common"
    name                     = "scenario6"
    enforcement_mode         = "blocking"
    template_name            = "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
}

resource "bigip_waf_policy" "P2S6" {
    provider                 = bigip.prod2
    application_language     = "utf-8"
    partition                = "Common"
    name                     = "scenario6"
    enforcement_mode         = "blocking"
    template_name            = "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
}

resource "bigip_waf_policy" "QAS6" {
    provider                 = bigip.qa
    application_language     = "utf-8"
    partition                = "Common"
    name                     = "scenario6"
    enforcement_mode         = "blocking"
    template_name            = "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
}

outputs.tf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
output "P1S6Id" {
        value        = bigip_waf_policy.P1S6.policy_id
}
output "P1S6JSON" {
        value    = bigip_waf_policy.P1S6.policy_export_json
}
output "P2S6Id" {
        value        = bigip_waf_policy.P2S6.policy_id
}
output "P2S6JSON" {
        value    = bigip_waf_policy.P2S6.policy_export_json
}
output "QAS6Id" {
        value        = bigip_waf_policy.QAS6.policy_id
}
output "QAS6JSON" {
        value    = bigip_waf_policy.QAS6.policy_export_json
}

Simulate a WAF Policy workflow

The following is a typical workflow:

On each BIG-IP, there is a scenario6.vs Virtual Server.

  1. Create and associate the same WAF Policy to these Virtual Servers.
  2. Run traffic on Production devices. Make sure you are not running the same requests on both Production devices: get distinct suggestions.
  3. Test the suggestions from Prod1 and Prod2 devices on the QA device and check that the application is not broken.
  4. Enforce suggestions on the Production devices.

Note

There are some changes that may be specific to the QA environment, such as setting Trusted IP addresses. So we will make the specific tuning first.

  1. Policy creation and association.

    Plan and apply your new Terraform project.

    foo@bar:~$ terraform init
    
    foo@bar:~$ terraform plan -out scenario6
    
    foo@bar:~$ terraform apply "scenario6"
    

    Go on your WebUI and associate the WAF Policies to the scenario6.vs Virtual Servers (do it manually, but it can also be done using the bigip_as3 terraform resource from the same Terraform F5Networks/bigip provider).

  2. Running real life traffic.

    Run both legitimate AND illegitimate traffic against your two production BIG-IP devices (scenario6 virtual servers on PROD1 and PROD2 BIG-IPs). Try to throw different attacks on each devices so we make sure we collect different Policy Builder suggestions (checkout the recommended steps described on Module5).

    You may need to run the same request multiple times to make sure you get a satisfying learning score.

  3. Collect and test the Policy Builder suggestions.

    Create a pb_suggestions.tf file:

    data "bigip_waf_pb_suggestions" "S6_22AUG20221800_P1" {
      provider                   = bigip.prod1
      policy_name            = "scenario6"
      partition              = "Common"
      minimum_learning_score = 100
    }
    
    data "bigip_waf_pb_suggestions" "S6_22AUG20221800_P2" {
      provider                   = bigip.prod2
      policy_name            = "scenario6"
      partition              = "Common"
      minimum_learning_score = 100
    }
    
    output "PB_S6_22AUG20221800_P1" {
      value   = data.bigip_waf_pb_suggestions.S6_22AUG20221800_P1.json
    }
    
    output "PB_S6_22AUG20221800_P2" {
      value   = data.bigip_waf_pb_suggestions.S6_22AUG20221800_P2.json
    }
    

    Update the main.tf file on the scenario6 QA WAF Policy resource:

    resource "bigip_waf_policy" "QAS6" {
        provider                 = bigip.qa
        application_language = "utf-8"
        name                 = "scenario6"
        partition            = "Common"
        template_name        = "POLICY_TEMPLATE_FUNDAMENTAL"
        type                 = "security"
        policy_import_json   = data.http.scenario6.body
        modifications        = [data.bigip_waf_pb_suggestions.S6_22AUG20221800_P1.json, data.bigip_waf_pb_suggestions.S6_22AUG20221800_P2.json]
    }
    

    Note

    There are obviously some redundant learning suggestions on both data sources but the Declarative WAF API automatically removes them.

    Test your application through the QA device.

    For UDF users: check https://qa.f5demo.fch and see that the application is not broken and attacks are blocked.

  4. Enforce suggestions on the Production devices. In a real life scenario, use one of the following ways to perform this step:

    1. The QA device WAF Policy should be 100% consistent with production devices.

      QA.WAF == PROD.WAF

      This is the easiest way. After validating the suggestions and removing the potential False Positives, just output the JSON policy from QA and refer to it as a policy_import_json argument in the production BIG-IPs.

      In this case, update the main.tf file:

      resource "bigip_waf_policy" "P1S6" {
          provider                   = bigip.prod1
          application_language       = "utf-8"
          partition                      = "Common"
          name                       = "scenario6"
          enforcement_mode           = "blocking"
          template_name              = "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
          policy_import_json     = bigip_waf_policy.QAS6.policy_export_json
      }
      
      resource "bigip_waf_policy" "P2S6" {
          provider                   = bigip.prod2
          application_language       = "utf-8"
          partition                  = "Common"
          name                       = "scenario6"
          enforcement_mode           = "blocking"
          template_name              = "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
          policy_import_json     = bigip_waf_policy.QAS6.policy_export_json
      }
      
      resource "bigip_waf_policy" "QAS6" {
          provider                   = bigip.qa
          application_language       = "utf-8"
          partition              = "Common"
          name                       = "scenario6"
          enforcement_mode           = "blocking"
          template_name              = "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
      }
      

      Plan and apply:

      foo@bar:~$ terraform plan -out scenario6
      foo@bar:~$ terraform apply "scenario6"
      
    2. The QA device WAF Policy may have settings differences with production devices (for example, Trusted IP exceptions).

      QA.WAF != PROD.WAF

      In this case, you must manage the learning suggestions as a separate modifications entity that has to move between WAF Policies. The learning suggestions, when imported into the QA WAF Policy, are de-duplicated and ingested into the WAF Policy. However, they remain in a dedicated space of the Declarative REST JSON: the modifications array. The goal is to import only this section back to the production devices, so any differences in the core entities are not affected.

      resource "bigip_waf_policy" "P1S6" {
          provider                    = bigip.prod1
          application_language    = "utf-8"
          partition               = "Common"
          name                    = "scenario6"
          enforcement_mode        = "blocking"
          template_name               = "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
          policy_import_json      = bigip_waf_policy.QAS6.policy_export_json.modifications
      }
      
      resource "bigip_waf_policy" "P2S6" {
          provider                = bigip.prod2
          application_language    = "utf-8"
          partition               = "Common"
          name                    = "scenario6"
          enforcement_mode        = "blocking"
          template_name           = "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
          policy_import_json      = bigip_waf_policy.QAS6.policy_export_json.modifications
      }
      
      resource "bigip_waf_policy" "QAS6" {
          provider                = bigip.qa
          application_language    = "utf-8"
          partition               = "Common"
          name                    = "scenario6"
          enforcement_mode        = "blocking"
          template_name           = "POLICY_TEMPLATE_RAPID_DEPLOYMENT"
      }
      
    3. Plan and apply:

      foo@bar:~$ terraform plan -out scenario6
      foo@bar:~$ terraform apply "scenario6"
      

What’s Next?