AWS AppSync is a fully managed service that allows users to implement Serverless GraphQL backends in the AWS cloud. With AppSync, you can connect to various data sources and scale your GraphQL backends according to your needs. Whether you are a beginner or expanding your existing APIs, safeguarding your endpoints to ensure security and high availability is always a priority.
We are excited to announce the integration of AWS AppSync with AWS WAF. AWS WAF is a web application firewall designed to protect APIs like AppSync GraphQL endpoints from common web exploits that can threaten availability, security, or consume excessive resources. AWS WAF enables you to get started quickly with Managed Rules that are automatically updated as new threats arise. You can also create customized rules, such as regular rules that block requests based on their origin and content, and rate-based rules that limit the number of requests per IP address over a specified timeframe.
In this article, we will guide you on how to use an AWS WAF Web Access Control List (Web ACL) to secure an AppSync API by implementing a rate-based rule to manage request traffic. We’ll also demonstrate how to use a regular rule to disable GraphQL introspection, which may be necessary due to specific organizational policies. This walkthrough can be applied to any AppSync API, and we will utilize the sample Event App API available in the AppSync Console wizard for this demonstration. You can easily deploy this API from the AppSync console by selecting Create API and choosing Event App in the Start from a sample project section.
Securing Your API with Rate-Based Rules
To begin, you’ll create a new web ACL with a rate-based rule that monitors the request rate from each originating IP address. This rule will activate an action for IPs that exceed a defined limit over a 5-minute duration. Once triggered, AWS WAF will apply the action to any further requests from the same IP until the request rate drops below the set limit.
Here are the steps to create a web ACL:
- Open the AWS WAF Console.
- Select Create web ACL.
- Enter “AppSync-First-ACL” for the Name.
- Choose Regional resources for Resource type.
- Select the same Region where your AppSync API is deployed.
- Click Next. You can skip associating an AWS resource at this stage; while you can click on Add AWS Resources and select your AppSync API, we will show you how to do this from the AppSync console in the next steps.
- In the Add rules and rule groups step, click Add rules and Add my own rules and rule groups.
- For Name, enter “Throttling-Rule.”
- Select Rate-based rule for Rule type.
- Enter “200” for Rate limit.
- Choose IP address in header for IP address to use for rate limiting.
- Click Add rule.
- Proceed by clicking Next until you reach Step 5: Review and create web ACL, then confirm your selections and click Create web ACL.
Once completed, navigate to the AWS AppSync Console in the same region. Select your API, toggle Enable AWS WAF on, and choose your ACL from the Web ACL dropdown. Click Save to link the ACL with your API.
Testing Your Secured AppSync API with AWS WAF
You’ve now established a Web ACL rate-based rule that activates after 200 requests are received from a specific source IP within a 5-minute window. Once this threshold is exceeded, subsequent requests from that IP are blocked until the rate falls below the limit.
To test, you can make a simple request to your API from a terminal using curl, replacing your API URL and API Key retrieved from the Settings section of your AppSync API in the console:
$ export APPSYNC_API_URL=<APPSYNC API URL> # insert your own API URL
$ export APPSYNC_API_KEY=<APPSYNC API KEY> # insert your own API KEY
$ curl -XPOST $APPSYNC_API_URL -H "Content-Type:application/graphql" -H "x-api-key:$APPSYNC_API_KEY" -d '{"query": "query ListEvents { listEvents { items { id } } }"}'
This command returns a list of events (which may be empty if no events have been created). For more on this topic, check out this informative blog post that expands on API testing strategies.
You can also use Artillery, an open-source performance testing toolkit, to run a load test:
- Install the CLI tool with npm:
$ npm install -g artillery
- Create a file named test.yaml that defines your load test, for instance, 10 requests per second for 2 minutes (totaling 1200 requests). Note that the script references the environment variables defined earlier.
config: target: "{{ $processEnvironment.APPSYNC_API_URL }}" phases: - duration: 120 arrivalRate: 10 defaults: headers: x-api-key: "{{ $processEnvironment.APPSYNC_API_KEY }}" Content-Type: 'application/graphql' scenarios: - flow: - post: url: '/' json: query: 'query ListEvents { listEvents { items { id } } }'
- Execute the test:
$ artillery run test.yaml
- The test runs and produces a summary. The number of 403 HTTP responses indicates how many requests were blocked when the rate limit was breached.
Next, run the curl command again:
$ curl -XPOST $APPSYNC_API_URL -H "Content-Type:application/graphql" -H "x-api-key:$APPSYNC_API_KEY" -d '{"query": "query ListEvents { listEvents { items { id } } }"}'
You should see a response indicating that WAF has blocked the request, confirming that the action was applied until the request rate dropped below the limit:
{
"errors": [{
"errorType": "WAFForbiddenException",
"message": "Forbidden"
}]
}
Disabling Introspection Queries for Specific API Keys
If you provide public access to an API using an API key without strict authentication, you might want to disable introspection queries for security reasons. To do this, you can create a rule to block these requests, which are typically made using the special __schema
field.
First, create a new API key for your AppSync API in the AppSync console under Settings.
Follow these steps to add a new rule to your ACL:
- In the WAF console, select “AppSync-First-ACL,” go to the Rules tab, and click Add rules and Add my own rules and rule groups.
- Name the rule “Introspection.”
- Choose Regular rule for Rule type.
- For If a request, select matches all the statements (AND).
- For Statement 1:
- Inspect: Header
- Header field name: x-api-key
- Match type: Exactly matches string
- String to match: <paste the API KEY you want to block>
- Text transformation: Lowercase
- Add another statement. For Statement 2:
- Inspect: Body
- Match type: Contains
For more best practices, you can visit this authoritative resource which discusses API security in detail.
Additionally, if you’re interested in learning more about career opportunities in this field, check out this excellent resource that showcases job openings.
Leave a Reply