AWS Builder Center: Learn, Build and Connect with builders in the AWS community
AWS Builder Center is the official home for builders on AWS. Share and read what others are working on, follow people who inspire you, explore training and workshops, and find tools to support what you're building.
Block malicious domain resolution using Route 53 Global Resolver DNS Firewall
Demonstrates how to configure DNS Firewall rules in a Route 53 Global Resolver DNS View to block malicious domains using custom domain lists, AWS managed lists, and DGA advanced threat detection, with OCSF log verification.
Background
DNS Firewall is the security layer within Global Resolver that evaluates DNS queries sent to Global Resolver before resolution. Queries matching a Block rule are denied and do not proceed to resolution. Queries matching an Alert rule are logged but permitted to continue.
Note: DNS Firewall only protects DNS queries sent to Global Resolver endpoints. Clients can bypass this protection by using other DNS resolvers or external DoH/DoT services. Direct IP connections also bypass domain-based DNS controls. For comprehensive coverage, use network-level policies to enforce Global Resolver usage, restrict unauthorized encrypted DNS services, and control direct outbound connections.
Architecture overview
Query flow from left to right:
- Client (office/remote/branch) sends DNS query to Global Resolver Anycast IP
- Global Resolver authenticates the client
- DNS Firewall evaluates the query
- Queries not blocked proceed to normal resolution
- Query Logging records all queries and Firewall actions
Prerequisites
- An AWS account with IAM permissions: AmazonRoute53GlobalResolverFullAccess + CloudWatchLogsFullAccess
- Latest AWS CLI v2 installed, run
aws route53globalresolver helpto confirm the subcommand is available - Your public IPv4 address:
curl -4 -s https://checkip.amazonaws.com
Step 1: Create the Global Resolver
-
Log in to the AWS Console and switch Region to us-east-2
-
Open Route 53, then in the left menu click Global Resolver -> Global resolvers
-
Click Create global resolver
-
Configuration:
- Resolver name: enter a descriptive name
- Regions: select at least 2 Regions closest to your clients
- IP address type: Dual-stack
-
Click Create
-
Wait for status to become Operational (approximately 3-5 minutes)
-
Note the assigned Anycast IPv4 addresses (needed for testing)
Step 2: Create a DNS View
- Click into your Global Resolver
- DNS views tab -> Create DNS view
- Enter the DNS view name
- Keep other options at their defaults:
- DNSSEC validation: Enable
- Firewall rules fail open behavior: Disable
- EDNS client subnet: Enable
- Click Create
- Wait for status to become Operational
Step 3: Configure Access Source
- Navigate into your DNS View -> Access sources tab
- Click Create access source
- Configuration:
- Name: enter a descriptive name
- CIDR block: your public IPv4/32 (exact match for your IP)
- Protocol: Do53
- Click Create
- Wait for status to become Operational
Step 4: Enable Query Logging
Enable logging before running tests to ensure all test queries are captured.
-
Go back to the Global Resolver details page
-
In the Resolver details section, find Observability Region -> click Edit -> select US East (Ohio) us-east-2 -> Save
-
Click the Log delivery tab
-
Click Add -> To Amazon CloudWatch Logs
-
Log type: keep GLOBAL_RESOLVER_LOGS
-
Destination log group: use the system-recommended path (format: /aws/vendedlogs/route53globalresolver/...)
-
Click Add
Step 5: Create a custom domain list
-
Navigate to Global Resolver -> Domain lists tab (important: this is NOT the Domain lists under VPC Resolver in the left menu, those are separate regional resources)
-
Click Create domain list
-
Enter a name
-
Click Create -> wait for status to become Operational
-
Click into the domain list -> Add domains
-
Select Specify domains manually
-
Enter domains to block, for example:
- malicious-test.example.com
- *.phishing-demo.net
- bad-site.org
-
Click Add domains -> wait for status to become Operational again
Note: Domain lists support exact matching and wildcard matching (*.example.com matches all subdomains). DNS Firewall matches against the query string, even non-existent domains will be blocked.
Step 6: Create DNS Firewall rules
Rule A: Custom domain list Block
-
Navigate to DNS View -> DNS Firewall rules tab
-
Click Create rule
-
Configuration:
- Rule name: enter a descriptive name
- Rule configuration type: Customer managed domain lists
- Domain lists: select the domain list created in Step 5
- Query type: leave empty (matches all query types)
- Action: Block
- Response to send for Block action: NXDOMAIN
-
Click Create rule
-
Wait for rule status to become Operational
Rule B: AWS managed domain list Block
- Click Create rule
- Configuration:
- Rule name: enter a descriptive name
- Rule configuration type: AWS managed domain lists
- Select the Malware category from the dropdown
- Action: Block
- Response to send for Block action: NXDOMAIN
- Click Create rule
- Wait for rule status to become Operational
Rule C: DGA Advanced Threat Detection
- Click Create rule
- Configuration:
- Rule name: enter a descriptive name
- Rule configuration type: DNS Firewall Advanced protections
- Protection type: Domain Generation Algorithms (DGAs)
- Confidence threshold: HIGH
- Action: Block
- Response to send for Block action: NXDOMAIN
- Click Create rule
- Wait for rule status to become Operational
Verify the rule list
After creation, confirm all three rules show Operational status in the DNS Firewall rules tab.
Note: Priority is automatically assigned by the system in creation order (1, 2, 3...). Lower numbers execute first. To adjust execution order, select a rule -> Edit -> modify the Priority value.
Step 7: Test and verify
From an authorized client, run the following queries to test resolver behavior, then use logs and metrics to validate applicable firewall rules.
Important: A dig response code (such as NXDOMAIN) alone cannot confirm whether a query was blocked by DNS Firewall or the domain simply does not exist. The definitive verification is the CloudWatch log entry:
- action_name = "Denied" -> the query was blocked
- action_name = "Allowed" -> the query was permitted
- firewall_rule_id, when present, identifies the rule associated with the decision
An Alert match is confirmed only when action_name = "Allowed", firewall_rule_id matches the expected rule, and that rule is configured with the Alert action.
Test 1: Normal domain resolution
dig @<Anycast-IP> aws.amazon.com
Expected dig result: Returns A records with NOERROR. Expected log entry: action_name = "Allowed", rcode = "NOERROR", and no firewall_rule_id matching Rules A, B, or C.
This confirms the Global Resolver is functioning and your access source is authorized.
Test 2: Custom domain list Block (Rule A)
dig @<Anycast-IP> malicious-test.example.com
Expected dig result: NXDOMAIN (the Block response configured in Rule A). Expected log entry: action_name = "Denied", enrichments[].data.firewall_rule_id matches Rule A.
Note: This domain also does not exist in public DNS, so the NXDOMAIN response alone is ambiguous. The log entry with action_name = "Denied" and the matching rule ID is the definitive proof of a firewall block.
The wildcard entry *.phishing-demo.net in the custom domain list also matches anything.phishing-demo.net. Because Rule A has the highest priority (lowest number), any query matching the custom list is intercepted by Rule A regardless of whether it might also appear in an AWS managed list.
Test 3: AWS managed domain list verification (Rule B)
AWS managed domain lists are not publicly browsable, so you cannot select a guaranteed-matching domain for on-demand testing.
Recommended verification approach:
- Configure Rule B with the Alert action (instead of Block). In Alert mode, matching queries are permitted rather than blocked, but the match is recorded.
- Monitor for a log entry where:
- action_name = "Allowed"
- enrichments[].data.firewall_rule_id matches Rule B's rule ID
- You can also confirm matches through DNS Firewall sampled requests or CloudWatch metrics for the rule.
- Once you observe real matches confirming Rule B is evaluating correctly, change the action to Block for production enforcement.
This follows the AWS best practice for managed domain lists: deploy in Alert mode first, validate through logs and metrics, then enable Block.
Test 4: DGA advanced threat detection (Rule C)
dig @<Anycast-IP> aef3fbb2bc7dqrb6n.ev11-test.example.com
Observed result: In this test, the domain was not classified as DGA-generated at HIGH confidence. The CloudWatch log shows action_name = "Allowed", rcode = "NOERROR".
DGA detection evaluates DNS queries for characteristics associated with algorithmically generated domains. The HIGH confidence threshold prioritizes lower false-positive rates, so a single synthetic random-looking domain is not guaranteed to trigger the rule.
For Rule C's current Block configuration, confirm a match only when action_name = "Denied" and enrichments[].data.firewall_rule_id matches Rule C.
Verify logs in CloudWatch
After running the test queries, navigate to CloudWatch Logs -> Log groups -> select the /aws/vendedlogs/route53globalresolver/... log group created in Step 4.
Each query generates an OCSF-formatted log entry. Key fields to examine:
- query.hostname: the domain that was queried
- action_name: "Allowed" (query permitted) or "Denied" (blocked by firewall)
- rcode: "NOERROR" (the DNS query completed without a protocol error, although the response might contain no answer records), "NXDOMAIN" (firewall block response or non-existent domain), or "REFUSED"
- enrichments[].data.firewall_rule_id: the specific rule associated with the decision (present for both Block and Alert matches)
- enrichments[].data.dns_view_id: the DNS View that processed the query
The screenshot below shows CloudWatch log entries for four sample queries:
- aws.amazon.com: Allowed, NOERROR — normal resolution confirmed
- malicious-test.example.com: Denied, NXDOMAIN — custom domain list block (Rule A) confirmed
- anything.phishing-demo.net: Denied, NXDOMAIN — blocked by the custom wildcard *.phishing-demo.net in Rule A (not Rule B)
- A separate DGA-style test domain: Allowed, NOERROR — HIGH confidence DGA detection was not triggered for this domain
This test run confirms that Rule A is blocking as expected. It does not validate Rule B, and Rule C did not trigger. Validate Rule B in Alert mode before enabling Block, and validate Rule C through subsequent rule-specific log matches.
The screenshot below shows sample log entries for all four test cases.
Summary
This article showed how to configure three DNS Firewall rule types for Route 53 Global Resolver: a custom domain list with Block, an AWS managed domain list using an Alert-before-Block workflow, and DGA advanced protection with Block at HIGH confidence. The test run confirmed the custom domain list block; the managed domain list and DGA rule require subsequent rule-specific matches for validation. Use the CloudWatch OCSF log fields action_name and enrichments[].data.firewall_rule_id as definitive evidence, rather than relying on dig response codes alone.
References
- [Route 53 Global Resolver] https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/gr-what-is-global-resolver.html
- [DNS Firewall for Global Resolver] https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/gr-configure-manage-firewall-rules.html
- [Managed domain lists] https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/gr-managed-domain-lists.html
- [Global Resolver DNS query logging - OCSF format] https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/gr-gain-visibility-into-dns-activity.html
- [Open Cybersecurity Schema Framework] https://schema.ocsf.io/
- Language
- English
Relevant content
asked a year ago
