AWS Security Blog
How to automate updates for your domain list in Route 53 Resolver DNS Firewall
Note: This post includes links to third-party websites. AWS is not responsible for the content on those websites.
Following the release of Amazon Route 53 Resolver DNS Firewall, Amazon Web Services (AWS) published several blog posts to help you protect your Amazon Virtual Private Cloud (Amazon VPC) DNS resolution, including How to Get Started with Amazon Route 53 Resolver DNS Firewall for Amazon VPC and Secure your Amazon VPC DNS resolution with Amazon Route 53 Resolver DNS Firewall. Route 53 Resolver DNS Firewall provides managed domain lists that are fully maintained and kept up-to-date by AWS and that directly benefit from the threat intelligence that we gather, but you might want to create or import your own list to have full control over the DNS filtering.
In this blog post, you will find a solution to automate the management of your domain list by using AWS Lambda, Amazon EventBridge, and Amazon Simple Storage Service (Amazon S3). The solution in this post uses, as an example, the URLhaus open Response Policy Zone (RPZ) list, which generates a new file every five minutes.
Architecture overview
The solution is made of the following four components, as shown in Figure 1.
- An EventBridge scheduled rule to invoke the Lambda function on a schedule.
- A Lambda function that uses the AWS SDK to perform the automation logic.
- An S3 bucket to temporarily store the list of domains retrieved.
- Amazon Route 53 Resolver DNS Firewall.
After the solution is deployed, it works as follows:
- The scheduled rule invokes the Lambda function every 5 minutes to fetch the latest domain list available.
- The Lambda function fetches the list from URLhaus, parses the data retrieved, formats the data, uploads the list of domains into the S3 bucket, and invokes the Route 53 Resolver DNS Firewall importFirewallDomains API action.
- The domain list is then updated.
Implementation steps
As a first step, create your own domain list on the Route 53 Resolver DNS Firewall. Having your own domain list allows you to have full control of the list of domains to which you want to apply actions, as defined within rule groups.
To create your own domain list
- In the Route 53 console, in the left menu, choose Domain lists in the DNS firewall section.
- Choose the Add domain list button, enter a name for your owned domain list, and then enter a placeholder domain to initialize the domain list.
- Choose Add domain list to finalize the creation of the domain list.
The list from URLhaus contains more than a thousand records. You will use the ImportFirewallDomains endpoint to upload this list to DNS Firewall. The use of the ImportFirewallDomains endpoint requires that you first upload the list of domains and make the list available in an S3 bucket that is located in the same AWS Region as the owned domain list that you just created.
To create the S3 bucket
- In the S3 console, choose Create bucket.
- Under General configuration, configure the AWS Region option to be the same as the Region in which you created your domain list.
- Finalize the configuration of your S3 bucket, and then choose Create bucket.
Because a new file is created every five minutes, we recommend setting a lifecycle rule to automatically expire and delete files after 24 hours to optimize for cost and only save the most recent lists.
To create the Lambda function
- Follow the steps in the topic Creating an execution role in the IAM console to create an execution role. After step 4, when you configure permissions, choose Create Policy, and then create and add an IAM policy similar to the following example. This policy needs to:
- Allow the Lambda function to put logs in Amazon CloudWatch.
- Allow the Lambda function to have read and write access to objects placed in the created S3 bucket.
- Allow the Lambda function to update the firewall domain list.
- (Optional) If you decide to use the example provided by AWS:
- After cloning the repository: Build the layer following the instruction included in the readme.md and the provided script.
- Zip the lambda.
- In the left menu, select Layers then Create Layer. Enter a name for the layer, then select Upload a .zip file. Choose to upload the layer (node-axios-layer.zip).
- As a compatible runtime, select: Node.js 16.x.
- Select Create
- In the Lambda console, in the same Region as your domain list, choose Create function, and then do the following:
- Choose your desired runtime and architecture.
- (Optional) To use the code provided by AWS: Select Node.js 16.x as the runtime.
- Choose Change the default execution role.
- Choose Use an existing role, and then pick the role that you just created.
- After the Lambda function is created, in the left menu of the Lambda console, choose Functions, and then select the function you created.
- For Code source, you can either enter the code of the Lambda function or choose the Upload from button and then choose the source for the code. AWS provides an example of functioning code on GitHub under a MIT-0 license.
(optional) To use the code provided by AWS:
- Choose the Upload from button and upload the zipped code example.
- After the code is uploaded, edit the default Runtime settings: Choose the Edit button and set the handler to be equal to: LambdaRpz.handler
- Edit the default Layers configuration, choose the Add a layer button, select Specify an ARN and enter the ARN of the layer created during the optional step 2.
- Edit the environment variables of the function: Select the Edit button and define the three following variables:
- Key : FirewallDomainListId | Value : <domain-list-id>
- Key : region | Value : <region>
- Key : s3Prefix | Value : <DNSFW-BUCKET-NAME>
The code that you place in the function will be able to fetch the list from URLhaus, upload the list as a file to S3, and start the import of domains.
For the Lambda function to be invoked every 5 minutes, next you will create a scheduled rule with Amazon EventBridge.
To automate the invoking of the Lambda function
- In the EventBridge console, in the same AWS Region as your domain list, choose Create rule.
- For Rule type, choose Schedule.
- For Schedule pattern, select the option A schedule that runs at a regular rate, such as every 10 minutes, and under Rate expression set a rate of 5 minutes.
- To select the target, choose AWS service, choose Lambda function, and then select the function that you previously created.
After the solution is deployed, your domain list will be updated every 5 minutes and look like the view in Figure 4.
Code samples
You can use the samples in the amazon-route-53-resolver-firewall-automation-examples-2 GitHub repository to ease the automation of your domain list, and the associated updates. The repository contains script files to help you with the deployment process of the AWS CloudFormation template. Note that you need to have the AWS Command Line Interface (AWS CLI) installed and properly configured in order to use the files.
To deploy the CloudFormation stack
- If you haven’t done so already, create an S3 bucket to store the artifacts in the Region where you wish to deploy. This name of this bucket will then be referenced as ParamS3ArtifactBucket with a value of <DOC-EXAMPLE-BUCKET-ARTIFACT>
- Clone the repository locally.
git clone https://github.com/aws-samples/amazon-route-53-resolver-firewall-automation-examples-2 - Build the Lambda function layer. From the /layer folder, use the provided script.
. ./build-layer.sh - Zip and upload the artifact to the bucket created in step 1. From the root folder, use the provided script.
. ./zipupload.sh <ParamS3ArtifactBucket> - Deploy the AWS CloudFormation stack by using either the AWS CLI or the CloudFormation console.
- To deploy by using the AWS CLI, from the root folder, type the following command, making sure to replace <region>, <DOC-EXAMPLE-BUCKET-ARTIFACT>, <DNSFW-BUCKET-NAME>, and <DomainListName>with your own values.
- To deploy by using the console, do the following:
- In the CloudFormation console, choose Create stack, and then choose With new resources (standard).
- On the creation screen, choose Template is ready, and upload the provided DNSFWStack.cfn.yaml file.
- Enter a stack name and configure the requested parameters with your desired configuration and outcomes. These parameters include the following:
- The name of your firewall domain list.
- The name of the S3 bucket that contains Lambda artifacts.
- The name of the S3 bucket that will be created to contain the files with the domain information from URLhaus.
- Acknowledge that the template requires IAM permission because it will create the role for the Lambda function and manage its IAM policy, and then choose Create stack.
After a few minutes, all the resources should be created and the CloudFormation stack is now deployed. After 5 minutes, your domain list should be updated, as shown in Figure 5.
Conclusions and cost
In this blog post, you learned about creating and automating the update of a domain list that you fully control. To go further, you can extend and replicate the architecture pattern to fetch domain names from other sources by editing the source code of the Lambda function.
After the solution is in place, in order for the filtering to be effective, you need to create a rule group referencing the domain list and associate the rule group with some of your VPCs.
For cost information, see the AWS Pricing Calculator. This solution will be invoked 60 (minutes) * 24 (hours) * 30 (days) / 5 (minutes) = 8,640 times per month, invoking the Lambda function that will run for an average of 400 minutes, storing an average of 0.5 GB in Amazon S3, and creating a domain list that averages 1,500 domains. According to our public pricing, and without factoring in the AWS Free Tier, this will incur the estimated total cost of $1.43 per month for the filtering of 1 million DNS requests.
If you have feedback about this post, submit comments in the Comments section below. If you have questions about this post, contact AWS Support.
Want more AWS Security news? Follow us on Twitter.