Configure Azure Private DNS Record Sets

The azure-native:privatedns:PrivateRecordSet resource, part of the Pulumi Azure Native provider, defines DNS records within a Private DNS zone: their type, values, and TTL. This guide focuses on four capabilities: A records for IPv4 resolution, CNAME records for aliasing, MX records for mail routing, and SRV records for service discovery.

Record sets belong to Private DNS zones and reference resource groups that must exist separately. The examples are intentionally small. Combine them with your own Private DNS zones and network infrastructure.

Map hostnames to IPv4 addresses with A records

Most private DNS deployments create A records that map hostnames to IPv4 addresses, enabling internal services to resolve by name.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const privateRecordSet = new azure_native.privatedns.PrivateRecordSet("privateRecordSet", {
    aRecords: [{
        ipv4Address: "1.2.3.4",
    }],
    metadata: {
        key1: "value1",
    },
    privateZoneName: "privatezone1.com",
    recordType: "A",
    relativeRecordSetName: "recordA",
    resourceGroupName: "resourceGroup1",
    ttl: 3600,
});
import pulumi
import pulumi_azure_native as azure_native

private_record_set = azure_native.privatedns.PrivateRecordSet("privateRecordSet",
    a_records=[{
        "ipv4_address": "1.2.3.4",
    }],
    metadata={
        "key1": "value1",
    },
    private_zone_name="privatezone1.com",
    record_type="A",
    relative_record_set_name="recordA",
    resource_group_name="resourceGroup1",
    ttl=3600)
package main

import (
	privatedns "github.com/pulumi/pulumi-azure-native-sdk/privatedns/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := privatedns.NewPrivateRecordSet(ctx, "privateRecordSet", &privatedns.PrivateRecordSetArgs{
			ARecords: privatedns.ARecordArray{
				&privatedns.ARecordArgs{
					Ipv4Address: pulumi.String("1.2.3.4"),
				},
			},
			Metadata: pulumi.StringMap{
				"key1": pulumi.String("value1"),
			},
			PrivateZoneName:       pulumi.String("privatezone1.com"),
			RecordType:            pulumi.String("A"),
			RelativeRecordSetName: pulumi.String("recordA"),
			ResourceGroupName:     pulumi.String("resourceGroup1"),
			Ttl:                   pulumi.Float64(3600),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var privateRecordSet = new AzureNative.PrivateDns.PrivateRecordSet("privateRecordSet", new()
    {
        ARecords = new[]
        {
            new AzureNative.PrivateDns.Inputs.ARecordArgs
            {
                Ipv4Address = "1.2.3.4",
            },
        },
        Metadata = 
        {
            { "key1", "value1" },
        },
        PrivateZoneName = "privatezone1.com",
        RecordType = "A",
        RelativeRecordSetName = "recordA",
        ResourceGroupName = "resourceGroup1",
        Ttl = 3600,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.privatedns.PrivateRecordSet;
import com.pulumi.azurenative.privatedns.PrivateRecordSetArgs;
import com.pulumi.azurenative.privatedns.inputs.ARecordArgs;
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 privateRecordSet = new PrivateRecordSet("privateRecordSet", PrivateRecordSetArgs.builder()
            .aRecords(ARecordArgs.builder()
                .ipv4Address("1.2.3.4")
                .build())
            .metadata(Map.of("key1", "value1"))
            .privateZoneName("privatezone1.com")
            .recordType("A")
            .relativeRecordSetName("recordA")
            .resourceGroupName("resourceGroup1")
            .ttl(3600.0)
            .build());

    }
}
resources:
  privateRecordSet:
    type: azure-native:privatedns:PrivateRecordSet
    properties:
      aRecords:
        - ipv4Address: 1.2.3.4
      metadata:
        key1: value1
      privateZoneName: privatezone1.com
      recordType: A
      relativeRecordSetName: recordA
      resourceGroupName: resourceGroup1
      ttl: 3600

When a client queries the hostname, DNS returns the IPv4 address from aRecords. The recordType property specifies “A” for IPv4 address records. The relativeRecordSetName sets the hostname within the zone (e.g., “recordA” becomes “recordA.privatezone1.com”). The ttl property controls how long clients cache the response, measured in seconds.

Create aliases with CNAME records

Applications often need DNS aliases that point one hostname to another, allowing you to change targets without updating clients.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const privateRecordSet = new azure_native.privatedns.PrivateRecordSet("privateRecordSet", {
    cnameRecord: {
        cname: "contoso.com",
    },
    metadata: {
        key1: "value1",
    },
    privateZoneName: "privatezone1.com",
    recordType: "CNAME",
    relativeRecordSetName: "recordCNAME",
    resourceGroupName: "resourceGroup1",
    ttl: 3600,
});
import pulumi
import pulumi_azure_native as azure_native

private_record_set = azure_native.privatedns.PrivateRecordSet("privateRecordSet",
    cname_record={
        "cname": "contoso.com",
    },
    metadata={
        "key1": "value1",
    },
    private_zone_name="privatezone1.com",
    record_type="CNAME",
    relative_record_set_name="recordCNAME",
    resource_group_name="resourceGroup1",
    ttl=3600)
package main

import (
	privatedns "github.com/pulumi/pulumi-azure-native-sdk/privatedns/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := privatedns.NewPrivateRecordSet(ctx, "privateRecordSet", &privatedns.PrivateRecordSetArgs{
			CnameRecord: &privatedns.CnameRecordArgs{
				Cname: pulumi.String("contoso.com"),
			},
			Metadata: pulumi.StringMap{
				"key1": pulumi.String("value1"),
			},
			PrivateZoneName:       pulumi.String("privatezone1.com"),
			RecordType:            pulumi.String("CNAME"),
			RelativeRecordSetName: pulumi.String("recordCNAME"),
			ResourceGroupName:     pulumi.String("resourceGroup1"),
			Ttl:                   pulumi.Float64(3600),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var privateRecordSet = new AzureNative.PrivateDns.PrivateRecordSet("privateRecordSet", new()
    {
        CnameRecord = new AzureNative.PrivateDns.Inputs.CnameRecordArgs
        {
            Cname = "contoso.com",
        },
        Metadata = 
        {
            { "key1", "value1" },
        },
        PrivateZoneName = "privatezone1.com",
        RecordType = "CNAME",
        RelativeRecordSetName = "recordCNAME",
        ResourceGroupName = "resourceGroup1",
        Ttl = 3600,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.privatedns.PrivateRecordSet;
import com.pulumi.azurenative.privatedns.PrivateRecordSetArgs;
import com.pulumi.azurenative.privatedns.inputs.CnameRecordArgs;
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 privateRecordSet = new PrivateRecordSet("privateRecordSet", PrivateRecordSetArgs.builder()
            .cnameRecord(CnameRecordArgs.builder()
                .cname("contoso.com")
                .build())
            .metadata(Map.of("key1", "value1"))
            .privateZoneName("privatezone1.com")
            .recordType("CNAME")
            .relativeRecordSetName("recordCNAME")
            .resourceGroupName("resourceGroup1")
            .ttl(3600.0)
            .build());

    }
}
resources:
  privateRecordSet:
    type: azure-native:privatedns:PrivateRecordSet
    properties:
      cnameRecord:
        cname: contoso.com
      metadata:
        key1: value1
      privateZoneName: privatezone1.com
      recordType: CNAME
      relativeRecordSetName: recordCNAME
      resourceGroupName: resourceGroup1
      ttl: 3600

The cnameRecord property contains a single cname value that points to the target hostname. CNAME records create aliases; when a client queries the alias, DNS returns the target name, which the client then resolves separately. This indirection lets you update the target without changing the alias.

Route email with MX records

Private zones can include MX records for internal mail routing, directing email to specific mail servers with priority-based failover.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const privateRecordSet = new azure_native.privatedns.PrivateRecordSet("privateRecordSet", {
    metadata: {
        key1: "value1",
    },
    mxRecords: [{
        exchange: "mail.privatezone1.com",
        preference: 0,
    }],
    privateZoneName: "privatezone1.com",
    recordType: "MX",
    relativeRecordSetName: "recordMX",
    resourceGroupName: "resourceGroup1",
    ttl: 3600,
});
import pulumi
import pulumi_azure_native as azure_native

private_record_set = azure_native.privatedns.PrivateRecordSet("privateRecordSet",
    metadata={
        "key1": "value1",
    },
    mx_records=[{
        "exchange": "mail.privatezone1.com",
        "preference": 0,
    }],
    private_zone_name="privatezone1.com",
    record_type="MX",
    relative_record_set_name="recordMX",
    resource_group_name="resourceGroup1",
    ttl=3600)
package main

import (
	privatedns "github.com/pulumi/pulumi-azure-native-sdk/privatedns/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := privatedns.NewPrivateRecordSet(ctx, "privateRecordSet", &privatedns.PrivateRecordSetArgs{
			Metadata: pulumi.StringMap{
				"key1": pulumi.String("value1"),
			},
			MxRecords: privatedns.MxRecordArray{
				&privatedns.MxRecordArgs{
					Exchange:   pulumi.String("mail.privatezone1.com"),
					Preference: pulumi.Int(0),
				},
			},
			PrivateZoneName:       pulumi.String("privatezone1.com"),
			RecordType:            pulumi.String("MX"),
			RelativeRecordSetName: pulumi.String("recordMX"),
			ResourceGroupName:     pulumi.String("resourceGroup1"),
			Ttl:                   pulumi.Float64(3600),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var privateRecordSet = new AzureNative.PrivateDns.PrivateRecordSet("privateRecordSet", new()
    {
        Metadata = 
        {
            { "key1", "value1" },
        },
        MxRecords = new[]
        {
            new AzureNative.PrivateDns.Inputs.MxRecordArgs
            {
                Exchange = "mail.privatezone1.com",
                Preference = 0,
            },
        },
        PrivateZoneName = "privatezone1.com",
        RecordType = "MX",
        RelativeRecordSetName = "recordMX",
        ResourceGroupName = "resourceGroup1",
        Ttl = 3600,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.privatedns.PrivateRecordSet;
import com.pulumi.azurenative.privatedns.PrivateRecordSetArgs;
import com.pulumi.azurenative.privatedns.inputs.MxRecordArgs;
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 privateRecordSet = new PrivateRecordSet("privateRecordSet", PrivateRecordSetArgs.builder()
            .metadata(Map.of("key1", "value1"))
            .mxRecords(MxRecordArgs.builder()
                .exchange("mail.privatezone1.com")
                .preference(0)
                .build())
            .privateZoneName("privatezone1.com")
            .recordType("MX")
            .relativeRecordSetName("recordMX")
            .resourceGroupName("resourceGroup1")
            .ttl(3600.0)
            .build());

    }
}
resources:
  privateRecordSet:
    type: azure-native:privatedns:PrivateRecordSet
    properties:
      metadata:
        key1: value1
      mxRecords:
        - exchange: mail.privatezone1.com
          preference: 0
      privateZoneName: privatezone1.com
      recordType: MX
      relativeRecordSetName: recordMX
      resourceGroupName: resourceGroup1
      ttl: 3600

The mxRecords array lists mail servers with their exchange hostnames and preference values. Lower preference numbers indicate higher priority; mail clients try servers in priority order. This enables failover: if the primary server is unavailable, clients automatically try the next priority level.

Service discovery protocols use SRV records to locate services by protocol and domain, encoding port numbers and load distribution.

import * as pulumi from "@pulumi/pulumi";
import * as azure_native from "@pulumi/azure-native";

const privateRecordSet = new azure_native.privatedns.PrivateRecordSet("privateRecordSet", {
    metadata: {
        key1: "value1",
    },
    privateZoneName: "privatezone1.com",
    recordType: "SRV",
    relativeRecordSetName: "recordSRV",
    resourceGroupName: "resourceGroup1",
    srvRecords: [{
        port: 80,
        priority: 0,
        target: "contoso.com",
        weight: 10,
    }],
    ttl: 3600,
});
import pulumi
import pulumi_azure_native as azure_native

private_record_set = azure_native.privatedns.PrivateRecordSet("privateRecordSet",
    metadata={
        "key1": "value1",
    },
    private_zone_name="privatezone1.com",
    record_type="SRV",
    relative_record_set_name="recordSRV",
    resource_group_name="resourceGroup1",
    srv_records=[{
        "port": 80,
        "priority": 0,
        "target": "contoso.com",
        "weight": 10,
    }],
    ttl=3600)
package main

import (
	privatedns "github.com/pulumi/pulumi-azure-native-sdk/privatedns/v3"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := privatedns.NewPrivateRecordSet(ctx, "privateRecordSet", &privatedns.PrivateRecordSetArgs{
			Metadata: pulumi.StringMap{
				"key1": pulumi.String("value1"),
			},
			PrivateZoneName:       pulumi.String("privatezone1.com"),
			RecordType:            pulumi.String("SRV"),
			RelativeRecordSetName: pulumi.String("recordSRV"),
			ResourceGroupName:     pulumi.String("resourceGroup1"),
			SrvRecords: privatedns.SrvRecordArray{
				&privatedns.SrvRecordArgs{
					Port:     pulumi.Int(80),
					Priority: pulumi.Int(0),
					Target:   pulumi.String("contoso.com"),
					Weight:   pulumi.Int(10),
				},
			},
			Ttl: pulumi.Float64(3600),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using AzureNative = Pulumi.AzureNative;

return await Deployment.RunAsync(() => 
{
    var privateRecordSet = new AzureNative.PrivateDns.PrivateRecordSet("privateRecordSet", new()
    {
        Metadata = 
        {
            { "key1", "value1" },
        },
        PrivateZoneName = "privatezone1.com",
        RecordType = "SRV",
        RelativeRecordSetName = "recordSRV",
        ResourceGroupName = "resourceGroup1",
        SrvRecords = new[]
        {
            new AzureNative.PrivateDns.Inputs.SrvRecordArgs
            {
                Port = 80,
                Priority = 0,
                Target = "contoso.com",
                Weight = 10,
            },
        },
        Ttl = 3600,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.azurenative.privatedns.PrivateRecordSet;
import com.pulumi.azurenative.privatedns.PrivateRecordSetArgs;
import com.pulumi.azurenative.privatedns.inputs.SrvRecordArgs;
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 privateRecordSet = new PrivateRecordSet("privateRecordSet", PrivateRecordSetArgs.builder()
            .metadata(Map.of("key1", "value1"))
            .privateZoneName("privatezone1.com")
            .recordType("SRV")
            .relativeRecordSetName("recordSRV")
            .resourceGroupName("resourceGroup1")
            .srvRecords(SrvRecordArgs.builder()
                .port(80)
                .priority(0)
                .target("contoso.com")
                .weight(10)
                .build())
            .ttl(3600.0)
            .build());

    }
}
resources:
  privateRecordSet:
    type: azure-native:privatedns:PrivateRecordSet
    properties:
      metadata:
        key1: value1
      privateZoneName: privatezone1.com
      recordType: SRV
      relativeRecordSetName: recordSRV
      resourceGroupName: resourceGroup1
      srvRecords:
        - port: 80
          priority: 0
          target: contoso.com
          weight: 10
      ttl: 3600

The srvRecords array defines service endpoints with port, priority, target, and weight properties. Priority controls failover order (lower values first). Weight enables load distribution among servers with the same priority; higher weights receive proportionally more traffic. The target specifies the hostname, and port indicates which TCP or UDP port the service listens on.

Beyond these examples

These snippets focus on specific record set features: DNS record types (A, CNAME, MX, SRV) and TTL and metadata configuration. They’re intentionally minimal rather than complete DNS zone configurations.

The examples reference pre-existing infrastructure such as Private DNS zones (privateZoneName) and Azure resource groups. They focus on configuring individual record sets rather than provisioning the surrounding DNS infrastructure.

To keep things focused, common record types are omitted, including:

  • AAAA records for IPv6 addressing
  • PTR records for reverse DNS lookups
  • SOA records for zone authority configuration
  • TXT records for verification and SPF

These omissions are intentional: the goal is to illustrate how each record type is wired, not provide drop-in DNS modules. See the Private DNS PrivateRecordSet resource reference for all available configuration options.

Let's configure Azure Private DNS Record Sets

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Record Types & Configuration
How do I create different types of DNS records?
Set recordType to your desired type (A, AAAA, CNAME, MX, PTR, SOA, SRV, or TXT) and configure the corresponding property. For example, use aRecords for A records, cnameRecord for CNAME, or mxRecords for MX records.
Why is cnameRecord singular while other records are arrays?
CNAME records use a single object (cnameRecord) because DNS allows only one CNAME per name. Other record types like A, AAAA, MX, PTR, SRV, and TXT use arrays (aRecords, mxRecords, etc.) to support multiple values.
How do I configure TTL for my records?
Set the ttl property to specify time-to-live in seconds. Examples in the schema use 3600 (1 hour).
What record types are supported?
Private DNS zones support A, AAAA, CNAME, MX, PTR, SOA, SRV, and TXT record types.
Immutability & Updates
What properties can't I change after creating a record set?
The privateZoneName, recordType, relativeRecordSetName, and resourceGroupName properties are immutable. Changing any of these requires destroying and recreating the resource.
Can I change the record type of an existing record set?
No, recordType is immutable. To change the type, you must delete the existing record set and create a new one with the desired type.
Special Record Types
How do I create an SOA record at the zone apex?
Set recordType to “SOA” and relativeRecordSetName to “@”. Configure the soaRecord object with email, host, expireTime, minimumTtl, refreshTime, retryTime, and serialNumber.
What does the isAutoRegistered property indicate?
This computed property shows whether the record set was automatically registered in the Private DNS zone through a virtual network link.

Using a different cloud?

Explore networking guides for other cloud providers: