How to implement rate limiting for an AppSync API

How to prevent single-source DoS attacks

Author's image
Tamás Sallai
1 min

AppSync rate limiting

Rate limiting is an effective mitigation strategy for some types of attacks. For example, when a single source does an enumeration attack to try to guess a valid ID, or downloading data en masse. And, of course, against denial-of-service attacks when an adversary tries to overload the service to deny access to legitimate traffic.

AppSync supports control over the incoming traffic with authorizers, resolvers, and directives in the schema, none of them capable of implementing rate limiting. But it supports WAF, the AWS-managed firewall solution, that has rules for denying access based on IP addresses, geolocation, and request rate.

Note that rate limiting is per-source, so it won't help against a distributed DoS attack, where the attack is coming from a lot of sources at once.

WAF config

To add a rate limiter to an AppSync API, first create a WAF Web ACL and configure a rule for it.

Then the rate-limiter rule:

WAF rules are JSON documents, so you can configure them by text:

{
	"Name": "rate-limit",
	"Priority": 1,
	"Statement": {
		"RateBasedStatement": {
			"Limit": 6000,
			"AggregateKeyType": "IP"
		}
	},
	"Action": {
		"Block": {}
	},
	"VisibilityConfig": {
		"SampledRequestsEnabled": false,
		"CloudWatchMetricsEnabled": false,
		"MetricName": "friendly-rule-metric-name"
	}
}

And to deploy this rule using Terraform:

resource "aws_wafv2_web_acl" "rate-limit" {
	rule {
		name     = "rate-limit"
		priority = 1

		action {
			block {}
		}

		statement {
			rate_based_statement {
				limit              = 6000
			}
		}

		visibility_config {
			cloudwatch_metrics_enabled = false
			metric_name                = "friendly-rule-metric-name"
			sampled_requests_enabled   = false
		}
	}
}

WAF rate limiting is based on a 5-minute window, so the number you specify is the number of allowed requests from a single source in any 5 minutes. Also, WAF supports combining different rules, so you can rate limit based on IP address or geolocation too. For example, you can have a "base country" where you define a higher rate limit and a lower one for everywhere else.

Associate with the API

The assocation is on AppSync's side:

With Terraform, you can use the aws_wafv2_web_acl_association resource to link the Web ACL and the API:

resource "aws_wafv2_web_acl_association" "appsync" {
	resource_arn = aws_appsync_graphql_api.appsync.arn
	web_acl_arn  = aws_wafv2_web_acl.rate-limit.arn
}

Having a "linking resource" comes with a nice property that any of the two resources can reference the other without creating a circular dependency.

Costs

WAF comes with its own pricing that is a combination of per-resource and per-request cost tags. Having Web ACLs and rules inside incur fixed costs even if nobody uses the API. Then the variable price tag adds to every request.

April 12, 2022
In this article