Scenario #1: Create a WAF Policy¶
This lab describes how to create a new F5 BIG-IP Advanced WAF Policy from scratch and manage some entities additions.
Pre-requisites¶
F5 BIG-IP version 16.1 or newer
Credentials with REST API access
On Terraform:
Using F5 BIG-IP provider version 1.15.0 or newer
Using Hashicorp versions as described in the Releases and versioning topic.
Create a Policy¶
Create 3 files:
variables.tf
inputs.auto.tfvars
main.tf
1variable bigip {} 2variable username {} 3variable password {}
1bigip = "10.1.1.9:443" 2username = "admin" 3password = "yYyYyYy"
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 name = "scenario1" 17 partition = "Common" 18 template_name = "POLICY_TEMPLATE_RAPID_DEPLOYMENT" 19 application_language = "utf-8" 20 enforcement_mode = "blocking" 21 server_technologies = ["Apache Tomcat", "MySQL", "Unix/Linux"] 22}
Run the project:
foo@bar:~$ terraform init Initializing the backend... Initializing provider plugins... - Finding f5networks/bigip versions matching "1.14.0"... - Installing f5networks/bigip v1.14.0... - Installed f5networks/bigip v1.14.0 (signed by a HashiCorp partner, key ID 0F284A6527D73A63) Partner and community providers are signed by their developers. To learn more about provider signing, read about it here: |awaf_terraform| Terraform has created a lock file ``.terraform.lock.hcl`` to record the provider selections it made above. Include this file in your version control repository, so that Terraform can guarantee to make the same selections by default when you run ``terraform init`` in the future. Terraform has been successfully initialized! You may now begin working with Terraform. Try running ``terraform plan`` to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary. foo@bar:~$ terraform plan -out scenario1 Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # bigip_waf_policy.this will be created + resource "bigip_waf_policy" "this" { + application_language = "utf-8" + case_insensitive = false + enable_passivemode = false + enforcement_mode = "blocking" + id = (known after apply) + name = "/Common/scenario1" + policy_export_json = (known after apply) + policy_id = (known after apply) + server_technologies = [ + "MySQL", + "Unix/Linux", + "MongoDB", ] + template_name = "POLICY_TEMPLATE_RAPID_DEPLOYMENT" + type = "security" } Plan: 1 to add, 0 to change, 0 to destroy. ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Saved the plan to: scenario1 To perform exactly these actions, run the following command to apply: terraform apply "scenario1" foo@bar:~$ terraform apply "scenario1" bigip_waf_policy.this: Creating... bigip_waf_policy.this: Still creating... [10s elapsed] bigip_waf_policy.this: Creation complete after 17s [id=41UMLL7yDtzoa0000Wimzw] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Your WAF Policy might evolve over time, so you can add entities, manage attack signature exceptions, and other similar modifications.
Manage Policy lifecycle
This section describes adding server technology into your WAF policy and managing parameter and signature changes over the lifecycle of your policy.
Manage Server Technologies
Add a MongoDB server technology into your WAF Policy. For the allowed values for server technologies, consult the Declarative WAF API documentation.
Edit the
main.tf
file:1resource "bigip_waf_policy" "this" { 2 name = "localS1" 3 partition = "Common" 4 template_name = "POLICY_TEMPLATE_RAPID_DEPLOYMENT" 5 application_language = "utf-8" 6 enforcement_mode = "blocking" 7 server_technologies = ["Apache Tomcat", "MySQL", "Unix/Linux", "MongoDB"] 8}
Manage parameters
Create a
parameters.tf
file:1data "bigip_waf_entity_parameter" "P1" { 2 name = "Parameter1" 3 type = "explicit" 4 data_type = "alpha-numeric" 5 perform_staging = true 6} 7 8data "bigip_waf_entity_parameter" "P2" { 9 name = "Parameter2" 10 type = "wildcard" 11 data_type = "alpha-numeric" 12 perform_staging = false 13 signature_overrides_disable = [200001494, 200001472] 14} 15 16data "bigip_waf_entity_parameter" "P3" { 17 name = "Parameter3" 18 type = "explicit" 19 data_type = "alpha-numeric" 20 is_header = true 21 sensitive_parameter = true 22 perform_staging = true 23}
Add references to these parameters in the
bigip_waf_policy
TF resource in themain.tf
file:1resource "bigip_waf_policy" "this" { 2 name = "scenario1" 3 partition = "Common" 4 template_name = "POLICY_TEMPLATE_RAPID_DEPLOYMENT" 5 application_language = "utf-8" 6 enforcement_mode = "blocking" 7 server_technologies = ["Apache Tomcat", "MySQL", "Unix/Linux", "MongoDB"] 8 parameters = [data.bigip_waf_entity_parameter.P1.json, data.bigip_waf_entity_parameter.P2.json, data.bigip_waf_entity_parameter.P3.json] 9}
Run the plan:
foo@bar:~$ terraform plan -out scenario1 [...] Plan: 0 to add, 1 to change, 0 to destroy. ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Saved the plan to: scenario1 To perform exactly these actions, run the following command to apply: terraform apply "scenario1" foo@bar:~$ terraform apply "scenario1" bigip_waf_policy.this: Modifying... [id=41UMLL7yDtzoa0000Wimzw] bigip_waf_policy.this: Still modifying... [id=41UMLL7yDtzoa0000Wimzw, 10s elapsed] bigip_waf_policy.this: Modifications complete after 17s [id=41UMLL7yDtzoa0000Wimzw] Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
Manage signatures
Create a separate signature definition file with 3 signatures:
S1 enables and perform staging on the 200010293 attack signature.
S2 disables the 200009024 attack signature.
S3 enables and enforce the 200014009 attack signature.
Create a
signatures.tf
file:1data "bigip_waf_signatures" "S1" { 2 signature_id = 200010293 3 description = "Java Code Execution" 4 enabled = true 5 perform_staging = true 6} 7 8data "bigip_waf_signatures" "S2" { 9 signature_id = 200009024 10 enabled = false 11} 12 13data "bigip_waf_signatures" "S3" { 14 signature_id = 200014009 15 description = "src http: (Header)" 16 enabled = true 17 perform_staging = false 18}
Add references to these attack signatures in the
bigip_waf_policy
TF resource in the main.tf file:resource "bigip_waf_policy" "this" { partition = "Common" name = "scenario1" template_name = "POLICY_TEMPLATE_RAPID_DEPLOYMENT" application_language = "utf-8" enforcement_mode = "blocking" server_technologies = ["Apache Tomcat", "MySQL", "Unix/Linux", "MongoDB"] parameters = [data.bigip_waf_entity_parameter.P1.json, data.bigip_waf_entity_parameter.P2.json, data.bigip_waf_entity_parameter.P3.json] signatures = [data.bigip_waf_signatures.S1.json, data.bigip_waf_signatures.S2.json, data.bigip_waf_signatures.S3.json] }
Run the plan:
foo@bar:~$ terraform plan -out scenario1 [...] # bigip_waf_policy.this will be updated in-place ~ resource "bigip_waf_policy" "this" { id = "tCwXEedPDS-S35Bl4TSU5w" name = "localS1" + signatures = [ + jsonencode( { + enabled = true + performStaging = true + signatureId = 200010293 } ), + jsonencode( { + performStaging = false + signatureId = 200009024 } ), + jsonencode( { + enabled = true + performStaging = false + signatureId = 200014009 } ), ] # (11 unchanged attributes hidden) } Plan: 0 to add, 1 to change, 0 to destroy. ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── Saved the plan to: scenario1 To perform exactly these actions, run the following command to apply: terraform apply "scenario1" foo@bar:~$ terraform apply "scenario1" bigip_waf_policy.this: Modifying... [id=41UMLL7yDtzoa0000Wimzw] bigip_waf_policy.this: Still modifying... [id=41UMLL7yDtzoa0000Wimzw, 10s elapsed] bigip_waf_policy.this: Modifications complete after 17s [id=41UMLL7yDtzoa0000Wimzw] Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
Use the following command to check the details on a specific attack signature:
$ terraform show -json | jq '.values.root_module.resources[] | select(.name == "S3")'
{ "address": "data.bigip_waf_signatures.S3", "mode": "data", "type": "bigip_waf_signatures", "name": "S3", "provider_name": "terraform.local/local/bigip", "schema_version": 0, "values": { "accuracy": "medium", "description": "Summary:\nThis event is generated when an attempt is made to abuse a web server functionality. This is a general detection signature (i.e. it is not specific to any web application).\n\nImpact:\nVary from information gathering to web server compromise.\n\nDetailed Information:\nAbuse of Functionality is an attack technique that uses a web site's own features and functionality to consume, defraud, or circumvents access controls mechanisms\n\nAffected Systems:\nAll systems.\n\nAttack Scenarios:\nThere are many possible.\n\nEase Of Attack:\nSimple to medium.\n\nFalse Positives:\nSome applications may accept valid input which matches these signatures.\n\nFalse Negatives:\nNone known.\n\nCorrective Action:\nEnsure the system is using an up to date version of the software and has had all vendor supplied patches applied. Utilize \"Positive Security Model\" by accepting only known types of input in web application.\n\nAdditional References:\nhttp://www.webappsec.org/projects/threat/classes/abuse_of_functionality.shtml\n\n", "enabled": true, "id": "200014009", "json": "{\"signatureId\":200014009,\"performStaging\":false,\"enabled\":true}", "name": "Unix \"cmd\" parameter execution attempt", "perform_staging": false, "risk": "high", "signature_id": 200014009, "system_signature_id": "GTK2ItJX6pnKHXBqiwtlxQ", "tag": null, "type": "request" }, "sensitive_values": {} }
Note
If you have multiple entities to manage, the entity lists in the bigip_waf_policy
can be difficult to use. In that case,
F5 recommends using Terraform HCL maps as presented in lab 4.
See also
F5 BIG-IP Terraform Provider official registry documentation.
Create a policy using an OpenAPI file¶
Create 3 files:
variables.tf
inputs.tfvars
main.tf
1variable bigip {} 2variable username {} 3variable password {}
1bigip = "10.1.1.9:443" 2username = "admin" 3password = "yYyYyYy"
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 = "scenario1.swagger" 18 template_name = "POLICY_TEMPLATE_API_SECURITY" 19 application_language = "utf-8" 20 enforcement_mode = "blocking" 21 server_technologies = ["MySQL", "Unix/Linux", "MongoDB"] 22 open_api_files = ["https://api.swaggerhub.com/apis/F5EMEASSA/API-Sentence/3.0.1"] 23 parameters = [data.bigip_waf_entity_parameter.P1.json, data.bigip_waf_entity_parameter.P2.json, data.bigip_waf_entity_parameter.P3.json] 24 signatures = [data.bigip_waf_signatures.S1.json, data.bigip_waf_signatures.S2.json]
Run the plan:
foo@bar:~$ terraform plan -out scenario1.swagger [...] # bigip_waf_policy.this must be replaced -/+ resource "bigip_waf_policy" "this" { ~ id = "41UMLL7yDtzoa0000Wimzw" -> (known after apply) ~ name = "scenario1" -> "scenario1-2.swagger" # forces replacement + open_api_files = [ + "https://api.swaggerhub.com/apis/F5EMEASSA/API-Sentence/3.0.1", ] ~ policy_export_json = jsonencode( { - applicationLanguage = "utf-8" - description = "FCH Testing WAF Policy from RDP Template" - enforcementMode = "blocking" - fullPath = "/Common/scenario1" - name = "scenario1" - parameters = [ - { - allowEmptyValue = true - allowRepeatedParameterName = true - attackSignaturesCheck = true - dataType = "alpha-numeric" - isHeader = true - level = "global" - name = "parameter3" - performStaging = true - sensitiveParameter = true - type = "explicit" - valueType = "user-input" }, - { - allowEmptyValue = true - allowRepeatedParameterName = true - attackSignaturesCheck = true - dataType = "alpha-numeric" - level = "global" - name = "Parameter2" - parameterLocation = "any" - signatureOverrides = [ - { - enabled = false - name = "\"style :expression (\" (Parameter)(1)" - signatureId = 200001494 }, ] - type = "wildcard" - valueType = "user-input" }, - { - allowEmptyValue = true - allowRepeatedParameterName = true - attackSignaturesCheck = true - dataType = "alpha-numeric" - level = "global" - name = "Parameter1" - parameterLocation = "any" - performStaging = true - type = "explicit" - valueType = "user-input" }, - { - allowEmptyValue = true - allowRepeatedParameterName = true - attackSignaturesCheck = true - level = "global" - name = "*" - parameterLocation = "any" - type = "wildcard" - valueType = "auto-detect" }, - { - allowEmptyValue = true - level = "global" - name = "__VIEWSTATE" - parameterLocation = "any" - type = "explicit" - valueType = "ignore" }, ] - server-technologies = [ - { - serverTechnologyName = "MongoDB" }, - { - serverTechnologyName = "MySQL" }, - { - serverTechnologyName = "Apache Tomcat" }, - { - serverTechnologyName = "Unix/Linux" }, ] - signature-sets = [ - { - alarm = true - block = true - learn = true - name = "Apache Tomcat Signatures (High/Medium Accuracy)" - signatureSet = { - filter = { - accuracyFilter = "ge" - accuracyValue = "medium" - hasCve = "all" - lastUpdatedFilter = "all" - riskFilter = "all" - riskValue = "all" - signatureType = "all" - tagFilter = "all" - userDefinedFilter = "all" } - systems = [ - { - name = "Apache Tomcat" }, ] - type = "filter-based" } }, - { - alarm = true - block = true - learn = true - name = "MongoDB Signatures (High/Medium Accuracy)" - signatureSet = { - filter = { - accuracyFilter = "ge" - accuracyValue = "medium" - hasCve = "all" - lastUpdatedFilter = "all" - riskFilter = "all" - riskValue = "all" - signatureType = "all" - tagFilter = "all" - userDefinedFilter = "all" } - systems = [ - { - name = "MongoDB" }, ] - type = "filter-based" } }, - { - alarm = true - block = true - learn = true - name = "Unix/Linux Signatures (High/Medium Accuracy)" - signatureSet = { - filter = { - accuracyFilter = "ge" - accuracyValue = "medium" - hasCve = "all" - lastUpdatedFilter = "all" - riskFilter = "all" - riskValue = "all" - signatureType = "all" - tagFilter = "all" - userDefinedFilter = "all" } - systems = [ - { - name = "Unix/Linux" }, ] - type = "filter-based" } }, - { - alarm = true - block = true - learn = true - name = "MySQL Signatures (High/Medium Accuracy)" - signatureSet = { - filter = { - accuracyFilter = "ge" - accuracyValue = "medium" - hasCve = "all" - lastUpdatedFilter = "all" - riskFilter = "all" - riskValue = "all" - signatureType = "all" - tagFilter = "all" - userDefinedFilter = "all" } - systems = [ - { - name = "MySQL" }, ] - type = "filter-based" } }, - { - alarm = true - block = true - learn = true - name = "Generic Detection Signatures (High/Medium Accuracy)" - signatureSet = { - filter = {} } }, ] - signature-settings = { - signatureStaging = true } - signatures = [ - { - enabled = true - performStaging = false - signatureId = "200014009" }, - { - enabled = true - performStaging = false - signatureId = "200009024" }, ] - template = { - name = "POLICY_TEMPLATE_RAPID_DEPLOYMENT" } - type = "security" - urls = [ - { - attackSignaturesCheck = true - isAllowed = true - method = "*" - name = "*" - protocol = "http" - type = "wildcard" }, - { - attackSignaturesCheck = true - isAllowed = true - method = "*" - name = "*" - protocol = "https" - type = "wildcard" }, ] } ) -> (known after apply) ~ policy_id = "41UMLL7yDtzoa0000Wimzw" -> (known after apply) ~ server_technologies = [ - "Apache Tomcat", "MySQL", # (2 unchanged elements hidden) ] ~ signatures = [ # (1 unchanged element hidden) jsonencode( { performStaging = false signatureId = 200009024 } ), - jsonencode( { - enabled = true - performStaging = false - signatureId = 200014009 } ), ] ~ template_name = "POLICY_TEMPLATE_RAPID_DEPLOYMENT" -> "POLICY_TEMPLATE_API_SECURITY" # forces replacement # (7 unchanged attributes hidden) } Plan: 1 to add, 0 to change, 1 to destroy. ─────────────────────────────────────────────────────────────────────────────── Saved the plan to: scenario1.swagger To perform exactly these actions, run the following command to apply: terraform apply "scenario1.swagger" foo@bar:~$ terraform apply "scenario1" bigip_waf_policy.this: Modifying... [id=41UMLL7yDtzoa0000Wimzw] bigip_waf_policy.this: Still modifying... [id=41UMLL7yDtzoa0000Wimzw, 10s elapsed] bigip_waf_policy.this: Modifications complete after 17s [id=41UMLL7yDtzoa0000Wimzw] Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
What’s Next?