Configure GCP Public Advertised Prefixes

The gcp:compute/publicAdvertisedPrefix:PublicAdvertisedPrefix resource, part of the Pulumi GCP provider, registers IP address ranges you own with Google Cloud for BYOIP (bring your own IP) scenarios. This guide focuses on three capabilities: IPv4 prefix registration with DNS verification, regional scoping for faster delegation, and IPv6 internal access configuration.

You must own the IP ranges before registering them. IPv4 prefixes require DNS verification to prove ownership. The examples are intentionally small. Combine them with public delegated prefix resources to actually use the addresses.

Organizations bringing their own IP addresses start by registering an IPv4 prefix and proving ownership through DNS verification.

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

const prefixes = new gcp.compute.PublicAdvertisedPrefix("prefixes", {
    name: "my-prefix",
    description: "description",
    dnsVerificationIp: "127.127.0.0",
    ipCidrRange: "127.127.0.0/16",
});
import pulumi
import pulumi_gcp as gcp

prefixes = gcp.compute.PublicAdvertisedPrefix("prefixes",
    name="my-prefix",
    description="description",
    dns_verification_ip="127.127.0.0",
    ip_cidr_range="127.127.0.0/16")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewPublicAdvertisedPrefix(ctx, "prefixes", &compute.PublicAdvertisedPrefixArgs{
			Name:              pulumi.String("my-prefix"),
			Description:       pulumi.String("description"),
			DnsVerificationIp: pulumi.String("127.127.0.0"),
			IpCidrRange:       pulumi.String("127.127.0.0/16"),
		})
		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 prefixes = new Gcp.Compute.PublicAdvertisedPrefix("prefixes", new()
    {
        Name = "my-prefix",
        Description = "description",
        DnsVerificationIp = "127.127.0.0",
        IpCidrRange = "127.127.0.0/16",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.PublicAdvertisedPrefix;
import com.pulumi.gcp.compute.PublicAdvertisedPrefixArgs;
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 prefixes = new PublicAdvertisedPrefix("prefixes", PublicAdvertisedPrefixArgs.builder()
            .name("my-prefix")
            .description("description")
            .dnsVerificationIp("127.127.0.0")
            .ipCidrRange("127.127.0.0/16")
            .build());

    }
}
resources:
  prefixes:
    type: gcp:compute:PublicAdvertisedPrefix
    properties:
      name: my-prefix
      description: description
      dnsVerificationIp: 127.127.0.0
      ipCidrRange: 127.127.0.0/16

The ipCidrRange defines the address block you’re bringing to Google Cloud. The dnsVerificationIp must be configured in your DNS records to prove you control the range. Google Cloud validates this IP before allowing the prefix to be used.

Set regional scope for delegated prefixes

When delegating portions of your prefix to specific regions, regional scoping reduces provisioning time from weeks to minutes.

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

const prefixes = new gcp.compute.PublicAdvertisedPrefix("prefixes", {
    name: "my-pap",
    description: "description",
    dnsVerificationIp: "127.127.0.0",
    ipCidrRange: "127.127.0.0/16",
    pdpScope: "REGIONAL",
});
import pulumi
import pulumi_gcp as gcp

prefixes = gcp.compute.PublicAdvertisedPrefix("prefixes",
    name="my-pap",
    description="description",
    dns_verification_ip="127.127.0.0",
    ip_cidr_range="127.127.0.0/16",
    pdp_scope="REGIONAL")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewPublicAdvertisedPrefix(ctx, "prefixes", &compute.PublicAdvertisedPrefixArgs{
			Name:              pulumi.String("my-pap"),
			Description:       pulumi.String("description"),
			DnsVerificationIp: pulumi.String("127.127.0.0"),
			IpCidrRange:       pulumi.String("127.127.0.0/16"),
			PdpScope:          pulumi.String("REGIONAL"),
		})
		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 prefixes = new Gcp.Compute.PublicAdvertisedPrefix("prefixes", new()
    {
        Name = "my-pap",
        Description = "description",
        DnsVerificationIp = "127.127.0.0",
        IpCidrRange = "127.127.0.0/16",
        PdpScope = "REGIONAL",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.PublicAdvertisedPrefix;
import com.pulumi.gcp.compute.PublicAdvertisedPrefixArgs;
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 prefixes = new PublicAdvertisedPrefix("prefixes", PublicAdvertisedPrefixArgs.builder()
            .name("my-pap")
            .description("description")
            .dnsVerificationIp("127.127.0.0")
            .ipCidrRange("127.127.0.0/16")
            .pdpScope("REGIONAL")
            .build());

    }
}
resources:
  prefixes:
    type: gcp:compute:PublicAdvertisedPrefix
    properties:
      name: my-pap
      description: description
      dnsVerificationIp: 127.127.0.0
      ipCidrRange: 127.127.0.0/16
      pdpScope: REGIONAL

The pdpScope property controls how child public delegated prefixes are scoped. Setting it to REGIONAL provisions in minutes rather than the ~4 weeks required for GLOBAL scope. Use REGIONAL when you know which regions will use the prefix.

Configure IPv6 prefix for internal use

IPv6 prefixes can be restricted to internal Google Cloud use, preventing internet announcement.

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

const prefixes = new gcp.compute.PublicAdvertisedPrefix("prefixes", {
    name: "my-pap",
    description: "description",
    ipCidrRange: "2001:db8::/32",
    pdpScope: "REGIONAL",
    ipv6AccessType: "INTERNAL",
});
import pulumi
import pulumi_gcp as gcp

prefixes = gcp.compute.PublicAdvertisedPrefix("prefixes",
    name="my-pap",
    description="description",
    ip_cidr_range="2001:db8::/32",
    pdp_scope="REGIONAL",
    ipv6_access_type="INTERNAL")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewPublicAdvertisedPrefix(ctx, "prefixes", &compute.PublicAdvertisedPrefixArgs{
			Name:           pulumi.String("my-pap"),
			Description:    pulumi.String("description"),
			IpCidrRange:    pulumi.String("2001:db8::/32"),
			PdpScope:       pulumi.String("REGIONAL"),
			Ipv6AccessType: pulumi.String("INTERNAL"),
		})
		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 prefixes = new Gcp.Compute.PublicAdvertisedPrefix("prefixes", new()
    {
        Name = "my-pap",
        Description = "description",
        IpCidrRange = "2001:db8::/32",
        PdpScope = "REGIONAL",
        Ipv6AccessType = "INTERNAL",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.PublicAdvertisedPrefix;
import com.pulumi.gcp.compute.PublicAdvertisedPrefixArgs;
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 prefixes = new PublicAdvertisedPrefix("prefixes", PublicAdvertisedPrefixArgs.builder()
            .name("my-pap")
            .description("description")
            .ipCidrRange("2001:db8::/32")
            .pdpScope("REGIONAL")
            .ipv6AccessType("INTERNAL")
            .build());

    }
}
resources:
  prefixes:
    type: gcp:compute:PublicAdvertisedPrefix
    properties:
      name: my-pap
      description: description
      ipCidrRange: 2001:db8::/32
      pdpScope: REGIONAL
      ipv6AccessType: INTERNAL

The ipv6AccessType property controls visibility. INTERNAL prevents the prefix from being announced to the internet, keeping it private within Google Cloud. All child delegated prefixes inherit this access type. IPv6 prefixes don’t require dnsVerificationIp.

Beyond these examples

These snippets focus on specific prefix-level features: IPv4 and IPv6 prefix advertisement, regional vs global delegation scoping, and internal vs external access control. They’re intentionally minimal rather than complete BYOIP implementations.

The examples assume you have pre-existing infrastructure such as owned IP address ranges and DNS records for IPv4 verification. They focus on registering the prefix rather than the full BYOIP workflow.

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

  • Public delegated prefix creation (child resources)
  • Prefix lifecycle management (activation, withdrawal)
  • Global scope provisioning (4-week timeline)
  • DNS verification completion workflow

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

Let's configure GCP Public Advertised Prefixes

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Provisioning & Timing
Why does provisioning my public advertised prefix take so long?
Provisioning time depends on pdpScope: REGIONAL scope takes a few minutes, while GLOBAL scope takes approximately 4 weeks.
What's the difference between GLOBAL and REGIONAL scope?
REGIONAL scope provisions in minutes and limits child public delegated prefixes to a single region. GLOBAL scope takes ~4 weeks to provision but allows global reach for child prefixes.
Immutability & Updates
What properties can I change after creating a public advertised prefix?
None. All properties (ipCidrRange, ipv6AccessType, name, project, description, dnsVerificationIp, pdpScope) are immutable. Changes require replacing the resource.
Can I change the IP range or scope after creation?
No. Both ipCidrRange and pdpScope are immutable and cannot be modified after creation.
IPv4 vs IPv6 Configuration
What's the difference between configuring IPv4 and IPv6 prefixes?
IPv4 prefixes require dnsVerificationIp (an IPv4 address) for reverse DNS verification. IPv6 prefixes require ipv6AccessType instead and use IPv6 CIDR format (e.g., 2001:db8::/32).
How does DNS verification work for public advertised prefixes?
For IPv4 prefixes, specify dnsVerificationIp (an IPv4 address). The output-only sharedSecret field contains the shared secret needed for reverse DNS verification.
Access Control & Visibility
What's the difference between EXTERNAL and INTERNAL access types?
EXTERNAL (default) announces the prefix to the internet, making it publicly routable. INTERNAL keeps the prefix private within Google Cloud. All child public delegated prefixes inherit the same access type.
What are the naming requirements for public advertised prefixes?
Names must be 1-63 characters, start with a lowercase letter, contain only lowercase letters, digits, and dashes, and cannot end with a dash (regex: [a-z][-a-z0-9]*[a-z0-9]?).

Using a different cloud?

Explore networking guides for other cloud providers: