Configure GCP Public Advertised Prefixes

The gcp:compute/publicAdvertisedPrefix:PublicAdvertisedPrefix resource, part of the Pulumi GCP provider, registers IP address blocks (IPv4 or IPv6) that you own for use in Google Cloud through BYOIP (bring your own IP). This guide focuses on three capabilities: IPv4 prefix registration with DNS verification, regional vs global scope control, and IPv6 prefix configuration for internal use.

Public advertised prefixes require IP blocks you already own and DNS infrastructure for verification (IPv4 only). The examples are intentionally small. Combine them with your own IP allocations and child public delegated prefixes.

Organizations bringing their own IP addresses to Google Cloud start by declaring ownership of an IPv4 CIDR block.

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 property specifies the address block you own. The dnsVerificationIp property sets an IPv4 address within that range for reverse DNS verification, proving you control the prefix. Google Cloud uses this verification to confirm ownership before allowing the prefix to be used.

Control prefix scope with regional delegation

Public delegated prefixes can be scoped globally or regionally, affecting provisioning time and where child prefixes can be used.

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 will be scoped. Setting it to REGIONAL provisions the prefix in minutes and restricts child prefixes to a single region. GLOBAL scope takes approximately four weeks to provision but allows child prefixes to be used anywhere.

Configure IPv6 prefixes for internal use

IPv6 prefixes can be configured for internal-only use within Google Cloud rather than being announced to the public internet.

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 internet announcement. Setting it to INTERNAL keeps the prefix private within Google Cloud; all child public delegated prefixes inherit this access type. EXTERNAL (the default) announces the prefix to the internet. IPv6 prefixes don’t require dnsVerificationIp since verification works differently for IPv6.

Beyond these examples

These snippets focus on specific prefix-level features: IPv4 and IPv6 prefix registration, DNS verification for reverse lookups, and scope control. They’re intentionally minimal rather than complete BYOIP implementations.

The examples assume pre-existing infrastructure such as IP address blocks owned by the organization and DNS infrastructure for verification. They focus on registering the prefix rather than provisioning the surrounding network infrastructure.

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

  • Child public delegated prefix creation
  • Integration with VPC networks and subnets
  • Prefix announcement and BGP configuration
  • Access control and IAM permissions

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 & Scope
How long does it take to provision a public advertised prefix?
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 regional use. GLOBAL scope takes ~4 weeks to provision but allows global child prefixes.
Immutability & Updates
Can I change my prefix configuration after creation?
No, most properties are immutable including ipCidrRange, ipv6AccessType, name, pdpScope, description, and dnsVerificationIp. Changes require replacing the resource.
What naming requirements must I follow?
The name must be 1-63 characters, start with a lowercase letter, contain only lowercase letters, digits, and dashes, and cannot end with a dash.
IPv6 Configuration
What's the difference between EXTERNAL and INTERNAL IPv6 access types?
EXTERNAL (default) announces the prefix to the internet, while INTERNAL keeps it private within Google Cloud. All child public delegated prefixes inherit the same access type.
Do I need to specify dnsVerificationIp for IPv6 prefixes?
The IPv6 example omits dnsVerificationIp, suggesting it may be optional for IPv6 prefixes (required for IPv4).

Using a different cloud?

Explore networking guides for other cloud providers: