Using Next-Gen WAF in Compute
Pass requests to Fastly's Next-Gen Web Application Firewall (Next-Gen WAF) from Compute code and make decisions based on the analysis response.
Prerequisites
The Next-Gen WAF is disabled by default. To purchase and enable the product for your Fastly account, contact sales@fastly.com. Once enabled, users assigned the role of superuser or engineer can enable the Next-Gen WAF for your Compute services.
Instructions
IMPORTANT: This tutorial assumes that you already have the Fastly CLI installed. If you are new to the platform, check out our guidance on getting started, which includes CLI installation instructions.
Initialize a project
If you haven't already created a Rust-based Compute project, run fastly compute init in a new directory in your terminal and follow the prompts to provision a new service using the empty Rust starter kit:
$ mkdir my-ngwaf-app && cd my-ngwaf-app$ fastly compute init
Creating a new Compute project.
Press ^C at any time to quit.
Name: [my-ngwaf-app]Description: A low quality image placeholder (LQIP) generator, at the edge.Author: My NameLanguage:[1] Rust[2] JavaScript[4] Other ('bring your own' Wasm binary)Choose option: [1]Starter kit:[1] Default starter for Rust A basic starter kit that demonstrates routing, simple synthetic responses and overriding caching rules. https://github.com/fastly/compute-starter-kit-rust-default[2] Empty starter for Rust An empty starter kit project template. https://github.com/fastly/compute-starter-kit-rust-empty
Choose option or paste git URL: [2]
After the command has completed, you'll have some new files and folders in the working directory.
Configure a backend
Your Compute service needs a backend from which it can load your website. For this tutorial, any backend will do, so we'll use http-me.glitch.me
, a backend that returns predictable HTTP responses for development and testing purposes. Add the following lines to the fastly.toml
file to inform the CLI that you want to create this backend when you deploy the application later:
[setup] [setup.backends] [setup.backends.content_backend] address = "http-me.glitch.me" port = 443
HINT: The fastly.toml
file specifies configuration related to a variety of resources, including config stores and logging endpoints. Check out our reference documentation about this package manifest format to learn more.
Configure the NGWAF inspector
To inspect requests, the Next-Gen WAF client must be configured with your corp (also known as account) and site (also known as workspace).
The best way to store configuration data for Compute services is using config stores, which allow you to share that data across services and update it without redeploying your service.
You can specify the requirement for a config store named ngwaf
in the fastly.toml
file, and the Fastly CLI will prompt you to create the store and populate it with values when you deploy the service for the first time. To do this, add the following lines to the fastly.toml
file in the [setup]
section:
[setup.config_stores] [setup.config_stores.ngwaf] description = "Next-gen WAF configuration" [setup.config_stores.ngwaf.items] [setup.config_stores.ngwaf.items.corp] [setup.config_stores.ngwaf.items.site]
This allows you to open the config store in your Rust code and read the corp (account) and site (workspace) values. Add the following code to the top of the request handler in your src/main.rs
file:
let ngwaf_config = fastly::config_store::ConfigStore::open("ngwaf"); let corp_name = ngwaf_config .get("corp") .expect("no `corp` present in config"); let site_name = ngwaf_config .get("site") .expect("no `site` present in config");
Next, initialize the Next-Gen WAF client with the corp (account) and site (workspace) values. Add the following lines below the config code that you just added:
let (req_handle, req_body) = req.into_handles(); let req_body = req_body.unwrap_or_else(|| BodyHandle::new()); let config = InspectConfig::new(&req_handle, &req_body) .corp(corp_name) .workspace(site_name);
Inspect the request and handle the verdict
The Next-Gen WAF is now available to inspect requests. The inspect
function returns a verdict that your code can use to decide how to handle the request. Add the following code to inspect the request and forward it to the origin only if the verdict is to allow the request:
match inspect(config) { Ok(resp) => match resp.verdict() { InspectVerdict::Block => Ok(Response::from_status(StatusCode::NOT_ACCEPTABLE)), InspectVerdict::Allow => { Ok(Request::from_handles(req_handle, Some(req_body)).send("content_backend")?) }, InspectVerdict::Unauthorized => { panic!("The service is not authorized to inspect the request") }, _ => Ok(Response::from_status(StatusCode::INTERNAL_SERVER_ERROR) .with_body("Unable to inspect request")), }, Err(err) => { let msg = format!("Invalid request: {err:?}"); Ok(Response::from_status(StatusCode::BAD_REQUEST).with_body(msg)) } }
Your code is ready! You can now deploy the service.
Deploy the service
To deploy the service, run the following command. Make sure to have your Next-Gen WAF corp (account) and site (workspace) names available, as you'll be prompted to enter them here:
$ fastly compute publish✓ Verifying fastly.toml✓ Identifying package name✓ Identifying toolchain✓ Running [scripts.build]✓ Creating package archive
SUCCESS: Built package (pkg/fastly-compute-project.tar.gz)
✓ Verifying fastly.toml
There is no Fastly service associated with this package. To connect to an existing service add the Service ID to the fastly.tomlfile, otherwise follow the prompts to create a service now.
Press ^C at any time to quit.
INFO: Processing of the fastly.toml [setup] configuration happens only when there is no existing service. Once aservice is created, any further changes to the service or its resources must be made manually.
Create new service: [y/N] y
Service name: [fastly-compute-project]
✓ Creating service
Domain: [annually-polite-akita.edgecompute.app]
Configure a backend called 'content_backend'
Hostname or IP address: [http-me.glitch.me]Port: [443]
Configuring config store 'ngwaf'Next-gen WAF configuration
Create a config store key called 'corp'
Value: [example] my-corp-name
Create a config store key called 'site'
Value: [example] my-site-name
✓ Creating domain 'annually-polite-akita.edgecompute.app'✓ Creating backend 'content_backend' (host: http-me.glitch.me, port: 443)✓ Creating config store 'ngwaf'✓ Creating config store item 'corp'✓ Creating config store item 'site'✓ Creating resource link between service and config store 'ngwaf'...✓ Uploading package✓ Activating service (version 1)✓ Checking service availability (status: 200)
Manage this service at: https://manage.fastly.com/configure/services/Tav180DsKiePBJ1MTb0zK2
View this service at: https://annually-polite-akita.edgecompute.app
SUCCESS: Deployed package (service Tav180DsKiePBJ1MTb0zK2, version 1)
Your service is now deployed, but Next-Gen WAF is not yet linked to the service. Follow the instructions in the Edge WAF deployment tutorial to set up the WAF deployment for the newly-created Compute service.
Once this is complete, visit the link in the fastly compute publish
output to view the service in your browser.
Test the NGWAF
Although visiting your service using your web browser will cause the request to be logged on the Next-Gen WAF dashboard, it is also helpful to be able to test that the inspection responses from the WAF are being handled correctly by your code. A great way to do this is with attack tooling, which you can try by following the Testing with attack tooling guide.