The gcp:dns/managedZone:ManagedZone resource, part of the Pulumi GCP provider, defines a Cloud DNS managed zone: its domain name, visibility scope, and integration with VPC networks or service registries. This guide focuses on four capabilities: public and private zone visibility, DNS forwarding to on-premises name servers, VPC network and GKE cluster integration, and Service Directory-backed zones.
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 record sets.
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 (must end with a dot). The visibility defaults to “public”, making records accessible from the Internet. The labels property adds metadata for organization and cost tracking.
Restrict zone visibility to specific VPC networks
Internal services often need DNS resolution isolated from the public Internet. Private zones make records visible only to 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 access to resources in the specified networks. The privateVisibilityConfig property lists VPC networks by their resource URLs. Resources in these networks can resolve the zone’s records; external clients cannot.
Forward DNS queries to on-premises name servers
Hybrid cloud architectures often need to resolve on-premises DNS names from GCP. Forwarding sends queries for the zone’s domain to specified name servers in your data center.
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 name servers by IP address. When a VPC resource queries a name in this zone’s domain, Cloud DNS forwards the query to your on-premises servers rather than hosting records directly. This extends private zone configuration with forwarding behavior.
Make zone visible to GKE cluster workloads
GKE clusters can access private DNS zones through cluster-specific visibility, allowing pods to resolve internal service names without exposing the zone to the entire VPC.
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 in privateVisibilityConfig scopes visibility to specific clusters. Pods in the referenced cluster can resolve the zone’s records. This provides finer-grained access control than network-level visibility.
Peer DNS zones across VPC networks
Organizations with multiple VPC networks sometimes need to share DNS resolution between them. DNS peering allows one network to resolve records from a zone visible in another network.
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 network. Resources in the source network (listed in privateVisibilityConfig) can resolve records from zones visible in the target network. DNS peering works independently of VPC network peering.
Integrate with Service Directory for service discovery
Service Directory provides a managed service registry for microservices. Backing a DNS zone with Service Directory automatically creates DNS 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. Cloud DNS automatically generates DNS records for services registered in that namespace, eliminating manual record management for dynamic service inventories.
Beyond these examples
These snippets focus on specific managed zone features: public and private zone visibility, DNS forwarding and peering, and GKE cluster 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 name servers for forwarding. They focus on configuring the zone rather than provisioning the surrounding infrastructure.
To keep things focused, common zone patterns are omitted, including:
- DNSSEC configuration (dnssecConfig)
- Cloud logging setup (cloudLoggingConfig)
- Reverse lookup zones (reverseLookup)
- Force destroy for non-empty zones (forceDestroy)
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 FREEFrequently Asked Questions
Zone Configuration & Setup
dnsName property must end with a dot (e.g., my-domain.com.). This follows DNS convention where the trailing dot represents the root of the DNS hierarchy.dnsName, name, project, visibility, reverseLookup, and serviceDirectoryConfig. Changing any of these requires recreating the zone.public visibility, making them accessible from the Internet. Set visibility to private to restrict access to VPC resources.Private Zones & Networking
visibility to private and configure privateVisibilityConfig with at least one of networks (VPC network URLs) or gkeClusters (GKE cluster names).privateVisibilityConfig, use gkeClusters with gkeClusterName set to the cluster’s resource ID.DNS Forwarding & Peering
forwardingConfig) sends DNS queries to external name servers you specify. Peering (peeringConfig) shares DNS resolution with another VPC network in GCP.forwardingConfig.targetNameServers, use ipv4Address for IPv4 or ipv6Address for IPv6 addresses.Zone Management
forceDestroy to true to automatically delete all DNS records when deleting the zone. Without this, deletion will fail if records exist.labels field only manages labels defined in your Pulumi configuration. Labels set by other clients or services aren’t removed. Use effectiveLabels to view all labels on the resource.Using a different cloud?
Explore networking guides for other cloud providers: