Scenario #2: Manage an existing WAF policy with Terraform¶
The goal of this lab is to take an existing F5 BIG-IP Advanced WAF Policy – that has been created and managed on an F5 BIG-IP outside of Terraform – and to import and manage its lifecycle using the F5 BIG-IP Terraform Provider.
If you have multiple WAF policies protecting your applications, then it is likely these WAF policies have evolved over time, complicating ta,king inventory of each policy, each entity, and every attribute. The goal is to import the current policy, making that policy your current baseline. Every new change like, adding server technology, parameters, or attack signatures, you will do using Terraform as an addition or correction of this new baseline policy.
Pre-requisites¶
On the BIG-IP:
Version 16.1 or newer
Credentials with REST API access
/Common/scenario2 WAF policy (Rapid deployment template) created
On Terraform:
Using F5 BIG-IP provider version 1.15.0 or newer
Using Hashicorp versions following Releases and versioning
Import a Policy¶
Create 3 files:
variables.tf
inputs.tfvars
main.tf
variables.tf¶1variable bigip {} 2variable username {} 3variable password {}
inputs.tfvars¶1bigip = "10.1.1.9:443" 2username = "admin" 3password = "whatIsYourBigIPPassword?"
main.tf¶1terraform { 2 required_providers { 3 bigip = { 4 source = "F5Networks/bigip" 5 version = "1.15" 6 } 7 } 8} 9provider "bigip" { 10 address = var.bigip 11 username = var.username 12 password = var.password 13} 14 15resource "bigip_waf_policy" "this" { 16 partition = "Common" 17 name = "scenario2" 18 template_name = "POLICY_TEMPLATE_RAPID_DEPLOYMENT" 19}
outputs.tf¶1output "policyId" { 2 value = bigip_waf_policy.this.policy_id 3} 4 5 6output "policyJSON" { 7 value = bigip_waf_policy.this.policy_export_json 8}
Only define the two required attributes of the
bigip_waf_policy
terraform resource:name
andtemplate_name
. You MUST provide these attributes in order to manage the resource.Policy ID is required. Use one of the following ways to get the ID:
Check the iControl REST API Endpoint:
/mgmt/tm/asm/policies?$filter=name+eq+scenario2&$select=id
Get a script example in the
lab/scripts/
folderUse a Go code- consult the following Online Go PlayGround example:
Copy the following piece of code in the Go PlayGround.
// You can edit this code! // Click here and start typing. package main import "fmt" func main() { fmt.Println("Hello, 世界") }
Update the value of the following variables located in the main function:
var partition string = "Common"
var policyName string = "scenario2"
Run and get the policy ID.
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 = "scenario2" fullName := "/" + partition + "/" + policyName policyId := Hasher(fullName) r := strings.NewReplacer("/", "_", "-", "_", "+", "-") fmt.Println("Policy Id: ", r.Replace(policyId)) }
Manage the imported policy¶
Run the following commands to:
Initialize the Terraform Project.
Import the current WAF policy into your state.
Set the JSON WAF Policy as your new baseline.
Configure the lifecycle of your WAF Policy.
foo@bar:~$ terraform init
Initializing the backend...
Initializing provider plugins...
[...]
Terraform has been successfully initialized!
foo@bar:~$ terraform import bigip_waf_policy.this EdchwjSqo9cFtYP-iWUJmw
bigip_waf_policy.this: Importing from ID "EdchwjSqo9cFtYP-iWUJmw"...
bigip_waf_policy.this: Import prepared!
Prepared bigip_waf_policy for import
bigip_waf_policy.this: Refreshing state... [id=EdchwjSqo9cFtYP-iWUJmw]
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' > importedWAFPolicy.json foo@bar:~$ terraform show -no-color # bigip_waf_policy.this: resource "bigip_waf_policy" "this" { application_language = "utf-8" id = "EdchwjSqo9cFtYP-iWUJmw" name = "scenario2" partition = "Common" policy_export_json = jsonencode( { [...] } ) policy_id = "EdchwjSqo9cFtYP-iWUJmw" template_name = "POLICY_TEMPLATE_FUNDAMENTAL" type = "security" }
Using the collected data from the Terraform import, you can now update your main.tf file:
resource "bigip_waf_policy" "this" { application_language = "utf-8" name = "scenario2" partition = "Common" policy_id = "EdchwjSqo9cFtYP-iWUJmw" template_name = "POLICY_TEMPLATE_FUNDAMENTAL" type = "security" policy_import_json = file("${path.module}/importedWAFPolicy.json") }
Note
The
policy_export_json
argument was replaced withpolicy_import_json
, pointing to the imported WAF Policy JSON file.Plan and apply your new project.
foo@bar:~$ terraform plan -out scenario2 bigip_waf_policy.this: Refreshing state... [id=EdchwjSqo9cFtYP-iWUJmw] 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: scenario2 To perform exactly these actions, run the following command to apply: terraform apply "scenario2" foo@bar:~$ terraform apply "scenario2" bigip_waf_policy.this: Modifying... [id=EdchwjSqo9cFtYP-iWUJmw] 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 = "{[...]}"`
Policy lifecycle management¶
Manage your WAF Policy as done in Scenario #1: Create a WAF Policy.
You can 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" "this" { [...] parameters = [data.bigip_waf_entity_parameter.P1.json] }
foo@bar:~$ terraform plan -out scenario2 foo@bar:~$ terraform apply "scenario2"
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" "this" { [...] urls = [data.bigip_waf_entity_url.U1.json, data.bigip_waf_entity_url.U2.json] }
Run the plan:
foo@bar:~$ terraform plan -out scenario2 foo@bar:~$ terraform apply "scenario2"
Define attack signatures
Create a signatures.tf file:
data "bigip_waf_signatures" "S1" { signature_id = 200104004 description = "Java Code Execution" enabled = true perform_staging = true } data "bigip_waf_signatures" "S2" { 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" "this" { [...] signatures = [data.bigip_waf_signatures.S1.json, data.bigip_waf_signatures.S2.json] }
Run the plan:
foo@bar:~$ terraform plan -out scenario2 foo@bar:~$ terraform apply "scenario2"
What’s Next?