Deploying Next-Gen WAF with the Signal Sciences Terraform provider

Learn how to deploy Fastly's Next-Gen WAF using the Signal Sciences Terraform provider. This guide appliese to Next-Gen WAF customers who cannot access the WAF using the Fastly control panel.

IMPORTANT: This feature is only available to Next-Gen WAF customers who cannot access the WAF using the Fastly control panel. If you can access the WAF in the Fastly control panel, refer to the Deploying Next-Gen WAF with the Fastly Terraform Provider tutorial instead.

This tutorial guides you through deploying Fastly's Next-Gen Web Application Firewall (Next-Gen WAF) for web and API endpoint security using the Edge Deployment method, which allows you to add an edge security service onto our Edge Cloud Platform without needing to make any modifications to your own hosting environment.

You will use the following Terraform providers:

Prerequisites

Before deploying the Next-Gen WAF, ensure you have the following:

1. Configure Terraform providers

Ensure Terraform 0.13+ is configured with the required providers for Fastly:

providers.tf
Terraform HCL
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
terraform {
required_providers {
fastly = {
source = "fastly/fastly"
version = ">= 5.7.1"
}
sigsci = {
source = "signalsciences/sigsci"
version = ">= 3.0.0"
}
http = {
source = "hashicorp/http"
}
}
}

2. Define variables

Declare the necessary variables and resources for the Fastly Edge VCL configuration, Next-Gen WAF settings, and dynamic snippets. This includes specifying domain names, backend hostnames, and API keys.

variables.tf
Terraform HCL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
variable "FASTLY_API_KEY" {
type = string
description = "This is the API key for the Fastly VCL edge configuration."
}
variable "USER_VCL_SERVICE_DOMAIN_NAME" {
type = string
description = "Frontend domain for your service."
default = "ngwaf-tf-demo.global.ssl.fastly.net"
}
variable "USER_VCL_SERVICE_BACKEND_HOSTNAME" {
type = string
description = "hostname used for backend."
default = "http-me.fastly.dev"
}
variables.tf
Terraform HCL
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
variable "NGWAF_CORP" {
type = string
description = "Corp name for NGWAF"
}
variable "NGWAF_SITE" {
type = string
description = "Site name for NGWAF"
}
variable "NGWAF_EMAIL" {
type = string
description = "Email address associated with the token for the NGWAF API."
}
variable "NGWAF_TOKEN" {
type = string
description = "Secret token for the NGWAF API."
sensitive = true
}

3. Set values for variables

The values for the declared variables must be available to the environment where Terraform is running following HashiCorp's guidance for managing variables.

4. Update the Fastly VCL service

Before linking the Next-Gen WAF edge deployment to the VCL service, you must add placeholders for dynamic snippets and a dictionary that will be used by the Next-Gen WAF integration. If the configurations are not added by Terraform, then Terraform will attempt to remove or replace the settings needed for the Next-Gen WAF Edge implementation. This behavior exists because the Next-Gen WAF Edge implementation uses the Terraform provider to make updates which impact the resources defined by the Fastly provider. Populating the dictionary and dynamic snippets with the desired values for the Next-Gen WAF edge deployment will be handled via the Terraform provider.

The dynamic snippets are simply commented VCL and act as a placeholder for the modifications that will occur via the Next-Gen WAF edge deployment. It is worth noting that both the dictionary and dynamic snippets are versionless. This means when modifications are made (even in subsequent service versions), those modifications will persist.

The priority of the snippets ngwaf_config_miss and ngwaf_config_pass are intentionally high, to avoid conflicts with any existing VCL logic.

main.tf
Terraform HCL
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
resource "fastly_service_dynamic_snippet_content" "ngwaf_config_init" {
for_each = {
for d in fastly_service_vcl.frontend-vcl-service.dynamicsnippet : d.name => d if d.name == "ngwaf_config_init"
}
service_id = fastly_service_vcl.frontend-vcl-service.id
snippet_id = each.value.snippet_id
content = "### Fastly managed ngwaf_config_init"
manage_snippets = false
}
resource "fastly_service_dynamic_snippet_content" "ngwaf_config_miss" {
for_each = {
for d in fastly_service_vcl.frontend-vcl-service.dynamicsnippet : d.name => d if d.name == "ngwaf_config_miss"
}
service_id = fastly_service_vcl.frontend-vcl-service.id
snippet_id = each.value.snippet_id
content = "### Fastly managed ngwaf_config_miss"
manage_snippets = false
}
resource "fastly_service_dynamic_snippet_content" "ngwaf_config_pass" {
for_each = {
for d in fastly_service_vcl.frontend-vcl-service.dynamicsnippet : d.name => d if d.name == "ngwaf_config_pass"
}
service_id = fastly_service_vcl.frontend-vcl-service.id
snippet_id = each.value.snippet_id
content = "### Fastly managed ngwaf_config_pass"
manage_snippets = false
}
resource "fastly_service_dynamic_snippet_content" "ngwaf_config_deliver" {
for_each = {
for d in fastly_service_vcl.frontend-vcl-service.dynamicsnippet : d.name => d if d.name == "ngwaf_config_deliver"
}
service_id = fastly_service_vcl.frontend-vcl-service.id
snippet_id = each.value.snippet_id
content = "### Fastly managed ngwaf_config_deliver"
manage_snippets = false
}

5. Integrate the Next-Gen WAF Edge deployment

Use the Signal Sciences provider to create the Next-Gen WAF Edge Service and link it to the Fastly VCL service. This step involves setting up a dictionary and updating dynamic snippets maintained by Fastly.

NOTE: The updated dynamic snippets will not be overwritten by subsequent terraform updates because of the manage_snippets = false setting in the dynamic snippet Terraform configuration. If manage_snippets is not set to false, then the dynamic snippets will be overwritten and traffic for your service will not be protected by the edge Next-Gen WAF deployment.

main.tf
Terraform HCL
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
provider "sigsci" {
corp = var.NGWAF_CORP
email = var.NGWAF_EMAIL
auth_token = var.NGWAF_TOKEN
fastly_api_key = var.FASTLY_API_KEY
}
resource "sigsci_edge_deployment" "ngwaf_edge_site_service" {
# https://registry.terraform.io/providers/signalsciences/sigsci/latest/docs/resources/edge_deployment
site_short_name = sigsci_site.ngwaf_edge_site.short_name
}
resource "sigsci_edge_deployment_service" "ngwaf_edge_service_link" {
# https://registry.terraform.io/providers/signalsciences/sigsci/latest/docs/resources/edge_deployment_service
site_short_name = sigsci_site.ngwaf_edge_site.short_name
fastly_sid = fastly_service_vcl.frontend-vcl-service.id
activate_version = true
percent_enabled = 100
depends_on = [
sigsci_edge_deployment.ngwaf_edge_site_service,
fastly_service_vcl.frontend-vcl-service,
fastly_service_dynamic_snippet_content.ngwaf_config_init,
fastly_service_dynamic_snippet_content.ngwaf_config_miss,
fastly_service_dynamic_snippet_content.ngwaf_config_pass,
fastly_service_dynamic_snippet_content.ngwaf_config_deliver,
]
}

Additionally, if you don't have dynamic backends enabled, you need to add the following:

main.tf
Terraform HCL
132
133
134
135
136
137
138
139
140
resource "sigsci_edge_deployment_service_backend" "example" {
site_short_name = sigsci_site.ngwaf_edge_site.short_name
fastly_sid = fastly_service_vcl.frontend-vcl-service.id
fastly_service_vcl_active_version = fastly_service_vcl.frontend-vcl-service.active_version
depends_on = [
sigsci_edge_deployment_service.ngwaf_edge_service_link,
]
}

6. Apply configuration

Apply the Terraform configuration using the following command.

terraform apply -parallelism=1

-parallelism=1 is required based on guidance from the Signal Sciences Terraform provider. In case of errors…

When the configuration is applied, the dynamic snippets will be added in a VCL version. The Signal Sciences provider will then do the following:

  1. Clone the existing active configuration.
  2. Populate the dynamic snippets and Dictionary with the values needed for the Next-Gen WAF integration.
  3. Activate the new version.

HINT: Your local Terraform state for the VCL service won't reflect this newly incremented version of the VCL service. Run terraform apply -parallelism=1 again in order to match the local state to the remote state. This terraform apply should not make any changes to the VCL service. After a successful run, you should see outputs like the following:

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
Outputs:
live_waf_love_output = <<EOT
#### Click the URL to go to the Fastly VCL service ####
https://cfg.fastly.com/LINKEDSERVICEID
#### Click the URL to go to the Fastly NGWAF service ####
https://dashboard.signalsciences.net/corps/my_corp_name/sites/my_site_name
#### Send a test request with curl. ####
curl -i "https://devhub-ngwaf-terraform-tutorial.global.ssl.fastly.net/anything/whydopirates?likeurls=theargs" -d foo=bar
#### Send a test as traversal with curl. ####
curl -i "https://devhub-ngwaf-terraform-tutorial.global.ssl.fastly.net/anything/myattackreq?i=../../../../etc/passwd" -d foo=bar
#### Send a test as XSS with curl. ####
curl -i "https://devhub-ngwaf-terraform-tutorial.global.ssl.fastly.net/anything/myattackreq?foo=%3Cscript%3E" -d foo=bar
#### Troubleshoot the logging configuration if necessary. ####
https://www.fastly.com/documentation/guides/integrations/streaming-logs/setting-up-remote-log-streaming/#troubleshooting-common-logging-errors
curl https://api.fastly.com/service/OuEbVB7UoymNTqI9ghCpE5/logging_status -H fastly-key:$FASTLY_API_TOKEN
EOT
response_body = [
"LINKEDSERVICEID",
]

Deployment considerations

Different designs using Terraform will require different approaches. The following sections contain a few considerations.

Deploying Next-Gen WAF edge to a new VCL service

For new implementations, you may use the complete Terraform implementation. When running the command terraform apply -parallelism=1, the implicit dependencies and the depends_on blocks within the resources ensure that the resources are created in the correct order.

Deploying Next-Gen WAF edge to an existing VCL service

The above methodology can work for an existing VCL service as well. It's very important to follow the guidance for updating the Fastly VCL service which makes Terraform aware of the dynamic snippets and dictionary. This configuration must occur before using the sigsci_edge_deployment_service Terraform resource. Otherwise, the dynamic snippets will be overwritten or deleted by subsequent terraform apply runs. For more information on the manage_snippets false configuration, please see our Fastly Terraform provider documentation for the resource fastly_service_dynamic_snippet_content.

You may complete the Next-Gen WAF edge implementation without sending traffic to the WAF. This can be helpful to test or gradually ramp traffic to the WAF edge implementation. The Edge_Security Dictionary may also be set to the value 0 within the Terraform resource sigsci_edge_deployment_service using the percent_enabled field. Our Traffic Ramping documentation has details for the percent_enabled field.

Deploying Next-Gen WAF edge to an existing Next-Gen WAF site

If you already have a Next-Gen WAF site you wish to use with the Next-Gen WAF edge implementation, then you may remove the Terraform resource block sigsci_site:

main.tf
Terraform HCL
142
143
144
145
146
147
148
resource "sigsci_site" "ngwaf_edge_site" {
short_name = var.NGWAF_SITE
display_name = var.NGWAF_SITE
block_duration_seconds = 86400
agent_anon_mode = ""
agent_level = "log"
}

You must then update all Terraform resources that depend on the sigsci_site resource, by replacing all references to sigsci_site.ngwaf_edge_site.short_name with the value var.NGWAF_SITE.

Optional: Identifying Fastly Delivery services linked with Next-Gen WAF edge deployments

Terraform can provide helpful outputs when doing a deployment. The example below shows you how to identify different Delivery services linked to a Next-Gen WAF edge deployment.

main.tf
Terraform HCL
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
provider "http" {}
data "http" "linked_fastly_services" {
url = "https://dashboard.signalsciences.net/api/v0/corps/${var.NGWAF_CORP}/sites/${var.NGWAF_SITE}/edgeDeployment"
request_headers = {
x-api-user = var.NGWAF_EMAIL
x-api-token = var.NGWAF_TOKEN
Content-Type = "application/json"
}
}
output "response_body" {
value = [for item in jsondecode(data.http.linked_fastly_services.response_body)["ServicesAttached"] : item.id]
}

Full reference implementation

The fastly/ngwaf-terraform-edge-deploy repository closely follows the recommendations in this tutorial.