Web application firewalls (WAFs) are an essential security layer for any web application. They protect your applications from common attacks, such as SQL injection, cross-site scripting, and denial-of-service attacks.
Terraform is an infrastructure as code (IaC) tool that can be used to automate the deployment and management of WAFs. This makes it easy to deploy consistent and secure WAFs across all of your environments.
In this blog post, we will show you how to set up a WAF using Terraform. We will use the AWS WAF v2 service as an example, but the same principles can be applied to other WAFs.
Prerequisites
Before getting started, you will need to have the following prerequisites:
- A Terraform installation
- An AWS account with the necessary permissions to create and manage WAF resources
Creating a Terraform configuration
The first step is to create a Terraform configuration file. This file will define the resources that you want to create, such as the WAF and its associated rules.
Here is a simple example of a Terraform configuration for an AWS WAF v2:
#######################################
# --- Resources ----
#######################################
resource "aws_wafv2_web_acl" "waf" {
count = var.create ? 1 : 0
name = "${var.prefix}-${var.name}"
scope = var.scope
// default action
default_action {
allow {}
}
// AWSManagedRulesCommonRuleSet
rule {
name = "AWSManagedRulesCommonRuleSet"
priority = 10
override_action {
none {
}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesCommonRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesCommonRuleSetMetric"
sampled_requests_enabled = true
}
}
// AWSManagedRulesKnownBadInputsRuleSet
rule {
name = "AWSManagedRulesKnownBadInputsRuleSet"
priority = 20
override_action {
none {
}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesKnownBadInputsRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesKnownBadInputsRuleSetMetric"
sampled_requests_enabled = true
}
}
// AWSManagedRulesAmazonIpReputationList
rule {
name = "AWSManagedRulesAmazonIpReputationList"
priority = 30
override_action {
none {
}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesAmazonIpReputationList"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesAmazonIpReputationListMetric"
sampled_requests_enabled = true
}
}
// AWSManagedRulesAnonymousIpList
rule {
name = "AWSManagedRulesAnonymousIpList"
priority = 40
override_action {
none {
}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesAnonymousIpList"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesAnonymousIpListMetric"
sampled_requests_enabled = true
}
}
// AWSManagedRulesSQLiRuleSet
rule {
name = "AWSManagedRulesSQLiRuleSet"
priority = 50
override_action {
none {
}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesSQLiRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesSQLiRuleSetMetric"
sampled_requests_enabled = true
}
}
// AWSManagedRulesLinuxRuleSet
rule {
name = "AWSManagedRulesLinuxRuleSet"
priority = 60
override_action {
none {
}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesLinuxRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesLinuxRuleSetMetric"
sampled_requests_enabled = true
}
}
// AWSManagedRulesUnixRuleSet
rule {
name = "AWSManagedRulesUnixRuleSet"
priority = 70
override_action {
none {
}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesUnixRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "AWSManagedRulesUnixRuleSetMetric"
sampled_requests_enabled = true
}
}
tags = {
Name = "${var.prefix}-${var.name}"
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = var.metric_name
sampled_requests_enabled = true
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_wafv2_web_acl_logging_configuration" "api_server_waf_log" {
count = var.create ? 1 : 0
log_destination_configs = [aws_s3_bucket.logs.arn]
resource_arn = aws_wafv2_web_acl.waf[count.index].arn
}
resource "aws_s3_bucket" "logs" {
bucket = "aws-waf-logs-${var.prefix}-${var.name}"
force_destroy = true
tags = {
Name = "aws-waf-logs-${var.prefix}-${var.name}"
}
}
resource "aws_s3_bucket_acl" "acl" {
bucket = aws_s3_bucket.logs.id
acl = "private"
depends_on = [aws_s3_bucket_ownership_controls.acl_ownership]
}
resource "aws_s3_bucket_ownership_controls" "acl_ownership" {
bucket = aws_s3_bucket.logs.id
rule {
object_ownership = "ObjectWriter"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "sse_configuration" {
bucket = aws_s3_bucket.logs.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
resource "aws_s3_bucket_public_access_block" "public_access_block" {
bucket = aws_s3_bucket.logs.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
#######################################
# --- Variables ----
#######################################
variable "create" {
description = "Controls if waf should be created"
type = bool
}
variable "prefix" {
description = "The prefix of the resource name"
type = string
}
variable "name" {
description = "The name of the waf resource"
type = string
}
variable "scope" {
description = "The scope of the waf"
type = string
}
variable "metric_name" {
description = "The name of the metric"
type = string
}
#######################################
# --- Outputs ----
#######################################
output "waf_arn" {
value = length(aws_wafv2_web_acl.waf) > 0 ? aws_wafv2_web_acl.waf[0].arn : ""
description = "The arn of waf"
}
Deploying the WAF
Once you have created the Terraform configuration file, you can deploy the WAF by running the following command:
terraform apply
This will create the WAF and its associated resources in AWS.
Testing the WAF
Once the WAF has been deployed, you should test it to make sure that it is working properly. You can do this by sending a test request to your web application and verifying that the WAF blocks the request.
You can also use the AWS WAF console to test the WAF. To do this, go to the Web ACLs page and click on the name of your web ACL. Then, click on the Test tab and enter a test request.
Conclusion
In this blog post, we have shown you how to set up a WAF using Terraform. Terraform is a powerful tool that can be used to automate the deployment and management of WAFs. This makes it easy to deploy consistent and secure WAFs across all of your environments.
Top comments (0)