Managing AWS WAF rules with Terraform for common attack patterns
AWS WAF provides a practical control layer for applications running behind CloudFront, Application Load Balancers, API Gateway, and other supported services. Terraform makes that control repeatable: rules can be reviewed in pull requests, promoted through environments, and recreated without relying on manual console changes.
A useful design starts with recognisable attack patterns rather than a long list of isolated signatures. SQL injection, cross-site scripting, malicious IP addresses, excessive request rates, and suspicious managed-rule findings are common priorities for Australian organisations operating public-facing services in AWS.
Choose the right WAF scope
AWS WAF has two scopes: REGIONAL and CLOUDFRONT. Regional web ACLs are used with resources such as Application Load Balancers and regional API Gateway endpoints. CloudFront web ACLs are global and must be created in the AWS US East (N. Virginia) region, even when the application is serving customers from Sydney or Melbourne.
The scope should match the first useful inspection point. CloudFront is often preferable when an application has a global audience or needs filtering before traffic reaches the origin. An ALB association is simpler for a regional workload, and it can suit an internal platform exposed through a controlled network path.
resource "aws_wafv2_web_acl" "public" {
name = "${var.environment}-public-acl"
scope = "REGIONAL"
default_action {
allow {}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${var.environment}-public-waf"
sampled_requests_enabled = true
}
}
Add AWS managed rule groups
AWS Managed Rules provide maintained protections for common vulnerabilities without requiring a team to write every statement from scratch. The Core Rule Set covers patterns associated with common web exploits, while the Known Bad Inputs group targets malformed or suspicious request values.
Managed rule groups can produce false positives when an application accepts unusual JSON, encoded parameters, or administrator-style payloads. Set priorities explicitly and use rule-group overrides when a known rule is too aggressive, rather than disabling an entire protection set.
rule {
name = "common-protections"
priority = 10
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesCommonRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "common-protections"
sampled_requests_enabled = true
}
}
Handle SQL injection and XSS
SQL injection and cross-site scripting rules can be defined with AWS WAF managed groups or targeted statements. Managed groups are usually the better baseline, while custom rules are useful for a specific endpoint, parameter, or application behaviour that the default groups do not understand.
A custom rule should be narrow. Matching every query string for a pattern such as select can block legitimate searches and reporting requests. Prefer inspection of known parameters, JSON bodies, or URI paths, and validate the behaviour in Count mode before switching to Block.
rule {
name = "protect-login-path"
priority = 20
action {
block {}
}
statement {
and_statement {
statement {
byte_match_statement {
field_to_match {
uri_path {}
}
positional_constraint = "STARTS_WITH"
search_string = "/login"
text_transformation {
priority = 0
type = "LOWERCASE"
}
}
}
statement {
sqli_match_statement {
field_to_match {
body {}
}
text_transformation {
priority = 0
type = "HTML_ENTITY_DECODE"
}
}
}
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "login-sqli"
sampled_requests_enabled = true
}
}
Control abusive request rates
Rate-based rules help limit credential stuffing, scraping, denial-of-service attempts, and poorly behaved clients. The limit is evaluated over a rolling five-minute period, so it should reflect real application traffic rather than an arbitrary low number.
A public API used by customers in Perth, Brisbane, or regional New South Wales may have different traffic patterns from an internal administration portal. Start with Count mode, examine CloudWatch metrics, and set a limit that protects the service without penalising mobile networks or carrier-grade NAT users who share an address.
rule {
name = "rate-limit-addresses"
priority = 30
action {
block {}
}
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "rate-limit-addresses"
sampled_requests_enabled = true
}
}
Block known malicious sources
The Amazon IP reputation list and anonymous IP list can reduce noise from botnets, scanners, VPN endpoints, and other suspicious infrastructure. These rules are useful at the edge, though they should not replace authentication, patching, secure headers, or application-level validation.
For Australian businesses, security monitoring should fit existing Essential Eight practices and incident response procedures. WAF logs may also contain IP addresses, paths, and request fragments that are personal information or operationally sensitive under the Privacy Act. Define retention, access, and redaction policies before enabling full request logging.
Connect the web ACL to infrastructure
The web ACL is ineffective until it is associated with a protected resource. For an ALB, Terraform uses aws_wafv2_web_acl_association. CloudFront takes the web ACL ARN through the distribution configuration, and API Gateway regional deployments can use the same association resource.
Keep the association in the same Terraform stack as the load balancer where practical. If serverless endpoints are part of the platform, a related Lambda Function URLs guide can help clarify how those endpoints fit into an AWS design, although AWS WAF support and the available inspection path should be checked for the chosen architecture.
resource "aws_wafv2_web_acl_association" "alb" {
resource_arn = aws_lb.application.arn
web_acl_arn = aws_wafv2_web_acl.public.arn
}
Test changes through Terraform workflows
Use variables for thresholds, environment names, and rule actions so development, staging, and production can have controlled differences. A practical workflow runs terraform fmt, validation, a security scan, and terraform plan in CI before applying changes through an approved pipeline. Store state remotely with locking and restrict access to the state bucket.
Review sampled requests and CloudWatch metrics after deployment. A rule that blocks legitimate traffic often reveals itself through a sudden change in application errors, login failures, or support tickets. Count mode, scoped exclusions, and temporary IP allow lists provide safer options than removing protection entirely.
For teams operating in Australian time zones, schedule disruptive rule changes during a documented maintenance window in AEST or AEDT and record the corresponding UTC time in change notes. This makes incident correlation easier across AWS logs, Melbourne or Sydney operations teams, and offshore support providers.