Configure AWS Route53 Resolver Rules

The aws:route53/resolverRule:ResolverRule resource, part of the Pulumi AWS provider, defines Route 53 Resolver rules that control how DNS queries for specific domains are resolved: forwarded to custom resolvers, blocked from forwarding, or recursively resolved. This guide focuses on three capabilities: SYSTEM rules to block forwarding, FORWARD rules to route queries to on-premises or custom DNS servers, and IPv4 and IPv6 target configuration.

FORWARD rules require an outbound resolver endpoint to route queries through; SYSTEM rules operate independently. The examples are intentionally small. Combine them with your own resolver endpoints and VPC associations.

Override AWS default DNS resolution for a subdomain

Some organizations need to prevent Route 53 Resolver from forwarding queries for specific subdomains, keeping resolution within AWS’s default DNS behavior.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const sys = new aws.route53.ResolverRule("sys", {
    domainName: "subdomain.example.com",
    ruleType: "SYSTEM",
});
import pulumi
import pulumi_aws as aws

sys = aws.route53.ResolverRule("sys",
    domain_name="subdomain.example.com",
    rule_type="SYSTEM")
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/route53"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := route53.NewResolverRule(ctx, "sys", &route53.ResolverRuleArgs{
			DomainName: pulumi.String("subdomain.example.com"),
			RuleType:   pulumi.String("SYSTEM"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var sys = new Aws.Route53.ResolverRule("sys", new()
    {
        DomainName = "subdomain.example.com",
        RuleType = "SYSTEM",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.route53.ResolverRule;
import com.pulumi.aws.route53.ResolverRuleArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var sys = new ResolverRule("sys", ResolverRuleArgs.builder()
            .domainName("subdomain.example.com")
            .ruleType("SYSTEM")
            .build());

    }
}
resources:
  sys:
    type: aws:route53:ResolverRule
    properties:
      domainName: subdomain.example.com
      ruleType: SYSTEM

When you set ruleType to SYSTEM, Route 53 Resolver uses AWS’s default DNS resolution for the specified domainName instead of forwarding queries to custom resolvers. This is useful when you have a FORWARD rule for a parent domain but want a subdomain to resolve normally.

Forward DNS queries to on-premises resolvers

Hybrid cloud architectures often need to resolve private domain names that exist in on-premises data centers.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const fwd = new aws.route53.ResolverRule("fwd", {
    domainName: "example.com",
    name: "example",
    ruleType: "FORWARD",
    resolverEndpointId: foo.id,
    targetIps: [{
        ip: "123.45.67.89",
    }],
    tags: {
        Environment: "Prod",
    },
});
import pulumi
import pulumi_aws as aws

fwd = aws.route53.ResolverRule("fwd",
    domain_name="example.com",
    name="example",
    rule_type="FORWARD",
    resolver_endpoint_id=foo["id"],
    target_ips=[{
        "ip": "123.45.67.89",
    }],
    tags={
        "Environment": "Prod",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/route53"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := route53.NewResolverRule(ctx, "fwd", &route53.ResolverRuleArgs{
			DomainName:         pulumi.String("example.com"),
			Name:               pulumi.String("example"),
			RuleType:           pulumi.String("FORWARD"),
			ResolverEndpointId: pulumi.Any(foo.Id),
			TargetIps: route53.ResolverRuleTargetIpArray{
				&route53.ResolverRuleTargetIpArgs{
					Ip: pulumi.String("123.45.67.89"),
				},
			},
			Tags: pulumi.StringMap{
				"Environment": pulumi.String("Prod"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var fwd = new Aws.Route53.ResolverRule("fwd", new()
    {
        DomainName = "example.com",
        Name = "example",
        RuleType = "FORWARD",
        ResolverEndpointId = foo.Id,
        TargetIps = new[]
        {
            new Aws.Route53.Inputs.ResolverRuleTargetIpArgs
            {
                Ip = "123.45.67.89",
            },
        },
        Tags = 
        {
            { "Environment", "Prod" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.route53.ResolverRule;
import com.pulumi.aws.route53.ResolverRuleArgs;
import com.pulumi.aws.route53.inputs.ResolverRuleTargetIpArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var fwd = new ResolverRule("fwd", ResolverRuleArgs.builder()
            .domainName("example.com")
            .name("example")
            .ruleType("FORWARD")
            .resolverEndpointId(foo.id())
            .targetIps(ResolverRuleTargetIpArgs.builder()
                .ip("123.45.67.89")
                .build())
            .tags(Map.of("Environment", "Prod"))
            .build());

    }
}
resources:
  fwd:
    type: aws:route53:ResolverRule
    properties:
      domainName: example.com
      name: example
      ruleType: FORWARD
      resolverEndpointId: ${foo.id}
      targetIps:
        - ip: 123.45.67.89
      tags:
        Environment: Prod

When queries match the domainName, Route 53 Resolver forwards them through the outbound endpoint specified by resolverEndpointId to the DNS servers listed in targetIps. The ip property specifies the IPv4 address of each target resolver. You can list multiple target IPs for redundancy.

Forward DNS queries to IPv6 resolvers

Networks transitioning to IPv6 or operating dual-stack environments need to forward DNS queries to IPv6-addressed resolvers.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const fwd = new aws.route53.ResolverRule("fwd", {
    domainName: "example.com",
    name: "example",
    ruleType: "FORWARD",
    resolverEndpointId: foo.id,
    targetIps: [{
        ipv6: "2600:1f18:1686:2000:4e60:6e3e:258:da36",
    }],
    tags: {
        Environment: "Prod",
    },
});
import pulumi
import pulumi_aws as aws

fwd = aws.route53.ResolverRule("fwd",
    domain_name="example.com",
    name="example",
    rule_type="FORWARD",
    resolver_endpoint_id=foo["id"],
    target_ips=[{
        "ipv6": "2600:1f18:1686:2000:4e60:6e3e:258:da36",
    }],
    tags={
        "Environment": "Prod",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/route53"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := route53.NewResolverRule(ctx, "fwd", &route53.ResolverRuleArgs{
			DomainName:         pulumi.String("example.com"),
			Name:               pulumi.String("example"),
			RuleType:           pulumi.String("FORWARD"),
			ResolverEndpointId: pulumi.Any(foo.Id),
			TargetIps: route53.ResolverRuleTargetIpArray{
				&route53.ResolverRuleTargetIpArgs{
					Ipv6: pulumi.String("2600:1f18:1686:2000:4e60:6e3e:258:da36"),
				},
			},
			Tags: pulumi.StringMap{
				"Environment": pulumi.String("Prod"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var fwd = new Aws.Route53.ResolverRule("fwd", new()
    {
        DomainName = "example.com",
        Name = "example",
        RuleType = "FORWARD",
        ResolverEndpointId = foo.Id,
        TargetIps = new[]
        {
            new Aws.Route53.Inputs.ResolverRuleTargetIpArgs
            {
                Ipv6 = "2600:1f18:1686:2000:4e60:6e3e:258:da36",
            },
        },
        Tags = 
        {
            { "Environment", "Prod" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.route53.ResolverRule;
import com.pulumi.aws.route53.ResolverRuleArgs;
import com.pulumi.aws.route53.inputs.ResolverRuleTargetIpArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var fwd = new ResolverRule("fwd", ResolverRuleArgs.builder()
            .domainName("example.com")
            .name("example")
            .ruleType("FORWARD")
            .resolverEndpointId(foo.id())
            .targetIps(ResolverRuleTargetIpArgs.builder()
                .ipv6("2600:1f18:1686:2000:4e60:6e3e:258:da36")
                .build())
            .tags(Map.of("Environment", "Prod"))
            .build());

    }
}
resources:
  fwd:
    type: aws:route53:ResolverRule
    properties:
      domainName: example.com
      name: example
      ruleType: FORWARD
      resolverEndpointId: ${foo.id}
      targetIps:
        - ipv6: 2600:1f18:1686:2000:4e60:6e3e:258:da36
      tags:
        Environment: Prod

This configuration works like the IPv4 forward rule, but uses the ipv6 property in targetIps to specify IPv6 addresses. Route 53 Resolver forwards matching queries through the outbound endpoint to the IPv6 resolvers.

Beyond these examples

These snippets focus on specific resolver rule features: SYSTEM rules for blocking forwarding, and FORWARD rules with IPv4 and IPv6 targets. They’re intentionally minimal rather than full DNS architectures.

The examples may reference pre-existing infrastructure such as outbound resolver endpoints (for FORWARD rules). They focus on configuring the rule rather than provisioning endpoints or VPC associations.

To keep things focused, common resolver rule patterns are omitted, including:

  • RECURSIVE rule type for conditional forwarding
  • Multiple target IPs for redundancy
  • Rule association with VPCs (aws.route53.ResolverRuleAssociation)
  • Cross-account rule sharing (shareStatus)

These omissions are intentional: the goal is to illustrate how each resolver rule feature is wired, not provide drop-in DNS modules. See the Route 53 Resolver Rule resource reference for all available configuration options.

Let's configure AWS Route53 Resolver Rules

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Rule Types & Configuration
What are the different rule types available?
Route53 Resolver supports three rule types: FORWARD (routes DNS queries to specified IP addresses), SYSTEM (uses AWS-managed routing), and RECURSIVE (performs standard DNS resolution).
What's required to create a FORWARD rule?
FORWARD rules require domainName, ruleType set to FORWARD, resolverEndpointId (outbound endpoint ID), and targetIps with at least one IP address.
Do I need a resolver endpoint for all rule types?
No, resolverEndpointId and targetIps should only be specified for FORWARD type rules. SYSTEM and RECURSIVE rules don’t use these properties.
Immutability & Updates
What properties can't be changed after creation?
Both domainName and ruleType are immutable. Changing either property forces replacement of the entire resolver rule.
Can I update the friendly name of a rule?
Yes, the name property can be updated without replacing the resource.
Forwarding & Target IPs
Can I use IPv6 addresses for DNS forwarding?
Yes, specify IPv6 addresses using the ipv6 field in the targetIps configuration block instead of the ip field.
Can I specify both IPv4 and IPv6 target IPs in the same rule?
Yes, you can include multiple entries in targetIps, with some using the ip field (IPv4) and others using the ipv6 field (IPv6).

Using a different cloud?

Explore networking guides for other cloud providers: