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 DNS servers, blocked from forwarding, or handled recursively. This guide focuses on three capabilities: SYSTEM rules to block forwarding, FORWARD rules to on-premises DNS, and IPv6 target configuration.

Resolver rules work with outbound resolver endpoints to route queries between AWS and external DNS infrastructure. The examples are intentionally small. Combine them with your own VPC associations and resolver endpoints.

Override DNS resolution for specific subdomains

Organizations sometimes need to prevent Route 53 Resolver from forwarding queries for certain 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 ruleType is SYSTEM, Route 53 Resolver uses AWS’s default DNS resolution for the specified domainName instead of forwarding queries. This blocks forwarding rules that would otherwise apply to parent domains. SYSTEM rules require only domainName and ruleType; they don’t use resolverEndpointId or targetIps.

Forward DNS queries to on-premises resolvers

Hybrid cloud architectures often resolve private domain names by forwarding queries from AWS to corporate DNS servers.

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 ruleType is FORWARD, queries matching domainName are sent to the IP addresses in targetIps via the outbound resolver endpoint specified by resolverEndpointId. The resolver endpoint must exist in your VPC with network connectivity to the target DNS servers. Each targetIp entry specifies either an ip (IPv4) or ipv6 address.

Forward DNS queries to IPv6 resolvers

IPv6-enabled networks can forward queries to IPv6 addresses, supporting dual-stack or IPv6-only infrastructure.

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 extends the forward rule pattern with IPv6 addressing. Instead of the ip field, use ipv6 in the targetIps configuration. The resolver endpoint and network path must support IPv6 connectivity to the target address.

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 complete DNS architectures.

The examples reference pre-existing infrastructure such as outbound resolver endpoints (resolverEndpointId) and network connectivity to target DNS servers. They focus on configuring the rule rather than provisioning resolver endpoints or VPC associations.

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

  • RECURSIVE rule type for conditional forwarding
  • Multiple target IPs for redundancy
  • Rule association with VPCs (separate resource)
  • Cross-account rule sharing

These omissions are intentional: the goal is to illustrate how each resolver rule type 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 resolver rule types?
Route53 Resolver supports three rule types: FORWARD (forwards queries to specified IPs), SYSTEM (uses Route53 Resolver default behavior), and RECURSIVE (performs recursive DNS resolution).
What's required to create a FORWARD rule?
FORWARD rules require resolverEndpointId (outbound resolver endpoint) and targetIps (destination IP addresses for DNS queries). SYSTEM and RECURSIVE rules don’t need these properties.
How do I create a SYSTEM rule?
Set ruleType to SYSTEM and specify domainName. You don’t need resolverEndpointId or targetIps for SYSTEM rules.
Immutability & Limitations
What properties can't I change after creating a resolver rule?
Both domainName and ruleType are immutable. Changing either requires replacing the resource.
Can I change a SYSTEM rule to a FORWARD rule?
No, ruleType is immutable. You must delete the existing rule and create a new one with the desired type.
IP Addressing & Endpoints
Can I use IPv6 addresses for DNS forwarding?
Yes, specify the ipv6 field in the targetIps configuration block instead of the ip field.
Can I mix IPv4 and IPv6 addresses in targetIps?
Yes, targetIps accepts multiple configuration blocks, each with either an ip (IPv4) or ipv6 field.
Sharing & Cross-Account
How do I know if a resolver rule is shared with other accounts?
Check the shareStatus output property. Values are NOT_SHARED, SHARED_BY_ME (you shared it), or SHARED_WITH_ME (shared with you).
How can I identify who owns a shared resolver rule?
The ownerId output property contains the AWS account ID of the account that owns the rule when it’s shared.

Using a different cloud?

Explore networking guides for other cloud providers: