Create and Manage GCP DNS Managed Zones

The gcp:dns/managedZone:ManagedZone resource, part of the Pulumi GCP provider, defines a Cloud DNS managed zone: the DNS namespace, visibility scope, and integration with VPC networks or Service Directory. This guide focuses on four capabilities: public and private zone creation, DNS forwarding to external resolvers, VPC network and GKE cluster visibility, and Service Directory integration.

Managed zones reference VPC networks, GKE clusters, or Service Directory namespaces that must exist separately. The examples are intentionally small. Combine them with your own network infrastructure and DNS records.

Create a public DNS zone with labels

Most DNS deployments start with a public zone that hosts records for a domain, exposing DNS records to the Internet for external resolution.

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

const example_zone = new gcp.dns.ManagedZone("example-zone", {
    name: "example-zone",
    dnsName: "my-domain.com.",
    description: "Example DNS zone",
    labels: {
        foo: "bar",
    },
});
import pulumi
import pulumi_gcp as gcp

example_zone = gcp.dns.ManagedZone("example-zone",
    name="example-zone",
    dns_name="my-domain.com.",
    description="Example DNS zone",
    labels={
        "foo": "bar",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := dns.NewManagedZone(ctx, "example-zone", &dns.ManagedZoneArgs{
			Name:        pulumi.String("example-zone"),
			DnsName:     pulumi.String("my-domain.com."),
			Description: pulumi.String("Example DNS zone"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var example_zone = new Gcp.Dns.ManagedZone("example-zone", new()
    {
        Name = "example-zone",
        DnsName = "my-domain.com.",
        Description = "Example DNS zone",
        Labels = 
        {
            { "foo", "bar" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
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 example_zone = new ManagedZone("example-zone", ManagedZoneArgs.builder()
            .name("example-zone")
            .dnsName("my-domain.com.")
            .description("Example DNS zone")
            .labels(Map.of("foo", "bar"))
            .build());

    }
}
resources:
  example-zone:
    type: gcp:dns:ManagedZone
    properties:
      name: example-zone
      dnsName: my-domain.com.
      description: Example DNS zone
      labels:
        foo: bar

The dnsName property sets the domain namespace (must end with a dot). The visibility property defaults to “public”, making records queryable by any resolver. Labels provide metadata for organization and cost tracking.

Create a private zone visible to specific VPCs

Internal applications often need DNS resolution that isn’t exposed to the Internet. Private zones resolve names only within specified VPC networks.

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

const network_1 = new gcp.compute.Network("network-1", {
    name: "network-1",
    autoCreateSubnetworks: false,
});
const network_2 = new gcp.compute.Network("network-2", {
    name: "network-2",
    autoCreateSubnetworks: false,
});
const private_zone = new gcp.dns.ManagedZone("private-zone", {
    name: "private-zone",
    dnsName: "private.example.com.",
    description: "Example private DNS zone",
    labels: {
        foo: "bar",
    },
    visibility: "private",
    privateVisibilityConfig: {
        networks: [
            {
                networkUrl: network_1.id,
            },
            {
                networkUrl: network_2.id,
            },
        ],
    },
});
import pulumi
import pulumi_gcp as gcp

network_1 = gcp.compute.Network("network-1",
    name="network-1",
    auto_create_subnetworks=False)
network_2 = gcp.compute.Network("network-2",
    name="network-2",
    auto_create_subnetworks=False)
private_zone = gcp.dns.ManagedZone("private-zone",
    name="private-zone",
    dns_name="private.example.com.",
    description="Example private DNS zone",
    labels={
        "foo": "bar",
    },
    visibility="private",
    private_visibility_config={
        "networks": [
            {
                "network_url": network_1.id,
            },
            {
                "network_url": network_2.id,
            },
        ],
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		network_1, err := compute.NewNetwork(ctx, "network-1", &compute.NetworkArgs{
			Name:                  pulumi.String("network-1"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		network_2, err := compute.NewNetwork(ctx, "network-2", &compute.NetworkArgs{
			Name:                  pulumi.String("network-2"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		_, err = dns.NewManagedZone(ctx, "private-zone", &dns.ManagedZoneArgs{
			Name:        pulumi.String("private-zone"),
			DnsName:     pulumi.String("private.example.com."),
			Description: pulumi.String("Example private DNS zone"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Visibility: pulumi.String("private"),
			PrivateVisibilityConfig: &dns.ManagedZonePrivateVisibilityConfigArgs{
				Networks: dns.ManagedZonePrivateVisibilityConfigNetworkArray{
					&dns.ManagedZonePrivateVisibilityConfigNetworkArgs{
						NetworkUrl: network_1.ID(),
					},
					&dns.ManagedZonePrivateVisibilityConfigNetworkArgs{
						NetworkUrl: network_2.ID(),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var network_1 = new Gcp.Compute.Network("network-1", new()
    {
        Name = "network-1",
        AutoCreateSubnetworks = false,
    });

    var network_2 = new Gcp.Compute.Network("network-2", new()
    {
        Name = "network-2",
        AutoCreateSubnetworks = false,
    });

    var private_zone = new Gcp.Dns.ManagedZone("private-zone", new()
    {
        Name = "private-zone",
        DnsName = "private.example.com.",
        Description = "Example private DNS zone",
        Labels = 
        {
            { "foo", "bar" },
        },
        Visibility = "private",
        PrivateVisibilityConfig = new Gcp.Dns.Inputs.ManagedZonePrivateVisibilityConfigArgs
        {
            Networks = new[]
            {
                new Gcp.Dns.Inputs.ManagedZonePrivateVisibilityConfigNetworkArgs
                {
                    NetworkUrl = network_1.Id,
                },
                new Gcp.Dns.Inputs.ManagedZonePrivateVisibilityConfigNetworkArgs
                {
                    NetworkUrl = network_2.Id,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.inputs.ManagedZonePrivateVisibilityConfigArgs;
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 network_1 = new Network("network-1", NetworkArgs.builder()
            .name("network-1")
            .autoCreateSubnetworks(false)
            .build());

        var network_2 = new Network("network-2", NetworkArgs.builder()
            .name("network-2")
            .autoCreateSubnetworks(false)
            .build());

        var private_zone = new ManagedZone("private-zone", ManagedZoneArgs.builder()
            .name("private-zone")
            .dnsName("private.example.com.")
            .description("Example private DNS zone")
            .labels(Map.of("foo", "bar"))
            .visibility("private")
            .privateVisibilityConfig(ManagedZonePrivateVisibilityConfigArgs.builder()
                .networks(                
                    ManagedZonePrivateVisibilityConfigNetworkArgs.builder()
                        .networkUrl(network_1.id())
                        .build(),
                    ManagedZonePrivateVisibilityConfigNetworkArgs.builder()
                        .networkUrl(network_2.id())
                        .build())
                .build())
            .build());

    }
}
resources:
  private-zone:
    type: gcp:dns:ManagedZone
    properties:
      name: private-zone
      dnsName: private.example.com.
      description: Example private DNS zone
      labels:
        foo: bar
      visibility: private
      privateVisibilityConfig:
        networks:
          - networkUrl: ${["network-1"].id}
          - networkUrl: ${["network-2"].id}
  network-1:
    type: gcp:compute:Network
    properties:
      name: network-1
      autoCreateSubnetworks: false
  network-2:
    type: gcp:compute:Network
    properties:
      name: network-2
      autoCreateSubnetworks: false

Setting visibility to “private” restricts queries to resources in the specified VPC networks. The privateVisibilityConfig property lists networks by their resource URLs. Each network can query records in this zone, but external resolvers cannot.

Forward DNS queries to on-premises resolvers

Hybrid cloud architectures often need to resolve on-premises domain names from GCP. Forwarding zones send queries for specific domains to your own DNS servers.

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

const network_1 = new gcp.compute.Network("network-1", {
    name: "network-1",
    autoCreateSubnetworks: false,
});
const network_2 = new gcp.compute.Network("network-2", {
    name: "network-2",
    autoCreateSubnetworks: false,
});
const private_zone = new gcp.dns.ManagedZone("private-zone", {
    name: "private-zone",
    dnsName: "private.example.com.",
    description: "Example private DNS zone",
    labels: {
        foo: "bar",
    },
    visibility: "private",
    privateVisibilityConfig: {
        networks: [
            {
                networkUrl: network_1.id,
            },
            {
                networkUrl: network_2.id,
            },
        ],
    },
    forwardingConfig: {
        targetNameServers: [
            {
                ipv4Address: "172.16.1.10",
            },
            {
                ipv4Address: "172.16.1.20",
            },
        ],
    },
});
import pulumi
import pulumi_gcp as gcp

network_1 = gcp.compute.Network("network-1",
    name="network-1",
    auto_create_subnetworks=False)
network_2 = gcp.compute.Network("network-2",
    name="network-2",
    auto_create_subnetworks=False)
private_zone = gcp.dns.ManagedZone("private-zone",
    name="private-zone",
    dns_name="private.example.com.",
    description="Example private DNS zone",
    labels={
        "foo": "bar",
    },
    visibility="private",
    private_visibility_config={
        "networks": [
            {
                "network_url": network_1.id,
            },
            {
                "network_url": network_2.id,
            },
        ],
    },
    forwarding_config={
        "target_name_servers": [
            {
                "ipv4_address": "172.16.1.10",
            },
            {
                "ipv4_address": "172.16.1.20",
            },
        ],
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		network_1, err := compute.NewNetwork(ctx, "network-1", &compute.NetworkArgs{
			Name:                  pulumi.String("network-1"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		network_2, err := compute.NewNetwork(ctx, "network-2", &compute.NetworkArgs{
			Name:                  pulumi.String("network-2"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		_, err = dns.NewManagedZone(ctx, "private-zone", &dns.ManagedZoneArgs{
			Name:        pulumi.String("private-zone"),
			DnsName:     pulumi.String("private.example.com."),
			Description: pulumi.String("Example private DNS zone"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Visibility: pulumi.String("private"),
			PrivateVisibilityConfig: &dns.ManagedZonePrivateVisibilityConfigArgs{
				Networks: dns.ManagedZonePrivateVisibilityConfigNetworkArray{
					&dns.ManagedZonePrivateVisibilityConfigNetworkArgs{
						NetworkUrl: network_1.ID(),
					},
					&dns.ManagedZonePrivateVisibilityConfigNetworkArgs{
						NetworkUrl: network_2.ID(),
					},
				},
			},
			ForwardingConfig: &dns.ManagedZoneForwardingConfigArgs{
				TargetNameServers: dns.ManagedZoneForwardingConfigTargetNameServerArray{
					&dns.ManagedZoneForwardingConfigTargetNameServerArgs{
						Ipv4Address: pulumi.String("172.16.1.10"),
					},
					&dns.ManagedZoneForwardingConfigTargetNameServerArgs{
						Ipv4Address: pulumi.String("172.16.1.20"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var network_1 = new Gcp.Compute.Network("network-1", new()
    {
        Name = "network-1",
        AutoCreateSubnetworks = false,
    });

    var network_2 = new Gcp.Compute.Network("network-2", new()
    {
        Name = "network-2",
        AutoCreateSubnetworks = false,
    });

    var private_zone = new Gcp.Dns.ManagedZone("private-zone", new()
    {
        Name = "private-zone",
        DnsName = "private.example.com.",
        Description = "Example private DNS zone",
        Labels = 
        {
            { "foo", "bar" },
        },
        Visibility = "private",
        PrivateVisibilityConfig = new Gcp.Dns.Inputs.ManagedZonePrivateVisibilityConfigArgs
        {
            Networks = new[]
            {
                new Gcp.Dns.Inputs.ManagedZonePrivateVisibilityConfigNetworkArgs
                {
                    NetworkUrl = network_1.Id,
                },
                new Gcp.Dns.Inputs.ManagedZonePrivateVisibilityConfigNetworkArgs
                {
                    NetworkUrl = network_2.Id,
                },
            },
        },
        ForwardingConfig = new Gcp.Dns.Inputs.ManagedZoneForwardingConfigArgs
        {
            TargetNameServers = new[]
            {
                new Gcp.Dns.Inputs.ManagedZoneForwardingConfigTargetNameServerArgs
                {
                    Ipv4Address = "172.16.1.10",
                },
                new Gcp.Dns.Inputs.ManagedZoneForwardingConfigTargetNameServerArgs
                {
                    Ipv4Address = "172.16.1.20",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.inputs.ManagedZonePrivateVisibilityConfigArgs;
import com.pulumi.gcp.dns.inputs.ManagedZoneForwardingConfigArgs;
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 network_1 = new Network("network-1", NetworkArgs.builder()
            .name("network-1")
            .autoCreateSubnetworks(false)
            .build());

        var network_2 = new Network("network-2", NetworkArgs.builder()
            .name("network-2")
            .autoCreateSubnetworks(false)
            .build());

        var private_zone = new ManagedZone("private-zone", ManagedZoneArgs.builder()
            .name("private-zone")
            .dnsName("private.example.com.")
            .description("Example private DNS zone")
            .labels(Map.of("foo", "bar"))
            .visibility("private")
            .privateVisibilityConfig(ManagedZonePrivateVisibilityConfigArgs.builder()
                .networks(                
                    ManagedZonePrivateVisibilityConfigNetworkArgs.builder()
                        .networkUrl(network_1.id())
                        .build(),
                    ManagedZonePrivateVisibilityConfigNetworkArgs.builder()
                        .networkUrl(network_2.id())
                        .build())
                .build())
            .forwardingConfig(ManagedZoneForwardingConfigArgs.builder()
                .targetNameServers(                
                    ManagedZoneForwardingConfigTargetNameServerArgs.builder()
                        .ipv4Address("172.16.1.10")
                        .build(),
                    ManagedZoneForwardingConfigTargetNameServerArgs.builder()
                        .ipv4Address("172.16.1.20")
                        .build())
                .build())
            .build());

    }
}
resources:
  private-zone:
    type: gcp:dns:ManagedZone
    properties:
      name: private-zone
      dnsName: private.example.com.
      description: Example private DNS zone
      labels:
        foo: bar
      visibility: private
      privateVisibilityConfig:
        networks:
          - networkUrl: ${["network-1"].id}
          - networkUrl: ${["network-2"].id}
      forwardingConfig:
        targetNameServers:
          - ipv4Address: 172.16.1.10
          - ipv4Address: 172.16.1.20
  network-1:
    type: gcp:compute:Network
    properties:
      name: network-1
      autoCreateSubnetworks: false
  network-2:
    type: gcp:compute:Network
    properties:
      name: network-2
      autoCreateSubnetworks: false

The forwardingConfig property defines target DNS servers by IP address. When a VPC resource queries this zone’s domain, Cloud DNS forwards the request to your specified resolvers instead of hosting records directly. This extends private zone configuration with forwarding behavior.

Make a private zone visible to GKE clusters

GKE workloads often need to resolve custom domain names for internal services. Private zones can be scoped to specific GKE clusters, allowing pods to query your DNS records.

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

const network_1 = new gcp.compute.Network("network-1", {
    name: "network-1",
    autoCreateSubnetworks: false,
});
const subnetwork_1 = new gcp.compute.Subnetwork("subnetwork-1", {
    name: network_1.name,
    network: network_1.name,
    ipCidrRange: "10.0.36.0/24",
    region: "us-central1",
    privateIpGoogleAccess: true,
    secondaryIpRanges: [
        {
            rangeName: "pod",
            ipCidrRange: "10.0.0.0/19",
        },
        {
            rangeName: "svc",
            ipCidrRange: "10.0.32.0/22",
        },
    ],
});
const cluster_1 = new gcp.container.Cluster("cluster-1", {
    name: "cluster-1",
    location: "us-central1-c",
    initialNodeCount: 1,
    networkingMode: "VPC_NATIVE",
    defaultSnatStatus: {
        disabled: true,
    },
    network: network_1.name,
    subnetwork: subnetwork_1.name,
    privateClusterConfig: {
        enablePrivateEndpoint: true,
        enablePrivateNodes: true,
        masterIpv4CidrBlock: "10.42.0.0/28",
        masterGlobalAccessConfig: {
            enabled: true,
        },
    },
    masterAuthorizedNetworksConfig: {},
    ipAllocationPolicy: {
        clusterSecondaryRangeName: subnetwork_1.secondaryIpRanges.apply(secondaryIpRanges => secondaryIpRanges[0].rangeName),
        servicesSecondaryRangeName: subnetwork_1.secondaryIpRanges.apply(secondaryIpRanges => secondaryIpRanges[1].rangeName),
    },
    deletionProtection: true,
});
const private_zone_gke = new gcp.dns.ManagedZone("private-zone-gke", {
    name: "private-zone",
    dnsName: "private.example.com.",
    description: "Example private DNS zone",
    labels: {
        foo: "bar",
    },
    visibility: "private",
    privateVisibilityConfig: {
        gkeClusters: [{
            gkeClusterName: cluster_1.id,
        }],
    },
});
import pulumi
import pulumi_gcp as gcp

network_1 = gcp.compute.Network("network-1",
    name="network-1",
    auto_create_subnetworks=False)
subnetwork_1 = gcp.compute.Subnetwork("subnetwork-1",
    name=network_1.name,
    network=network_1.name,
    ip_cidr_range="10.0.36.0/24",
    region="us-central1",
    private_ip_google_access=True,
    secondary_ip_ranges=[
        {
            "range_name": "pod",
            "ip_cidr_range": "10.0.0.0/19",
        },
        {
            "range_name": "svc",
            "ip_cidr_range": "10.0.32.0/22",
        },
    ])
cluster_1 = gcp.container.Cluster("cluster-1",
    name="cluster-1",
    location="us-central1-c",
    initial_node_count=1,
    networking_mode="VPC_NATIVE",
    default_snat_status={
        "disabled": True,
    },
    network=network_1.name,
    subnetwork=subnetwork_1.name,
    private_cluster_config={
        "enable_private_endpoint": True,
        "enable_private_nodes": True,
        "master_ipv4_cidr_block": "10.42.0.0/28",
        "master_global_access_config": {
            "enabled": True,
        },
    },
    master_authorized_networks_config={},
    ip_allocation_policy={
        "cluster_secondary_range_name": subnetwork_1.secondary_ip_ranges[0].range_name,
        "services_secondary_range_name": subnetwork_1.secondary_ip_ranges[1].range_name,
    },
    deletion_protection=True)
private_zone_gke = gcp.dns.ManagedZone("private-zone-gke",
    name="private-zone",
    dns_name="private.example.com.",
    description="Example private DNS zone",
    labels={
        "foo": "bar",
    },
    visibility="private",
    private_visibility_config={
        "gke_clusters": [{
            "gke_cluster_name": cluster_1.id,
        }],
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/container"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		network_1, err := compute.NewNetwork(ctx, "network-1", &compute.NetworkArgs{
			Name:                  pulumi.String("network-1"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		subnetwork_1, err := compute.NewSubnetwork(ctx, "subnetwork-1", &compute.SubnetworkArgs{
			Name:                  network_1.Name,
			Network:               network_1.Name,
			IpCidrRange:           pulumi.String("10.0.36.0/24"),
			Region:                pulumi.String("us-central1"),
			PrivateIpGoogleAccess: pulumi.Bool(true),
			SecondaryIpRanges: compute.SubnetworkSecondaryIpRangeArray{
				&compute.SubnetworkSecondaryIpRangeArgs{
					RangeName:   pulumi.String("pod"),
					IpCidrRange: pulumi.String("10.0.0.0/19"),
				},
				&compute.SubnetworkSecondaryIpRangeArgs{
					RangeName:   pulumi.String("svc"),
					IpCidrRange: pulumi.String("10.0.32.0/22"),
				},
			},
		})
		if err != nil {
			return err
		}
		cluster_1, err := container.NewCluster(ctx, "cluster-1", &container.ClusterArgs{
			Name:             pulumi.String("cluster-1"),
			Location:         pulumi.String("us-central1-c"),
			InitialNodeCount: pulumi.Int(1),
			NetworkingMode:   pulumi.String("VPC_NATIVE"),
			DefaultSnatStatus: &container.ClusterDefaultSnatStatusArgs{
				Disabled: pulumi.Bool(true),
			},
			Network:    network_1.Name,
			Subnetwork: subnetwork_1.Name,
			PrivateClusterConfig: &container.ClusterPrivateClusterConfigArgs{
				EnablePrivateEndpoint: pulumi.Bool(true),
				EnablePrivateNodes:    pulumi.Bool(true),
				MasterIpv4CidrBlock:   pulumi.String("10.42.0.0/28"),
				MasterGlobalAccessConfig: &container.ClusterPrivateClusterConfigMasterGlobalAccessConfigArgs{
					Enabled: pulumi.Bool(true),
				},
			},
			MasterAuthorizedNetworksConfig: &container.ClusterMasterAuthorizedNetworksConfigArgs{},
			IpAllocationPolicy: &container.ClusterIpAllocationPolicyArgs{
				ClusterSecondaryRangeName: subnetwork_1.SecondaryIpRanges.ApplyT(func(secondaryIpRanges []compute.SubnetworkSecondaryIpRange) (*string, error) {
					return &secondaryIpRanges[0].RangeName, nil
				}).(pulumi.StringPtrOutput),
				ServicesSecondaryRangeName: subnetwork_1.SecondaryIpRanges.ApplyT(func(secondaryIpRanges []compute.SubnetworkSecondaryIpRange) (*string, error) {
					return &secondaryIpRanges[1].RangeName, nil
				}).(pulumi.StringPtrOutput),
			},
			DeletionProtection: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = dns.NewManagedZone(ctx, "private-zone-gke", &dns.ManagedZoneArgs{
			Name:        pulumi.String("private-zone"),
			DnsName:     pulumi.String("private.example.com."),
			Description: pulumi.String("Example private DNS zone"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Visibility: pulumi.String("private"),
			PrivateVisibilityConfig: &dns.ManagedZonePrivateVisibilityConfigArgs{
				GkeClusters: dns.ManagedZonePrivateVisibilityConfigGkeClusterArray{
					&dns.ManagedZonePrivateVisibilityConfigGkeClusterArgs{
						GkeClusterName: cluster_1.ID(),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var network_1 = new Gcp.Compute.Network("network-1", new()
    {
        Name = "network-1",
        AutoCreateSubnetworks = false,
    });

    var subnetwork_1 = new Gcp.Compute.Subnetwork("subnetwork-1", new()
    {
        Name = network_1.Name,
        Network = network_1.Name,
        IpCidrRange = "10.0.36.0/24",
        Region = "us-central1",
        PrivateIpGoogleAccess = true,
        SecondaryIpRanges = new[]
        {
            new Gcp.Compute.Inputs.SubnetworkSecondaryIpRangeArgs
            {
                RangeName = "pod",
                IpCidrRange = "10.0.0.0/19",
            },
            new Gcp.Compute.Inputs.SubnetworkSecondaryIpRangeArgs
            {
                RangeName = "svc",
                IpCidrRange = "10.0.32.0/22",
            },
        },
    });

    var cluster_1 = new Gcp.Container.Cluster("cluster-1", new()
    {
        Name = "cluster-1",
        Location = "us-central1-c",
        InitialNodeCount = 1,
        NetworkingMode = "VPC_NATIVE",
        DefaultSnatStatus = new Gcp.Container.Inputs.ClusterDefaultSnatStatusArgs
        {
            Disabled = true,
        },
        Network = network_1.Name,
        Subnetwork = subnetwork_1.Name,
        PrivateClusterConfig = new Gcp.Container.Inputs.ClusterPrivateClusterConfigArgs
        {
            EnablePrivateEndpoint = true,
            EnablePrivateNodes = true,
            MasterIpv4CidrBlock = "10.42.0.0/28",
            MasterGlobalAccessConfig = new Gcp.Container.Inputs.ClusterPrivateClusterConfigMasterGlobalAccessConfigArgs
            {
                Enabled = true,
            },
        },
        MasterAuthorizedNetworksConfig = null,
        IpAllocationPolicy = new Gcp.Container.Inputs.ClusterIpAllocationPolicyArgs
        {
            ClusterSecondaryRangeName = subnetwork_1.SecondaryIpRanges.Apply(secondaryIpRanges => secondaryIpRanges[0].RangeName),
            ServicesSecondaryRangeName = subnetwork_1.SecondaryIpRanges.Apply(secondaryIpRanges => secondaryIpRanges[1].RangeName),
        },
        DeletionProtection = true,
    });

    var private_zone_gke = new Gcp.Dns.ManagedZone("private-zone-gke", new()
    {
        Name = "private-zone",
        DnsName = "private.example.com.",
        Description = "Example private DNS zone",
        Labels = 
        {
            { "foo", "bar" },
        },
        Visibility = "private",
        PrivateVisibilityConfig = new Gcp.Dns.Inputs.ManagedZonePrivateVisibilityConfigArgs
        {
            GkeClusters = new[]
            {
                new Gcp.Dns.Inputs.ManagedZonePrivateVisibilityConfigGkeClusterArgs
                {
                    GkeClusterName = cluster_1.Id,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.Subnetwork;
import com.pulumi.gcp.compute.SubnetworkArgs;
import com.pulumi.gcp.compute.inputs.SubnetworkSecondaryIpRangeArgs;
import com.pulumi.gcp.container.Cluster;
import com.pulumi.gcp.container.ClusterArgs;
import com.pulumi.gcp.container.inputs.ClusterDefaultSnatStatusArgs;
import com.pulumi.gcp.container.inputs.ClusterPrivateClusterConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterPrivateClusterConfigMasterGlobalAccessConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterMasterAuthorizedNetworksConfigArgs;
import com.pulumi.gcp.container.inputs.ClusterIpAllocationPolicyArgs;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.inputs.ManagedZonePrivateVisibilityConfigArgs;
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 network_1 = new Network("network-1", NetworkArgs.builder()
            .name("network-1")
            .autoCreateSubnetworks(false)
            .build());

        var subnetwork_1 = new Subnetwork("subnetwork-1", SubnetworkArgs.builder()
            .name(network_1.name())
            .network(network_1.name())
            .ipCidrRange("10.0.36.0/24")
            .region("us-central1")
            .privateIpGoogleAccess(true)
            .secondaryIpRanges(            
                SubnetworkSecondaryIpRangeArgs.builder()
                    .rangeName("pod")
                    .ipCidrRange("10.0.0.0/19")
                    .build(),
                SubnetworkSecondaryIpRangeArgs.builder()
                    .rangeName("svc")
                    .ipCidrRange("10.0.32.0/22")
                    .build())
            .build());

        var cluster_1 = new Cluster("cluster-1", ClusterArgs.builder()
            .name("cluster-1")
            .location("us-central1-c")
            .initialNodeCount(1)
            .networkingMode("VPC_NATIVE")
            .defaultSnatStatus(ClusterDefaultSnatStatusArgs.builder()
                .disabled(true)
                .build())
            .network(network_1.name())
            .subnetwork(subnetwork_1.name())
            .privateClusterConfig(ClusterPrivateClusterConfigArgs.builder()
                .enablePrivateEndpoint(true)
                .enablePrivateNodes(true)
                .masterIpv4CidrBlock("10.42.0.0/28")
                .masterGlobalAccessConfig(ClusterPrivateClusterConfigMasterGlobalAccessConfigArgs.builder()
                    .enabled(true)
                    .build())
                .build())
            .masterAuthorizedNetworksConfig(ClusterMasterAuthorizedNetworksConfigArgs.builder()
                .build())
            .ipAllocationPolicy(ClusterIpAllocationPolicyArgs.builder()
                .clusterSecondaryRangeName(subnetwork_1.secondaryIpRanges().applyValue(_secondaryIpRanges -> _secondaryIpRanges[0].rangeName()))
                .servicesSecondaryRangeName(subnetwork_1.secondaryIpRanges().applyValue(_secondaryIpRanges -> _secondaryIpRanges[1].rangeName()))
                .build())
            .deletionProtection(true)
            .build());

        var private_zone_gke = new ManagedZone("private-zone-gke", ManagedZoneArgs.builder()
            .name("private-zone")
            .dnsName("private.example.com.")
            .description("Example private DNS zone")
            .labels(Map.of("foo", "bar"))
            .visibility("private")
            .privateVisibilityConfig(ManagedZonePrivateVisibilityConfigArgs.builder()
                .gkeClusters(ManagedZonePrivateVisibilityConfigGkeClusterArgs.builder()
                    .gkeClusterName(cluster_1.id())
                    .build())
                .build())
            .build());

    }
}
resources:
  private-zone-gke:
    type: gcp:dns:ManagedZone
    properties:
      name: private-zone
      dnsName: private.example.com.
      description: Example private DNS zone
      labels:
        foo: bar
      visibility: private
      privateVisibilityConfig:
        gkeClusters:
          - gkeClusterName: ${["cluster-1"].id}
  network-1:
    type: gcp:compute:Network
    properties:
      name: network-1
      autoCreateSubnetworks: false
  subnetwork-1:
    type: gcp:compute:Subnetwork
    properties:
      name: ${["network-1"].name}
      network: ${["network-1"].name}
      ipCidrRange: 10.0.36.0/24
      region: us-central1
      privateIpGoogleAccess: true
      secondaryIpRanges:
        - rangeName: pod
          ipCidrRange: 10.0.0.0/19
        - rangeName: svc
          ipCidrRange: 10.0.32.0/22
  cluster-1:
    type: gcp:container:Cluster
    properties:
      name: cluster-1
      location: us-central1-c
      initialNodeCount: 1
      networkingMode: VPC_NATIVE
      defaultSnatStatus:
        disabled: true
      network: ${["network-1"].name}
      subnetwork: ${["subnetwork-1"].name}
      privateClusterConfig:
        enablePrivateEndpoint: true
        enablePrivateNodes: true
        masterIpv4CidrBlock: 10.42.0.0/28
        masterGlobalAccessConfig:
          enabled: true
      masterAuthorizedNetworksConfig: {}
      ipAllocationPolicy:
        clusterSecondaryRangeName: ${["subnetwork-1"].secondaryIpRanges[0].rangeName}
        servicesSecondaryRangeName: ${["subnetwork-1"].secondaryIpRanges[1].rangeName}
      deletionProtection: true

The gkeClusters property within privateVisibilityConfig restricts visibility to specific GKE clusters by their resource IDs. Pods in these clusters can resolve the zone’s domain, but other VPC resources cannot unless also listed in the networks property.

Peer DNS zones across VPC networks

Organizations with multiple VPC networks sometimes need to share DNS resolution between them. DNS peering allows one VPC to query private zones defined in another VPC.

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

const network_source = new gcp.compute.Network("network-source", {
    name: "network-source",
    autoCreateSubnetworks: false,
});
const network_target = new gcp.compute.Network("network-target", {
    name: "network-target",
    autoCreateSubnetworks: false,
});
const peering_zone = new gcp.dns.ManagedZone("peering-zone", {
    name: "peering-zone",
    dnsName: "peering.example.com.",
    description: "Example private DNS peering zone",
    visibility: "private",
    privateVisibilityConfig: {
        networks: [{
            networkUrl: network_source.id,
        }],
    },
    peeringConfig: {
        targetNetwork: {
            networkUrl: network_target.id,
        },
    },
});
import pulumi
import pulumi_gcp as gcp

network_source = gcp.compute.Network("network-source",
    name="network-source",
    auto_create_subnetworks=False)
network_target = gcp.compute.Network("network-target",
    name="network-target",
    auto_create_subnetworks=False)
peering_zone = gcp.dns.ManagedZone("peering-zone",
    name="peering-zone",
    dns_name="peering.example.com.",
    description="Example private DNS peering zone",
    visibility="private",
    private_visibility_config={
        "networks": [{
            "network_url": network_source.id,
        }],
    },
    peering_config={
        "target_network": {
            "network_url": network_target.id,
        },
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		network_source, err := compute.NewNetwork(ctx, "network-source", &compute.NetworkArgs{
			Name:                  pulumi.String("network-source"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		network_target, err := compute.NewNetwork(ctx, "network-target", &compute.NetworkArgs{
			Name:                  pulumi.String("network-target"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		_, err = dns.NewManagedZone(ctx, "peering-zone", &dns.ManagedZoneArgs{
			Name:        pulumi.String("peering-zone"),
			DnsName:     pulumi.String("peering.example.com."),
			Description: pulumi.String("Example private DNS peering zone"),
			Visibility:  pulumi.String("private"),
			PrivateVisibilityConfig: &dns.ManagedZonePrivateVisibilityConfigArgs{
				Networks: dns.ManagedZonePrivateVisibilityConfigNetworkArray{
					&dns.ManagedZonePrivateVisibilityConfigNetworkArgs{
						NetworkUrl: network_source.ID(),
					},
				},
			},
			PeeringConfig: &dns.ManagedZonePeeringConfigArgs{
				TargetNetwork: &dns.ManagedZonePeeringConfigTargetNetworkArgs{
					NetworkUrl: network_target.ID(),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var network_source = new Gcp.Compute.Network("network-source", new()
    {
        Name = "network-source",
        AutoCreateSubnetworks = false,
    });

    var network_target = new Gcp.Compute.Network("network-target", new()
    {
        Name = "network-target",
        AutoCreateSubnetworks = false,
    });

    var peering_zone = new Gcp.Dns.ManagedZone("peering-zone", new()
    {
        Name = "peering-zone",
        DnsName = "peering.example.com.",
        Description = "Example private DNS peering zone",
        Visibility = "private",
        PrivateVisibilityConfig = new Gcp.Dns.Inputs.ManagedZonePrivateVisibilityConfigArgs
        {
            Networks = new[]
            {
                new Gcp.Dns.Inputs.ManagedZonePrivateVisibilityConfigNetworkArgs
                {
                    NetworkUrl = network_source.Id,
                },
            },
        },
        PeeringConfig = new Gcp.Dns.Inputs.ManagedZonePeeringConfigArgs
        {
            TargetNetwork = new Gcp.Dns.Inputs.ManagedZonePeeringConfigTargetNetworkArgs
            {
                NetworkUrl = network_target.Id,
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.inputs.ManagedZonePrivateVisibilityConfigArgs;
import com.pulumi.gcp.dns.inputs.ManagedZonePeeringConfigArgs;
import com.pulumi.gcp.dns.inputs.ManagedZonePeeringConfigTargetNetworkArgs;
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 network_source = new Network("network-source", NetworkArgs.builder()
            .name("network-source")
            .autoCreateSubnetworks(false)
            .build());

        var network_target = new Network("network-target", NetworkArgs.builder()
            .name("network-target")
            .autoCreateSubnetworks(false)
            .build());

        var peering_zone = new ManagedZone("peering-zone", ManagedZoneArgs.builder()
            .name("peering-zone")
            .dnsName("peering.example.com.")
            .description("Example private DNS peering zone")
            .visibility("private")
            .privateVisibilityConfig(ManagedZonePrivateVisibilityConfigArgs.builder()
                .networks(ManagedZonePrivateVisibilityConfigNetworkArgs.builder()
                    .networkUrl(network_source.id())
                    .build())
                .build())
            .peeringConfig(ManagedZonePeeringConfigArgs.builder()
                .targetNetwork(ManagedZonePeeringConfigTargetNetworkArgs.builder()
                    .networkUrl(network_target.id())
                    .build())
                .build())
            .build());

    }
}
resources:
  peering-zone:
    type: gcp:dns:ManagedZone
    properties:
      name: peering-zone
      dnsName: peering.example.com.
      description: Example private DNS peering zone
      visibility: private
      privateVisibilityConfig:
        networks:
          - networkUrl: ${["network-source"].id}
      peeringConfig:
        targetNetwork:
          networkUrl: ${["network-target"].id}
  network-source:
    type: gcp:compute:Network
    properties:
      name: network-source
      autoCreateSubnetworks: false
  network-target:
    type: gcp:compute:Network
    properties:
      name: network-target
      autoCreateSubnetworks: false

The peeringConfig property specifies a target VPC network. Resources in the source network (listed in privateVisibilityConfig) can query private zones defined in the target network. DNS peering works independently of VPC network peering.

Integrate with Service Directory namespaces

Service Directory provides service registration and discovery for GCP resources. When you back a DNS zone with a Service Directory namespace, Cloud DNS automatically creates records for registered services.

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

const example = new gcp.servicedirectory.Namespace("example", {
    namespaceId: "example",
    location: "us-central1",
});
const sd_zone = new gcp.dns.ManagedZone("sd-zone", {
    name: "peering-zone",
    dnsName: "services.example.com.",
    description: "Example private DNS Service Directory zone",
    visibility: "private",
    serviceDirectoryConfig: {
        namespace: {
            namespaceUrl: example.id,
        },
    },
});
const network = new gcp.compute.Network("network", {
    name: "network",
    autoCreateSubnetworks: false,
});
import pulumi
import pulumi_gcp as gcp

example = gcp.servicedirectory.Namespace("example",
    namespace_id="example",
    location="us-central1")
sd_zone = gcp.dns.ManagedZone("sd-zone",
    name="peering-zone",
    dns_name="services.example.com.",
    description="Example private DNS Service Directory zone",
    visibility="private",
    service_directory_config={
        "namespace": {
            "namespace_url": example.id,
        },
    })
network = gcp.compute.Network("network",
    name="network",
    auto_create_subnetworks=False)
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/servicedirectory"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		example, err := servicedirectory.NewNamespace(ctx, "example", &servicedirectory.NamespaceArgs{
			NamespaceId: pulumi.String("example"),
			Location:    pulumi.String("us-central1"),
		})
		if err != nil {
			return err
		}
		_, err = dns.NewManagedZone(ctx, "sd-zone", &dns.ManagedZoneArgs{
			Name:        pulumi.String("peering-zone"),
			DnsName:     pulumi.String("services.example.com."),
			Description: pulumi.String("Example private DNS Service Directory zone"),
			Visibility:  pulumi.String("private"),
			ServiceDirectoryConfig: &dns.ManagedZoneServiceDirectoryConfigArgs{
				Namespace: &dns.ManagedZoneServiceDirectoryConfigNamespaceArgs{
					NamespaceUrl: example.ID(),
				},
			},
		})
		if err != nil {
			return err
		}
		_, err = compute.NewNetwork(ctx, "network", &compute.NetworkArgs{
			Name:                  pulumi.String("network"),
			AutoCreateSubnetworks: pulumi.Bool(false),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var example = new Gcp.ServiceDirectory.Namespace("example", new()
    {
        NamespaceId = "example",
        Location = "us-central1",
    });

    var sd_zone = new Gcp.Dns.ManagedZone("sd-zone", new()
    {
        Name = "peering-zone",
        DnsName = "services.example.com.",
        Description = "Example private DNS Service Directory zone",
        Visibility = "private",
        ServiceDirectoryConfig = new Gcp.Dns.Inputs.ManagedZoneServiceDirectoryConfigArgs
        {
            Namespace = new Gcp.Dns.Inputs.ManagedZoneServiceDirectoryConfigNamespaceArgs
            {
                NamespaceUrl = example.Id,
            },
        },
    });

    var network = new Gcp.Compute.Network("network", new()
    {
        Name = "network",
        AutoCreateSubnetworks = false,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.servicedirectory.Namespace;
import com.pulumi.gcp.servicedirectory.NamespaceArgs;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.inputs.ManagedZoneServiceDirectoryConfigArgs;
import com.pulumi.gcp.dns.inputs.ManagedZoneServiceDirectoryConfigNamespaceArgs;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
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 example = new Namespace("example", NamespaceArgs.builder()
            .namespaceId("example")
            .location("us-central1")
            .build());

        var sd_zone = new ManagedZone("sd-zone", ManagedZoneArgs.builder()
            .name("peering-zone")
            .dnsName("services.example.com.")
            .description("Example private DNS Service Directory zone")
            .visibility("private")
            .serviceDirectoryConfig(ManagedZoneServiceDirectoryConfigArgs.builder()
                .namespace(ManagedZoneServiceDirectoryConfigNamespaceArgs.builder()
                    .namespaceUrl(example.id())
                    .build())
                .build())
            .build());

        var network = new Network("network", NetworkArgs.builder()
            .name("network")
            .autoCreateSubnetworks(false)
            .build());

    }
}
resources:
  sd-zone:
    type: gcp:dns:ManagedZone
    properties:
      name: peering-zone
      dnsName: services.example.com.
      description: Example private DNS Service Directory zone
      visibility: private
      serviceDirectoryConfig:
        namespace:
          namespaceUrl: ${example.id}
  example:
    type: gcp:servicedirectory:Namespace
    properties:
      namespaceId: example
      location: us-central1
  network:
    type: gcp:compute:Network
    properties:
      name: network
      autoCreateSubnetworks: false

The serviceDirectoryConfig property links the zone to a Service Directory namespace by its resource URL. Cloud DNS automatically generates DNS records for services registered in that namespace, eliminating manual record management.

Enable query logging for DNS zones

DNS query logs help with troubleshooting, security analysis, and compliance. Cloud Logging integration captures all queries to your zone.

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

const cloud_logging_enabled_zone = new gcp.dns.ManagedZone("cloud-logging-enabled-zone", {
    name: "cloud-logging-enabled-zone",
    dnsName: "services.example.com.",
    description: "Example cloud logging enabled DNS zone",
    labels: {
        foo: "bar",
    },
    cloudLoggingConfig: {
        enableLogging: true,
    },
});
import pulumi
import pulumi_gcp as gcp

cloud_logging_enabled_zone = gcp.dns.ManagedZone("cloud-logging-enabled-zone",
    name="cloud-logging-enabled-zone",
    dns_name="services.example.com.",
    description="Example cloud logging enabled DNS zone",
    labels={
        "foo": "bar",
    },
    cloud_logging_config={
        "enable_logging": True,
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := dns.NewManagedZone(ctx, "cloud-logging-enabled-zone", &dns.ManagedZoneArgs{
			Name:        pulumi.String("cloud-logging-enabled-zone"),
			DnsName:     pulumi.String("services.example.com."),
			Description: pulumi.String("Example cloud logging enabled DNS zone"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			CloudLoggingConfig: &dns.ManagedZoneCloudLoggingConfigArgs{
				EnableLogging: pulumi.Bool(true),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var cloud_logging_enabled_zone = new Gcp.Dns.ManagedZone("cloud-logging-enabled-zone", new()
    {
        Name = "cloud-logging-enabled-zone",
        DnsName = "services.example.com.",
        Description = "Example cloud logging enabled DNS zone",
        Labels = 
        {
            { "foo", "bar" },
        },
        CloudLoggingConfig = new Gcp.Dns.Inputs.ManagedZoneCloudLoggingConfigArgs
        {
            EnableLogging = true,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.inputs.ManagedZoneCloudLoggingConfigArgs;
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 cloud_logging_enabled_zone = new ManagedZone("cloud-logging-enabled-zone", ManagedZoneArgs.builder()
            .name("cloud-logging-enabled-zone")
            .dnsName("services.example.com.")
            .description("Example cloud logging enabled DNS zone")
            .labels(Map.of("foo", "bar"))
            .cloudLoggingConfig(ManagedZoneCloudLoggingConfigArgs.builder()
                .enableLogging(true)
                .build())
            .build());

    }
}
resources:
  cloud-logging-enabled-zone:
    type: gcp:dns:ManagedZone
    properties:
      name: cloud-logging-enabled-zone
      dnsName: services.example.com.
      description: Example cloud logging enabled DNS zone
      labels:
        foo: bar
      cloudLoggingConfig:
        enableLogging: true

The cloudLoggingConfig property enables query logging when enableLogging is true. Cloud DNS sends query logs to Cloud Logging, including query name, type, response code, and timestamp.

Beyond these examples

These snippets focus on specific managed zone features: public and private zone visibility, DNS forwarding and peering, and GKE and Service Directory integration. They’re intentionally minimal rather than full DNS deployments.

The examples may reference pre-existing infrastructure such as VPC networks and subnets, GKE clusters with VPC-native networking, Service Directory namespaces, and on-premises DNS servers for forwarding. They focus on configuring the zone rather than provisioning everything around it.

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

  • DNSSEC configuration (dnssecConfig)
  • Reverse lookup zones (reverseLookup)
  • Force destroy for non-empty zones (forceDestroy)
  • DNS record management (separate RecordSet resource)

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

Let's create and Manage GCP DNS Managed Zones

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Zone Configuration & Immutability
What properties can't I change after creating a managed zone?
The following properties are immutable and require resource replacement if changed: dnsName, name, project, visibility, reverseLookup, and serviceDirectoryConfig.
What's the difference between public and private DNS zones?
Public zones are exposed to the Internet, while private zones are visible only to specified VPC resources. The default visibility is public.
What's the default description for a managed zone?
The default description is “Managed by Pulumi” if not explicitly specified.
Private Zones & Visibility
How do I create a private DNS zone?
Set visibility to private and configure privateVisibilityConfig with at least one of networks or gkeClusters.
Can I connect a private zone to multiple VPCs?
Yes, specify multiple networks in the privateVisibilityConfig.networks array, each with a networkUrl.
Can I make a private zone visible to GKE clusters?
Yes, use privateVisibilityConfig.gkeClusters with the cluster’s resource ID in gkeClusterName.
What's a reverse lookup zone?
When reverseLookup is true, Cloud DNS automatically resolves reverse lookup queries for VPC resources listed in privateVisibilityConfig. This property is immutable.
DNS Forwarding & Peering
How do I forward DNS queries to my own nameservers?
Configure forwardingConfig.targetNameServers with either ipv4Address or ipv6Address for each destination nameserver.
What's the difference between DNS peering and forwarding?
DNS peering (peeringConfig) connects your zone to another network’s zone for resolution, while forwarding (forwardingConfig) sends queries to specific nameserver IP addresses.
Labels & Metadata
Why aren't all my labels showing up in the labels field?
The labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to see all labels present on the resource, including those set by other clients.
Deletion & Cleanup
How do I safely delete a zone that contains DNS records?
Set forceDestroy to true to automatically delete all records in the zone when the resource is destroyed.

Using a different cloud?

Explore networking guides for other cloud providers: