The gcp:vertex/aiIndexEndpoint:AiIndexEndpoint resource, part of the Pulumi GCP provider, defines a Vertex AI index endpoint that serves as the deployment target for vector similarity search indexes. This guide focuses on three connectivity capabilities: public internet access, VPC network peering, and Private Service Connect configuration.
Index endpoints can operate in three mutually exclusive modes: public internet access, VPC peering (requires VPC network and Service Networking setup), or Private Service Connect (requires project allowlists). The examples are intentionally small. Combine them with your own index deployments and access policies.
Expose an endpoint through a public domain
Some deployments need index endpoints accessible from the internet without complex networking setup.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const indexEndpoint = new gcp.vertex.AiIndexEndpoint("index_endpoint", {
displayName: "sample-endpoint",
description: "A sample vertex endpoint with an public endpoint",
region: "us-central1",
labels: {
"label-one": "value-one",
},
publicEndpointEnabled: true,
});
import pulumi
import pulumi_gcp as gcp
index_endpoint = gcp.vertex.AiIndexEndpoint("index_endpoint",
display_name="sample-endpoint",
description="A sample vertex endpoint with an public endpoint",
region="us-central1",
labels={
"label-one": "value-one",
},
public_endpoint_enabled=True)
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/vertex"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := vertex.NewAiIndexEndpoint(ctx, "index_endpoint", &vertex.AiIndexEndpointArgs{
DisplayName: pulumi.String("sample-endpoint"),
Description: pulumi.String("A sample vertex endpoint with an public endpoint"),
Region: pulumi.String("us-central1"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
PublicEndpointEnabled: 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 indexEndpoint = new Gcp.Vertex.AiIndexEndpoint("index_endpoint", new()
{
DisplayName = "sample-endpoint",
Description = "A sample vertex endpoint with an public endpoint",
Region = "us-central1",
Labels =
{
{ "label-one", "value-one" },
},
PublicEndpointEnabled = true,
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.vertex.AiIndexEndpoint;
import com.pulumi.gcp.vertex.AiIndexEndpointArgs;
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 indexEndpoint = new AiIndexEndpoint("indexEndpoint", AiIndexEndpointArgs.builder()
.displayName("sample-endpoint")
.description("A sample vertex endpoint with an public endpoint")
.region("us-central1")
.labels(Map.of("label-one", "value-one"))
.publicEndpointEnabled(true)
.build());
}
}
resources:
indexEndpoint:
type: gcp:vertex:AiIndexEndpoint
name: index_endpoint
properties:
displayName: sample-endpoint
description: A sample vertex endpoint with an public endpoint
region: us-central1
labels:
label-one: value-one
publicEndpointEnabled: true
When publicEndpointEnabled is true, Vertex AI provisions a public domain name (available in the publicEndpointDomainName output property) that clients can use to query deployed indexes. This mode requires no VPC configuration but exposes the endpoint to the internet.
Peer an endpoint with a VPC network
Most production deployments connect index endpoints to a VPC network to enable private access from compute resources.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const vertexNetwork = new gcp.compute.Network("vertex_network", {name: "network-name"});
const vertexRange = new gcp.compute.GlobalAddress("vertex_range", {
name: "address-name",
purpose: "VPC_PEERING",
addressType: "INTERNAL",
prefixLength: 24,
network: vertexNetwork.id,
});
const vertexVpcConnection = new gcp.servicenetworking.Connection("vertex_vpc_connection", {
network: vertexNetwork.id,
service: "servicenetworking.googleapis.com",
reservedPeeringRanges: [vertexRange.name],
});
const project = gcp.organizations.getProject({});
const indexEndpoint = new gcp.vertex.AiIndexEndpoint("index_endpoint", {
displayName: "sample-endpoint",
description: "A sample vertex endpoint",
region: "us-central1",
labels: {
"label-one": "value-one",
},
network: pulumi.all([project, vertexNetwork.name]).apply(([project, name]) => `projects/${project.number}/global/networks/${name}`),
}, {
dependsOn: [vertexVpcConnection],
});
import pulumi
import pulumi_gcp as gcp
vertex_network = gcp.compute.Network("vertex_network", name="network-name")
vertex_range = gcp.compute.GlobalAddress("vertex_range",
name="address-name",
purpose="VPC_PEERING",
address_type="INTERNAL",
prefix_length=24,
network=vertex_network.id)
vertex_vpc_connection = gcp.servicenetworking.Connection("vertex_vpc_connection",
network=vertex_network.id,
service="servicenetworking.googleapis.com",
reserved_peering_ranges=[vertex_range.name])
project = gcp.organizations.get_project()
index_endpoint = gcp.vertex.AiIndexEndpoint("index_endpoint",
display_name="sample-endpoint",
description="A sample vertex endpoint",
region="us-central1",
labels={
"label-one": "value-one",
},
network=vertex_network.name.apply(lambda name: f"projects/{project.number}/global/networks/{name}"),
opts = pulumi.ResourceOptions(depends_on=[vertex_vpc_connection]))
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/servicenetworking"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/vertex"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
vertexNetwork, err := compute.NewNetwork(ctx, "vertex_network", &compute.NetworkArgs{
Name: pulumi.String("network-name"),
})
if err != nil {
return err
}
vertexRange, err := compute.NewGlobalAddress(ctx, "vertex_range", &compute.GlobalAddressArgs{
Name: pulumi.String("address-name"),
Purpose: pulumi.String("VPC_PEERING"),
AddressType: pulumi.String("INTERNAL"),
PrefixLength: pulumi.Int(24),
Network: vertexNetwork.ID(),
})
if err != nil {
return err
}
vertexVpcConnection, err := servicenetworking.NewConnection(ctx, "vertex_vpc_connection", &servicenetworking.ConnectionArgs{
Network: vertexNetwork.ID(),
Service: pulumi.String("servicenetworking.googleapis.com"),
ReservedPeeringRanges: pulumi.StringArray{
vertexRange.Name,
},
})
if err != nil {
return err
}
project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
if err != nil {
return err
}
_, err = vertex.NewAiIndexEndpoint(ctx, "index_endpoint", &vertex.AiIndexEndpointArgs{
DisplayName: pulumi.String("sample-endpoint"),
Description: pulumi.String("A sample vertex endpoint"),
Region: pulumi.String("us-central1"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
Network: vertexNetwork.Name.ApplyT(func(name string) (string, error) {
return fmt.Sprintf("projects/%v/global/networks/%v", project.Number, name), nil
}).(pulumi.StringOutput),
}, pulumi.DependsOn([]pulumi.Resource{
vertexVpcConnection,
}))
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 vertexNetwork = new Gcp.Compute.Network("vertex_network", new()
{
Name = "network-name",
});
var vertexRange = new Gcp.Compute.GlobalAddress("vertex_range", new()
{
Name = "address-name",
Purpose = "VPC_PEERING",
AddressType = "INTERNAL",
PrefixLength = 24,
Network = vertexNetwork.Id,
});
var vertexVpcConnection = new Gcp.ServiceNetworking.Connection("vertex_vpc_connection", new()
{
Network = vertexNetwork.Id,
Service = "servicenetworking.googleapis.com",
ReservedPeeringRanges = new[]
{
vertexRange.Name,
},
});
var project = Gcp.Organizations.GetProject.Invoke();
var indexEndpoint = new Gcp.Vertex.AiIndexEndpoint("index_endpoint", new()
{
DisplayName = "sample-endpoint",
Description = "A sample vertex endpoint",
Region = "us-central1",
Labels =
{
{ "label-one", "value-one" },
},
Network = Output.Tuple(project, vertexNetwork.Name).Apply(values =>
{
var project = values.Item1;
var name = values.Item2;
return $"projects/{project.Apply(getProjectResult => getProjectResult.Number)}/global/networks/{name}";
}),
}, new CustomResourceOptions
{
DependsOn =
{
vertexVpcConnection,
},
});
});
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.GlobalAddress;
import com.pulumi.gcp.compute.GlobalAddressArgs;
import com.pulumi.gcp.servicenetworking.Connection;
import com.pulumi.gcp.servicenetworking.ConnectionArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.vertex.AiIndexEndpoint;
import com.pulumi.gcp.vertex.AiIndexEndpointArgs;
import com.pulumi.resources.CustomResourceOptions;
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 vertexNetwork = new Network("vertexNetwork", NetworkArgs.builder()
.name("network-name")
.build());
var vertexRange = new GlobalAddress("vertexRange", GlobalAddressArgs.builder()
.name("address-name")
.purpose("VPC_PEERING")
.addressType("INTERNAL")
.prefixLength(24)
.network(vertexNetwork.id())
.build());
var vertexVpcConnection = new Connection("vertexVpcConnection", ConnectionArgs.builder()
.network(vertexNetwork.id())
.service("servicenetworking.googleapis.com")
.reservedPeeringRanges(vertexRange.name())
.build());
final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
.build());
var indexEndpoint = new AiIndexEndpoint("indexEndpoint", AiIndexEndpointArgs.builder()
.displayName("sample-endpoint")
.description("A sample vertex endpoint")
.region("us-central1")
.labels(Map.of("label-one", "value-one"))
.network(vertexNetwork.name().applyValue(_name -> String.format("projects/%s/global/networks/%s", project.number(),_name)))
.build(), CustomResourceOptions.builder()
.dependsOn(vertexVpcConnection)
.build());
}
}
resources:
indexEndpoint:
type: gcp:vertex:AiIndexEndpoint
name: index_endpoint
properties:
displayName: sample-endpoint
description: A sample vertex endpoint
region: us-central1
labels:
label-one: value-one
network: projects/${project.number}/global/networks/${vertexNetwork.name}
options:
dependsOn:
- ${vertexVpcConnection}
vertexVpcConnection:
type: gcp:servicenetworking:Connection
name: vertex_vpc_connection
properties:
network: ${vertexNetwork.id}
service: servicenetworking.googleapis.com
reservedPeeringRanges:
- ${vertexRange.name}
vertexRange:
type: gcp:compute:GlobalAddress
name: vertex_range
properties:
name: address-name
purpose: VPC_PEERING
addressType: INTERNAL
prefixLength: 24
network: ${vertexNetwork.id}
vertexNetwork:
type: gcp:compute:Network
name: vertex_network
properties:
name: network-name
variables:
project:
fn::invoke:
function: gcp:organizations:getProject
arguments: {}
The network property specifies the VPC to peer with, using the format projects/{project_number}/global/networks/{network_name}. Before creating the endpoint, you must configure VPC peering through the Service Networking API: reserve an IP range with compute.GlobalAddress (purpose set to VPC_PEERING) and establish the connection with servicenetworking.Connection. The dependsOn ensures peering completes before endpoint creation.
Configure Private Service Connect access
Private Service Connect provides an alternative to VPC peering with more granular project-level access control.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const project = gcp.organizations.getProject({});
const indexEndpoint = new gcp.vertex.AiIndexEndpoint("index_endpoint", {
displayName: "sample-endpoint",
description: "A sample vertex endpoint",
region: "us-central1",
labels: {
"label-one": "value-one",
},
privateServiceConnectConfig: {
enablePrivateServiceConnect: true,
projectAllowlists: [project.then(project => project.name)],
},
});
import pulumi
import pulumi_gcp as gcp
project = gcp.organizations.get_project()
index_endpoint = gcp.vertex.AiIndexEndpoint("index_endpoint",
display_name="sample-endpoint",
description="A sample vertex endpoint",
region="us-central1",
labels={
"label-one": "value-one",
},
private_service_connect_config={
"enable_private_service_connect": True,
"project_allowlists": [project.name],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/vertex"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
if err != nil {
return err
}
_, err = vertex.NewAiIndexEndpoint(ctx, "index_endpoint", &vertex.AiIndexEndpointArgs{
DisplayName: pulumi.String("sample-endpoint"),
Description: pulumi.String("A sample vertex endpoint"),
Region: pulumi.String("us-central1"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
PrivateServiceConnectConfig: &vertex.AiIndexEndpointPrivateServiceConnectConfigArgs{
EnablePrivateServiceConnect: pulumi.Bool(true),
ProjectAllowlists: pulumi.StringArray{
pulumi.String(project.Name),
},
},
})
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 project = Gcp.Organizations.GetProject.Invoke();
var indexEndpoint = new Gcp.Vertex.AiIndexEndpoint("index_endpoint", new()
{
DisplayName = "sample-endpoint",
Description = "A sample vertex endpoint",
Region = "us-central1",
Labels =
{
{ "label-one", "value-one" },
},
PrivateServiceConnectConfig = new Gcp.Vertex.Inputs.AiIndexEndpointPrivateServiceConnectConfigArgs
{
EnablePrivateServiceConnect = true,
ProjectAllowlists = new[]
{
project.Apply(getProjectResult => getProjectResult.Name),
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.vertex.AiIndexEndpoint;
import com.pulumi.gcp.vertex.AiIndexEndpointArgs;
import com.pulumi.gcp.vertex.inputs.AiIndexEndpointPrivateServiceConnectConfigArgs;
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) {
final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
.build());
var indexEndpoint = new AiIndexEndpoint("indexEndpoint", AiIndexEndpointArgs.builder()
.displayName("sample-endpoint")
.description("A sample vertex endpoint")
.region("us-central1")
.labels(Map.of("label-one", "value-one"))
.privateServiceConnectConfig(AiIndexEndpointPrivateServiceConnectConfigArgs.builder()
.enablePrivateServiceConnect(true)
.projectAllowlists(project.name())
.build())
.build());
}
}
resources:
indexEndpoint:
type: gcp:vertex:AiIndexEndpoint
name: index_endpoint
properties:
displayName: sample-endpoint
description: A sample vertex endpoint
region: us-central1
labels:
label-one: value-one
privateServiceConnectConfig:
enablePrivateServiceConnect: true
projectAllowlists:
- ${project.name}
variables:
project:
fn::invoke:
function: gcp:organizations:getProject
arguments: {}
The privateServiceConnectConfig block enables Private Service Connect and defines which projects can access the endpoint through projectAllowlists. This mode is mutually exclusive with the network property; you configure either VPC peering or Private Service Connect, not both.
Beyond these examples
These snippets focus on specific endpoint connectivity features: public internet access, VPC network peering, and Private Service Connect configuration. They’re intentionally minimal rather than full vector search deployments.
The examples may reference pre-existing infrastructure such as VPC networks and IP address ranges for VPC peering, and Service Networking API enablement. They focus on endpoint connectivity rather than index deployment or query operations.
To keep things focused, common endpoint patterns are omitted, including:
- Customer-managed encryption keys (encryptionSpec)
- Index deployment to endpoints
- Endpoint monitoring and observability
- Multi-region endpoint configuration
These omissions are intentional: the goal is to illustrate how each connectivity mode is wired, not provide drop-in vector search modules. See the Vertex AI Index Endpoint resource reference for all available configuration options.
Let's deploy GCP Vertex AI Index Endpoints
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Connectivity & Networking
You have three connectivity options:
- VPC peering - Use
networkproperty to peer with a VPC - Private Service Connect - Use
privateServiceConnectConfigfor PSC - Public endpoint - Set
publicEndpointEnabled: truefor internet access
network and privateServiceConnectConfig are mutually exclusive. Choose one connectivity method.network property requires project NUMBER, not project ID, in format projects/{number}/global/networks/{name}. (2) Private services access must already be configured via servicenetworking.Connection before creating the endpoint.servicenetworking.Connection must complete before creating the index endpoint to ensure private services access is properly configured for the network.Configuration & Immutability
network, privateServiceConnectConfig, project, encryptionSpec, publicEndpointEnabled, and region.labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels output to see all labels present on the resource, including those set by other clients.displayName can be up to 128 characters long and support any UTF-8 characters.Setup & Configuration
encryptionSpec property with your encryption key. This secures the index endpoint and all its sub-resources. Note that encryptionSpec is immutable.publicEndpointEnabled is true, the publicEndpointDomainName output field will be populated with the domain name for accessing the endpoint.Using a different cloud?
Explore analytics guides for other cloud providers: