Back to blog

Follow and Subscribe

How to Deploy Fastly’s Next-Gen WAF in less than 10 minutes

Brooks Cunningham

Senior Security Strategist, Fastly

Getting started

Two of the main problems people encounter when trying to secure their web and API endpoints is that their security solution is complicated or difficult to maintain, and that the deployment is slow and painful. 

Enabling devops teams to speed policy and rule changes for application security threat mitigation (such as custom signals or rate limit rules) becomes increasingly important - especially in the face of a dynamic, evolving threat landscape. 

Speed and automation translate into a stronger security policy in the face of evolving web threats - teams can adapt more quickly with less reliance on human error to update rules to prevent attacks. As we’ll see in this blog an integrated approach that involves IaC (Infrastructure-as-Code) can help here.

Fastly’s Next-Gen WAF (NGWAF) solves both of these - that’s the great thing about being “next-gen!” It works out of the box to eliminate false positives without requiring rules or messing with Regex or any kind of tuning or maintenance. These are a number of reasons why Fastly’s Next Gen WAF is named a Customers’ Choice for five consecutive years by Gartner. Also, it can also be deployed quickly and easily. Below I’m going to demonstrate how fast and easy it is to create a new NGWAF Edge deployment using Terraform.

Terraform is continuing to grow in popularity as a  tool for deploying and managing IT infrastructure and makes it easier than ever to protect your web and API endpoints with our NGWAF as an Edge deployment. However, the guidance here may simply be used to easily provision the infrastructure and then set aside terraform. 

A quick note on terminology

Here are a few of the terms we’re going to be using and a brief definition of what they mean. If you want to learn more you can check out our online docs (https://docs.fastly.com/signalsciences/using-signal-sciences/corp-management/).

Deciding on the structure of your deployment

Two common customer questions are “Which NGWAF Site should I link to my edge integration?” and “Do I need to create a new NGWAF Site for the edge integration?” With NGWAF you can pick the structure that works best for your organization. You can easily use an existing Site if you prefer, or you create a new site for this specific deployment option. Here’s a great resource about how to design your NGWAF Edge Corp and Site structure if you want to learn more about those options, but the simplest way to get started is to deploy using an existing NGWAF Site.

Fastly provides everything you’ll need for this process:

  1. A Fastly Edge API key with permissions to create and manage services. https://docs.fastly.com/en/guides/using-api-tokens#creating-api-tokens 

  2. A NextGen WAF API key with Corp Admin permissions.

  3. A NextGen WAF Corp and Site. https://docs.fastly.com/signalsciences/using-signal-sciences/corp-management/ 

Deploying the Next-Gen WAF on the Edge

Here's a video that walks you through the whole process in 4 minutes, but keep reading for the Terraform configuration and more!

The following Terraform configuration should be used for the deployment.

# Terraform 0.13+ requires providers to be declared in a "required_providers" block
# https://registry.terraform.io/providers/fastly/fastly/latest/docs
terraform {
 required_providers {
   fastly = {
     source  = "fastly/fastly"
     version = ">= 3.0.4"
   }
   sigsci = {
     source = "signalsciences/sigsci"
     version = ">= 1.2.18"
   }
 }
}
# Fastly Edge VCL configuration
variable "FASTLY_API_KEY" {
   type        = string
   description = "This is API key for the Fastly VCL edge configuration."
}
#### VCL Service variables - Start
variable "USER_VCL_SERVICE_DOMAIN_NAME" {
 type = string
 description = "Frontend domain for your service. Try 'YOURNAME.global.ssl.fastly.net' to get up and running quickly."
 default = "brooks-ngwaf-tf-demo.global.ssl.fastly.net"
}
variable "USER_VCL_SERVICE_BACKEND_HOSTNAME" {
 type          = string
 description   = "hostname used for backend."
 default       = "http-me.glitch.me"
}
# Controls the percentage of traffic sent to NGWAF
variable "Edge_Security_dictionary" {
 type = string
 default = "Edge_Security"
}
variable "NGWAF_CORP" {
 type          = string
 description   = "Corp name for NGWAF"
}
variable "NGWAF_SITE" {
 type          = string
 description   = "Site name for NGWAF"
}
#### VCL Service variables - End
#### NGWAF variables - Start
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
}
#### NGWAF variables - End
# Configure the Fastly Provider
provider "fastly" {
 api_key = var.FASTLY_API_KEY
}
#### Fastly VCL Service - Start
resource "fastly_service_vcl" "frontend-vcl-service" {
 name = "Frontend VCL Service - NGWAF edge deploy"
 domain {
   name    = var.USER_VCL_SERVICE_DOMAIN_NAME
   comment = "Frontend VCL Service - NGWAF edge deploy"
 }
 backend {
   address = var.USER_VCL_SERVICE_BACKEND_HOSTNAME
   name = "vcl_service_origin_1"
   port    = 443
   use_ssl = true
   ssl_cert_hostname = var.USER_VCL_SERVICE_BACKEND_HOSTNAME
   ssl_sni_hostname = var.USER_VCL_SERVICE_BACKEND_HOSTNAME
   override_host = var.USER_VCL_SERVICE_BACKEND_HOSTNAME
 }
 #### NGWAF Dynamic Snippets - MANAGED BY FASTLY - Start
  dynamicsnippet {
    name     = "ngwaf_config_init"
    type     = "init"
    priority = 0
  }
  dynamicsnippet {
    name     = "ngwaf_config_miss"
    type     = "miss"
    priority = 9000
  }
  dynamicsnippet {
    name     = "ngwaf_config_pass"
    type     = "pass"
    priority = 9000
  }
  dynamicsnippet {
    name     = "ngwaf_config_deliver"
    type     = "deliver"
    priority = 9000
  }
 #### NGWAF Dynamic Snippets - MANAGED BY FASTLY - End
 dictionary {
   name       = var.Edge_Security_dictionary
 }
 lifecycle {
   ignore_changes = [
     product_enablement,
   ]
 }
 force_destroy = true
}
resource "fastly_service_dictionary_items" "edge_security_dictionary_items" {
 for_each = {
 for d in fastly_service_vcl.frontend-vcl-service.dictionary : d.name => d if d.name == var.Edge_Security_dictionary
 }
 service_id = fastly_service_vcl.frontend-vcl-service.id
 dictionary_id = each.value.dictionary_id
 items = {
   Enabled: "100"
 }
}
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
}
#### Fastly VCL Service - End
#### NGWAF Edge deploy - Start
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 = var.NGWAF_SITE
}
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 = var.NGWAF_SITE
 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_dictionary_items.edge_security_dictionary_items,
   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,
 ]
}
resource "sigsci_edge_deployment_service_backend" "ngwaf_edge_service_backend_sync" {
  site_short_name = var.NGWAF_SITE
  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,
  ]
}
#### NGWAF Edge deploy - End
output "love_laugh_live_ngwaf" {
  value = <<tfmultiline
  #### Click the URL to go to the service ####
  https://cfg.fastly.com/${fastly_service_vcl.frontend-vcl-service.id}
  #### Send a test request with curl. ####
  curl -i "https://${var.USER_VCL_SERVICE_DOMAIN_NAME}/anything/whydopirates?likeurls=theargs" -d foo=bar
  #### Send an test as cmd exe request with curl. ####
  curl -i "https://${var.USER_VCL_SERVICE_DOMAIN_NAME}/anything/myattackreq?i=../../../../etc/passwd'" -d foo=bar
  #### Troubleshoot the logging configuration if necessary. ####
  curl https://api.fastly.com/service/${fastly_service_vcl.frontend-vcl-service.id}/logging_status -H fastly-key:$FASTLY_API_KEY
  tfmultiline
 description = "Output hints on what to do next."
 depends_on = [
   sigsci_edge_deployment_service.ngwaf_edge_service_link
 ]
}

If you’ve got all the above requirements Fastly Edge API key, NGWAF API key, permissions, and NGWAF Corp /Site), then all you have to do is run `terraform apply` and send a request to test out the deployment for a new deployment. Fortunately, we have built the test request into Terraform as well (because we want this to be EASY for you!).

Now you can start using the Fastly NGWAF UI to manage your application security settings or continue using Terraform, same as you would with any other deployment option.

So what  is happening in the background?

The Signal Sciences Terraform provider is doing two things.

  1. Creating the NGWAF Edge Service

  2. Linking the NGWAF Edge Service to your VCL service

Linking  the VCL service and the NGWAF Edge Service does a few things. 

  • It will create an edge dictionary, 

  • Create dynamic snippets that Fastly will maintain

  • Synchronize the origins configured at the VCL service with the NGWAF Edge Service

When we first run `terraform apply`, the VCL service is created with 4 dynamic snippets. All of which are setting `managed = false` to indicate that those specific resources will be managed outside of terraform (https://registry.terraform.io/providers/fastly/fastly/latest/docs/resources/service_dynamic_snippet_content#manage_snippets). In this case, ‘outside of terraform’ means that Fastly will manage the snippets and make changes if necessary.

Congratulations!

It’s as simple as that, and your site is now protected. So you hopefully have a better understanding of how to provision a NGWAF edge deployment with new VCL services using Terraform — easy! Stay tuned for a future blog post for using Terraform with an existing Fastly service, and let us know if you have questions or feedback.