Scenario #3: Migrate a WAF Policy between two BIG-IPs¶
This lab is a variant of the previous one. It takes a manually managed F5 BIG-IP Advanced WAF Policy from an existing F5 BIG-IP and migrates it to a different BIG-IP through Terraform resources.
You can encounter this scenario in multiple use-cases:
Migrating from a BIG-IP to another (platform refresh).
Re-hosting (also known as, Lift & Shift) in a Cloud migration project.
Back-and-forth importing/exporting WAF Policies between the following environments: development, test/QA, and production.
The goal is to leverage the previous import scenario in order to carry and ingest the WAF Policy from one BIG-IP to another, while keeping its state through Terraform.
You can couple the WAF Policy and its children objects (parameters, URLs, attack signatures, exceptions, and other similar object) with a BIG-IP and/or share the objects across multiple policies, depending on the use case.
Pre-requisites¶
On the BIG-IP:
BIG-IP version 16.1 or newer
Advanced WAF Provisioned
Credentials with REST API access
On Terraform:
Using F5 BIG-IP provider version 1.15.0 or newer
Using Hashicorp versions following Releases and versioning
Migrate a Policy¶
Create 4 files:
variables.tf
inputs.auto.tfvars
main.tf
outputs.tf
variables.tf¶1variable previous_bigip {} 2variable new_bigip {} 3variable username {} 4variable password {}
inputs.auto.tfvars¶1previous_bigip = "10.1.1.8:443" 2new_bigip = "10.1.1.9:443" 3username = "admin" 4password = "whatIsYourBigIPPassword?"
main.tf¶1terraform { 2 required_providers { 3 bigip = { 4 source = "F5Networks/bigip" 5 version = "1.15" 6 } 7 } 8} 9provider "bigip" { 10 alias = "old" 11 address = var.previous_bigip 12 username = var.username 13 password = var.password 14} 15provider "bigip" { 16 alias = "new" 17 address = var.new_bigip 18 username = var.username 19 password = var.password 20} 21 22 23resource "bigip_waf_policy" "current" { 24 provider = bigip.old 25 partition = "Common" 26 name = "scenario3" 27 template_name = "POLICY_TEMPLATE_RAPID_DEPLOYMENT" 28}
Note
You can set the template value to anything. When you import the template, the value is overwritten.
outputs.tf¶1output "policyId" { 2 value = bigip_waf_policy.current.policy_id 3} 4 5output "policyJSON" { 6 value = bigip_waf_policy.current.policy_export_json 7}
This example defines two BIG-IPs: “old” and “new”. The “old” BIG-IP has the existing Advanced WAF Policies, the “new” is our target.
Similar to Scenario #2: Manage an existing WAF policy with Terraform, you need the Advanced WAF Policy ID to make the initial import:
Check on the iControl REST API Endpoint:
/mgmt/tm/asm/policies?$filter=name+eq+scenario3&$select=id
Get a script example in the
lab/scripts/
folderRun the following code sample in the Go PlayGround:
package main import ( "crypto/md5" b64 "encoding/base64" "fmt" "strings" ) func Hasher(policyName string) string { hasher := md5.New() hasher.Write([]byte(policyName)) encodedString := b64.StdEncoding.EncodeToString(hasher.Sum(nil)) return strings.TrimRight(encodedString, "=") } func main() { var partition string = "Common" var policyName string = "scenario3" fullName := "/" + partition + "/" + policyName policyId := Hasher(fullName) r := strings.NewReplacer("/", "_", "-", "_", "+", "-") fmt.Println("Policy Id: ", r.Replace(policyId)) }
Run the following commands to:
Initialize the Terraform Project.
Import the current WAF policy from the “old” BIG-IP into your Terraform state.
Create the Advanced WAF Policy resource for the “BIG-IP” pointing to the imported state.
Configure the lifecycle of our WAF Policy.
foo@bar:~$ terraform init Initializing the backend... Initializing provider plugins... [...] Terraform has been successfully initialized! foo@bar:~$ terraform import bigip_waf_policy.current YiEQ4l1Fw1U9UnB2-mTKWA bigip_waf_policy.this: Importing from ID "YiEQ4l1Fw1U9UnB2-mTKWA"... bigip_waf_policy.this: Import prepared! Prepared bigip_waf_policy for import bigip_waf_policy.this: Refreshing state... [id=YiEQ4l1Fw1U9UnB2-mTKWA] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
Update your terraform main.tf file with the outputs from the following two commands:
foo@bar:~$ terraform show -json | jq '.values.root_module.resources[].values.policy_export_json | fromjson' > currentWAFPolicy.json foo@bar:~$ terraform show -no-color # bigip_waf_policy.this: resource "bigip_waf_policy" "this" { application_language = "utf-8" id = "YiEQ4l1Fw1U9UnB2-mTKWA" name = "/Common/scenario3" policy_export_json = jsonencode( { [...] } ) policy_id = "YiEQ4l1Fw1U9UnB2-mTKWA" template_name = "POLICY_TEMPLATE_COMPREHENSIVE" type = "security" }
This is a migration use case, so you do not need the current WAF Policy from the existing BIG-IP. Using the collected data from the Terraform import, you can now update your main.tf file:
resource "bigip_waf_policy" "migrated" { provider = bigip.new application_language = "utf-8" partition = "Common" name = "scenario3" policy_id = "YiEQ4l1Fw1U9UnB2-mTKWA" template_name = "POLICY_TEMPLATE_COMPREHENSIVE" type = "security" policy_import_json = file("${path.module}/currentWAFPolicy.json") }
Note
F5 replaced the
policy_export_json
argument withpolicy_import_json
pointing to the imported WAF Policy JSON file.Plan and apply your new project.
foo@bar:~$ terraform plan -out scenario3 bigip_waf_policy.migrated: Refreshing state... [id=YiEQ4l1Fw1U9UnB2-mTKWA] Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: ~ update in-place [...] ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Saved the plan to: scenario3 To perform exactly these actions, run the following command to apply: terraform apply "scenario3" foo@bar:~$ terraform apply "scenario3" bigip_waf_policy.this: Modifying... [id=YiEQ4l1Fw1U9UnB2-mTKWA] bigip_waf_policy.this: Still modifying... [id=EdchwjSqo9cFtYP-iWUJmw, 10s elapsed] bigip_waf_policy.this: Modifications complete after 16s [id=EdchwjSqo9cFtYP-iWUJmw] Apply complete! Resources: 0 added, 1 changed, 0 destroyed. Outputs: policyId = "EdchwjSqo9cFtYP-iWUJmw" policyJSON = "{[...]}"
Manage Policy lifecycle¶
Manage your WAF Policy using the previous lab, then check your WAF Policy on your BIG-IP after each Terraform apply.
Define parameters
Create a parameters.tf file:
data "bigip_waf_entity_parameter" "P1" { name = "Parameter1" type = "explicit" data_type = "alpha-numeric" perform_staging = true signature_overrides_disable = [200001494, 200001472] }
Add references to these parameters in the
bigip_waf_policy
Terraform resource in the main.tf file:resource "bigip_waf_policy" "migrated" { [...] parameters = [data.bigip_waf_entity_parameter.P1.json] }
foo@bar:~$ terraform plan -out scenario3 foo@bar:~$ terraform apply "scenario3"
Define URLs
Create a urls.tf file:
data "bigip_waf_entity_url" "U1" { name = "/URL1" description = "this is a test for URL1" type = "explicit" protocol = "http" perform_staging = true signature_overrides_disable = [12345678, 87654321] method_overrides { allow = false method = "BCOPY" } method_overrides { allow = true method = "BDELETE" } } data "bigip_waf_entity_url" "U2" { name = "/URL2" }
Add references to this URL in the
bigip_waf_policy
Terraform resource in the main.tf file:resource "bigip_waf_policy" "migrated" { [...] urls = [data.bigip_waf_entity_url.U1.json, data.bigip_waf_entity_url.U2.json] }
Run it:
foo@bar:~$ terraform plan -out scenario3 foo@bar:~$ terraform apply "scenario3"
Define attack signatures
Create a signatures.tf file:
data "bigip_waf_signatures" "S1" { provider = bigip.new signature_id = 200104004 description = "Java Code Execution" enabled = true perform_staging = true } data "bigip_waf_signatures" "S2" { provider = bigip.new signature_id = 200104005 enabled = false }
Add references to this URL in the
bigip_waf_policy
Terraform resource in the main.tf file:resource "bigip_waf_policy" "migrated" { [...] signatures = [data.bigip_waf_signatures.S1.json, data.bigip_waf_signatures.S2.json] }
Run the plan:
foo@bar:~$ terraform plan -out scenario3 foo@bar:~$ terraform apply "scenario3"
What’s Next?