The gcp:vertex/aiEndpoint:AiEndpoint resource, part of the Pulumi GCP provider, defines a Vertex AI endpoint that serves deployed ML models and handles prediction requests. This guide focuses on three capabilities: VPC peering for private connectivity, Private Service Connect for isolated access, and dedicated endpoints for performance isolation.
Endpoints reference VPC networks, KMS keys, and BigQuery datasets that must exist separately. Models are deployed to endpoints after creation using separate API calls. The examples are intentionally small. Combine them with your own model deployment and traffic management configuration.
Peer endpoint to VPC for private model access
ML deployments that need to access private resources or restrict network exposure often peer Vertex AI endpoints to a VPC network with private service access configured.
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 bqDataset = new gcp.bigquery.Dataset("bq_dataset", {
datasetId: "some_dataset",
friendlyName: "logging dataset",
description: "This is a dataset that requests are logged to",
location: "US",
deleteContentsOnDestroy: true,
});
const project = gcp.organizations.getProject({});
const endpoint = new gcp.vertex.AiEndpoint("endpoint", {
name: "endpoint-name",
displayName: "sample-endpoint",
description: "A sample vertex endpoint",
location: "us-central1",
region: "us-central1",
labels: {
"label-one": "value-one",
},
network: pulumi.all([project, vertexNetwork.name]).apply(([project, name]) => `projects/${project.number}/global/networks/${name}`),
encryptionSpec: {
kmsKeyName: "kms-name",
},
predictRequestResponseLoggingConfig: {
bigqueryDestination: {
outputUri: pulumi.all([project, bqDataset.datasetId]).apply(([project, datasetId]) => `bq://${project.projectId}.${datasetId}.request_response_logging`),
},
enabled: true,
samplingRate: 0.1,
},
trafficSplit: JSON.stringify({
"12345": 100,
}),
}, {
dependsOn: [vertexVpcConnection],
});
const cryptoKey = new gcp.kms.CryptoKeyIAMMember("crypto_key", {
cryptoKeyId: "kms-name",
role: "roles/cloudkms.cryptoKeyEncrypterDecrypter",
member: project.then(project => `serviceAccount:service-${project.number}@gcp-sa-aiplatform.iam.gserviceaccount.com`),
});
import pulumi
import json
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])
bq_dataset = gcp.bigquery.Dataset("bq_dataset",
dataset_id="some_dataset",
friendly_name="logging dataset",
description="This is a dataset that requests are logged to",
location="US",
delete_contents_on_destroy=True)
project = gcp.organizations.get_project()
endpoint = gcp.vertex.AiEndpoint("endpoint",
name="endpoint-name",
display_name="sample-endpoint",
description="A sample vertex endpoint",
location="us-central1",
region="us-central1",
labels={
"label-one": "value-one",
},
network=vertex_network.name.apply(lambda name: f"projects/{project.number}/global/networks/{name}"),
encryption_spec={
"kms_key_name": "kms-name",
},
predict_request_response_logging_config={
"bigquery_destination": {
"output_uri": bq_dataset.dataset_id.apply(lambda dataset_id: f"bq://{project.project_id}.{dataset_id}.request_response_logging"),
},
"enabled": True,
"sampling_rate": 0.1,
},
traffic_split=json.dumps({
"12345": 100,
}),
opts = pulumi.ResourceOptions(depends_on=[vertex_vpc_connection]))
crypto_key = gcp.kms.CryptoKeyIAMMember("crypto_key",
crypto_key_id="kms-name",
role="roles/cloudkms.cryptoKeyEncrypterDecrypter",
member=f"serviceAccount:service-{project.number}@gcp-sa-aiplatform.iam.gserviceaccount.com")
package main
import (
"encoding/json"
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/bigquery"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/kms"
"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
}
bqDataset, err := bigquery.NewDataset(ctx, "bq_dataset", &bigquery.DatasetArgs{
DatasetId: pulumi.String("some_dataset"),
FriendlyName: pulumi.String("logging dataset"),
Description: pulumi.String("This is a dataset that requests are logged to"),
Location: pulumi.String("US"),
DeleteContentsOnDestroy: pulumi.Bool(true),
})
if err != nil {
return err
}
project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
if err != nil {
return err
}
tmpJSON0, err := json.Marshal(map[string]interface{}{
"12345": 100,
})
if err != nil {
return err
}
json0 := string(tmpJSON0)
_, err = vertex.NewAiEndpoint(ctx, "endpoint", &vertex.AiEndpointArgs{
Name: pulumi.String("endpoint-name"),
DisplayName: pulumi.String("sample-endpoint"),
Description: pulumi.String("A sample vertex endpoint"),
Location: pulumi.String("us-central1"),
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),
EncryptionSpec: &vertex.AiEndpointEncryptionSpecArgs{
KmsKeyName: pulumi.String("kms-name"),
},
PredictRequestResponseLoggingConfig: &vertex.AiEndpointPredictRequestResponseLoggingConfigArgs{
BigqueryDestination: &vertex.AiEndpointPredictRequestResponseLoggingConfigBigqueryDestinationArgs{
OutputUri: bqDataset.DatasetId.ApplyT(func(datasetId string) (string, error) {
return fmt.Sprintf("bq://%v.%v.request_response_logging", project.ProjectId, datasetId), nil
}).(pulumi.StringOutput),
},
Enabled: pulumi.Bool(true),
SamplingRate: pulumi.Float64(0.1),
},
TrafficSplit: pulumi.String(json0),
}, pulumi.DependsOn([]pulumi.Resource{
vertexVpcConnection,
}))
if err != nil {
return err
}
_, err = kms.NewCryptoKeyIAMMember(ctx, "crypto_key", &kms.CryptoKeyIAMMemberArgs{
CryptoKeyId: pulumi.String("kms-name"),
Role: pulumi.String("roles/cloudkms.cryptoKeyEncrypterDecrypter"),
Member: pulumi.Sprintf("serviceAccount:service-%v@gcp-sa-aiplatform.iam.gserviceaccount.com", project.Number),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
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 bqDataset = new Gcp.BigQuery.Dataset("bq_dataset", new()
{
DatasetId = "some_dataset",
FriendlyName = "logging dataset",
Description = "This is a dataset that requests are logged to",
Location = "US",
DeleteContentsOnDestroy = true,
});
var project = Gcp.Organizations.GetProject.Invoke();
var endpoint = new Gcp.Vertex.AiEndpoint("endpoint", new()
{
Name = "endpoint-name",
DisplayName = "sample-endpoint",
Description = "A sample vertex endpoint",
Location = "us-central1",
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}";
}),
EncryptionSpec = new Gcp.Vertex.Inputs.AiEndpointEncryptionSpecArgs
{
KmsKeyName = "kms-name",
},
PredictRequestResponseLoggingConfig = new Gcp.Vertex.Inputs.AiEndpointPredictRequestResponseLoggingConfigArgs
{
BigqueryDestination = new Gcp.Vertex.Inputs.AiEndpointPredictRequestResponseLoggingConfigBigqueryDestinationArgs
{
OutputUri = Output.Tuple(project, bqDataset.DatasetId).Apply(values =>
{
var project = values.Item1;
var datasetId = values.Item2;
return $"bq://{project.Apply(getProjectResult => getProjectResult.ProjectId)}.{datasetId}.request_response_logging";
}),
},
Enabled = true,
SamplingRate = 0.1,
},
TrafficSplit = JsonSerializer.Serialize(new Dictionary<string, object?>
{
["12345"] = 100,
}),
}, new CustomResourceOptions
{
DependsOn =
{
vertexVpcConnection,
},
});
var cryptoKey = new Gcp.Kms.CryptoKeyIAMMember("crypto_key", new()
{
CryptoKeyId = "kms-name",
Role = "roles/cloudkms.cryptoKeyEncrypterDecrypter",
Member = $"serviceAccount:service-{project.Apply(getProjectResult => getProjectResult.Number)}@gcp-sa-aiplatform.iam.gserviceaccount.com",
});
});
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.bigquery.Dataset;
import com.pulumi.gcp.bigquery.DatasetArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.vertex.AiEndpoint;
import com.pulumi.gcp.vertex.AiEndpointArgs;
import com.pulumi.gcp.vertex.inputs.AiEndpointEncryptionSpecArgs;
import com.pulumi.gcp.vertex.inputs.AiEndpointPredictRequestResponseLoggingConfigArgs;
import com.pulumi.gcp.vertex.inputs.AiEndpointPredictRequestResponseLoggingConfigBigqueryDestinationArgs;
import com.pulumi.gcp.kms.CryptoKeyIAMMember;
import com.pulumi.gcp.kms.CryptoKeyIAMMemberArgs;
import static com.pulumi.codegen.internal.Serialization.*;
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());
var bqDataset = new Dataset("bqDataset", DatasetArgs.builder()
.datasetId("some_dataset")
.friendlyName("logging dataset")
.description("This is a dataset that requests are logged to")
.location("US")
.deleteContentsOnDestroy(true)
.build());
final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
.build());
var endpoint = new AiEndpoint("endpoint", AiEndpointArgs.builder()
.name("endpoint-name")
.displayName("sample-endpoint")
.description("A sample vertex endpoint")
.location("us-central1")
.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)))
.encryptionSpec(AiEndpointEncryptionSpecArgs.builder()
.kmsKeyName("kms-name")
.build())
.predictRequestResponseLoggingConfig(AiEndpointPredictRequestResponseLoggingConfigArgs.builder()
.bigqueryDestination(AiEndpointPredictRequestResponseLoggingConfigBigqueryDestinationArgs.builder()
.outputUri(bqDataset.datasetId().applyValue(_datasetId -> String.format("bq://%s.%s.request_response_logging", project.projectId(),_datasetId)))
.build())
.enabled(true)
.samplingRate(0.1)
.build())
.trafficSplit(serializeJson(
jsonObject(
jsonProperty("12345", 100)
)))
.build(), CustomResourceOptions.builder()
.dependsOn(vertexVpcConnection)
.build());
var cryptoKey = new CryptoKeyIAMMember("cryptoKey", CryptoKeyIAMMemberArgs.builder()
.cryptoKeyId("kms-name")
.role("roles/cloudkms.cryptoKeyEncrypterDecrypter")
.member(String.format("serviceAccount:service-%s@gcp-sa-aiplatform.iam.gserviceaccount.com", project.number()))
.build());
}
}
resources:
endpoint:
type: gcp:vertex:AiEndpoint
properties:
name: endpoint-name
displayName: sample-endpoint
description: A sample vertex endpoint
location: us-central1
region: us-central1
labels:
label-one: value-one
network: projects/${project.number}/global/networks/${vertexNetwork.name}
encryptionSpec:
kmsKeyName: kms-name
predictRequestResponseLoggingConfig:
bigqueryDestination:
outputUri: bq://${project.projectId}.${bqDataset.datasetId}.request_response_logging
enabled: true
samplingRate: 0.1
trafficSplit:
fn::toJSON:
'12345': 100
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
cryptoKey:
type: gcp:kms:CryptoKeyIAMMember
name: crypto_key
properties:
cryptoKeyId: kms-name
role: roles/cloudkms.cryptoKeyEncrypterDecrypter
member: serviceAccount:service-${project.number}@gcp-sa-aiplatform.iam.gserviceaccount.com
bqDataset:
type: gcp:bigquery:Dataset
name: bq_dataset
properties:
datasetId: some_dataset
friendlyName: logging dataset
description: This is a dataset that requests are logged to
location: US
deleteContentsOnDestroy: true
variables:
project:
fn::invoke:
function: gcp:organizations:getProject
arguments: {}
The endpoint connects to your VPC through the network property, which requires VPC peering already configured via servicenetworking.Connection. The predictRequestResponseLoggingConfig sends prediction data to BigQuery for analysis, with samplingRate controlling what percentage of requests are logged. The encryptionSpec secures the endpoint and its data with a customer-managed KMS key. The trafficSplit property maps deployed model IDs to traffic percentages; here “12345” receives 100% of traffic.
Enable Private Service Connect for isolated access
Teams that need stronger network isolation can use Private Service Connect to expose endpoints through dedicated connections without VPC peering.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.Network("default", {name: "psc-network-_7495"});
const project = gcp.organizations.getProject({});
const endpoint = new gcp.vertex.AiEndpoint("endpoint", {
name: "endpoint-name_21912",
displayName: "sample-endpoint",
description: "A sample vertex endpoint",
location: "us-central1",
region: "us-central1",
labels: {
"label-one": "value-one",
},
privateServiceConnectConfig: {
enablePrivateServiceConnect: true,
projectAllowlists: [project.then(project => project.projectId)],
pscAutomationConfigs: [{
projectId: project.then(project => project.projectId),
network: _default.id,
}],
},
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.Network("default", name="psc-network-_7495")
project = gcp.organizations.get_project()
endpoint = gcp.vertex.AiEndpoint("endpoint",
name="endpoint-name_21912",
display_name="sample-endpoint",
description="A sample vertex endpoint",
location="us-central1",
region="us-central1",
labels={
"label-one": "value-one",
},
private_service_connect_config={
"enable_private_service_connect": True,
"project_allowlists": [project.project_id],
"psc_automation_configs": [{
"project_id": project.project_id,
"network": default.id,
}],
})
package main
import (
"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/vertex"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := compute.NewNetwork(ctx, "default", &compute.NetworkArgs{
Name: pulumi.String("psc-network-_7495"),
})
if err != nil {
return err
}
project, err := organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
if err != nil {
return err
}
_, err = vertex.NewAiEndpoint(ctx, "endpoint", &vertex.AiEndpointArgs{
Name: pulumi.String("endpoint-name_21912"),
DisplayName: pulumi.String("sample-endpoint"),
Description: pulumi.String("A sample vertex endpoint"),
Location: pulumi.String("us-central1"),
Region: pulumi.String("us-central1"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
PrivateServiceConnectConfig: &vertex.AiEndpointPrivateServiceConnectConfigArgs{
EnablePrivateServiceConnect: pulumi.Bool(true),
ProjectAllowlists: pulumi.StringArray{
pulumi.String(project.ProjectId),
},
PscAutomationConfigs: vertex.AiEndpointPrivateServiceConnectConfigPscAutomationConfigArray{
&vertex.AiEndpointPrivateServiceConnectConfigPscAutomationConfigArgs{
ProjectId: pulumi.String(project.ProjectId),
Network: _default.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 @default = new Gcp.Compute.Network("default", new()
{
Name = "psc-network-_7495",
});
var project = Gcp.Organizations.GetProject.Invoke();
var endpoint = new Gcp.Vertex.AiEndpoint("endpoint", new()
{
Name = "endpoint-name_21912",
DisplayName = "sample-endpoint",
Description = "A sample vertex endpoint",
Location = "us-central1",
Region = "us-central1",
Labels =
{
{ "label-one", "value-one" },
},
PrivateServiceConnectConfig = new Gcp.Vertex.Inputs.AiEndpointPrivateServiceConnectConfigArgs
{
EnablePrivateServiceConnect = true,
ProjectAllowlists = new[]
{
project.Apply(getProjectResult => getProjectResult.ProjectId),
},
PscAutomationConfigs = new[]
{
new Gcp.Vertex.Inputs.AiEndpointPrivateServiceConnectConfigPscAutomationConfigArgs
{
ProjectId = project.Apply(getProjectResult => getProjectResult.ProjectId),
Network = @default.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.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
import com.pulumi.gcp.vertex.AiEndpoint;
import com.pulumi.gcp.vertex.AiEndpointArgs;
import com.pulumi.gcp.vertex.inputs.AiEndpointPrivateServiceConnectConfigArgs;
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 default_ = new Network("default", NetworkArgs.builder()
.name("psc-network-_7495")
.build());
final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
.build());
var endpoint = new AiEndpoint("endpoint", AiEndpointArgs.builder()
.name("endpoint-name_21912")
.displayName("sample-endpoint")
.description("A sample vertex endpoint")
.location("us-central1")
.region("us-central1")
.labels(Map.of("label-one", "value-one"))
.privateServiceConnectConfig(AiEndpointPrivateServiceConnectConfigArgs.builder()
.enablePrivateServiceConnect(true)
.projectAllowlists(project.projectId())
.pscAutomationConfigs(AiEndpointPrivateServiceConnectConfigPscAutomationConfigArgs.builder()
.projectId(project.projectId())
.network(default_.id())
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:compute:Network
properties:
name: psc-network-_7495
endpoint:
type: gcp:vertex:AiEndpoint
properties:
name: endpoint-name_21912
displayName: sample-endpoint
description: A sample vertex endpoint
location: us-central1
region: us-central1
labels:
label-one: value-one
privateServiceConnectConfig:
enablePrivateServiceConnect: true
projectAllowlists:
- ${project.projectId}
pscAutomationConfigs:
- projectId: ${project.projectId}
network: ${default.id}
variables:
project:
fn::invoke:
function: gcp:organizations:getProject
arguments: {}
Private Service Connect provides an alternative to VPC peering. The privateServiceConnectConfig enables the feature and defines which projects can access the endpoint via projectAllowlists. The pscAutomationConfigs specify which networks in which projects should have automated Private Service Connect attachment points created. This approach isolates endpoint traffic without requiring VPC peering setup.
Create dedicated DNS endpoint for performance isolation
Production workloads that require predictable performance and traffic isolation can enable dedicated endpoints, which provide a separate DNS name and isolated infrastructure.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const endpoint = new gcp.vertex.AiEndpoint("endpoint", {
name: "endpoint-name_46731",
displayName: "sample-endpoint",
description: "A sample vertex endpoint",
location: "us-central1",
region: "us-central1",
labels: {
"label-one": "value-one",
},
dedicatedEndpointEnabled: true,
});
const project = gcp.organizations.getProject({});
import pulumi
import pulumi_gcp as gcp
endpoint = gcp.vertex.AiEndpoint("endpoint",
name="endpoint-name_46731",
display_name="sample-endpoint",
description="A sample vertex endpoint",
location="us-central1",
region="us-central1",
labels={
"label-one": "value-one",
},
dedicated_endpoint_enabled=True)
project = gcp.organizations.get_project()
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 {
_, err := vertex.NewAiEndpoint(ctx, "endpoint", &vertex.AiEndpointArgs{
Name: pulumi.String("endpoint-name_46731"),
DisplayName: pulumi.String("sample-endpoint"),
Description: pulumi.String("A sample vertex endpoint"),
Location: pulumi.String("us-central1"),
Region: pulumi.String("us-central1"),
Labels: pulumi.StringMap{
"label-one": pulumi.String("value-one"),
},
DedicatedEndpointEnabled: pulumi.Bool(true),
})
if err != nil {
return err
}
_, err = organizations.LookupProject(ctx, &organizations.LookupProjectArgs{}, nil)
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 endpoint = new Gcp.Vertex.AiEndpoint("endpoint", new()
{
Name = "endpoint-name_46731",
DisplayName = "sample-endpoint",
Description = "A sample vertex endpoint",
Location = "us-central1",
Region = "us-central1",
Labels =
{
{ "label-one", "value-one" },
},
DedicatedEndpointEnabled = true,
});
var project = Gcp.Organizations.GetProject.Invoke();
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.vertex.AiEndpoint;
import com.pulumi.gcp.vertex.AiEndpointArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetProjectArgs;
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 endpoint = new AiEndpoint("endpoint", AiEndpointArgs.builder()
.name("endpoint-name_46731")
.displayName("sample-endpoint")
.description("A sample vertex endpoint")
.location("us-central1")
.region("us-central1")
.labels(Map.of("label-one", "value-one"))
.dedicatedEndpointEnabled(true)
.build());
final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
.build());
}
}
resources:
endpoint:
type: gcp:vertex:AiEndpoint
properties:
name: endpoint-name_46731
displayName: sample-endpoint
description: A sample vertex endpoint
location: us-central1
region: us-central1
labels:
label-one: value-one
dedicatedEndpointEnabled: true
variables:
project:
fn::invoke:
function: gcp:organizations:getProject
arguments: {}
Setting dedicatedEndpointEnabled to true provisions dedicated infrastructure and a unique DNS name (available in the dedicatedEndpointDns output). This isolates your endpoint’s traffic from other users’ requests, providing better performance and reliability. Once enabled, you must use the dedicated DNS rather than the shared regional endpoint.
Beyond these examples
These snippets focus on specific endpoint-level features: VPC peering and Private Service Connect networking, request-response logging to BigQuery, and dedicated endpoint DNS for traffic isolation. They’re intentionally minimal rather than full ML serving deployments.
The examples may reference pre-existing infrastructure such as VPC networks with private service access configured, KMS keys for encryption, and BigQuery datasets for logging. They focus on configuring the endpoint rather than deploying models or managing predictions.
To keep things focused, common endpoint patterns are omitted, including:
- Model deployment and traffic splitting (trafficSplit property shown but not explained)
- Encryption key IAM bindings and rotation
- Monitoring job configuration (modelDeploymentMonitoringJob)
- Label management and resource tagging strategies
These omissions are intentional: the goal is to illustrate how each endpoint feature is wired, not provide drop-in ML serving modules. See the Vertex AI Endpoint resource reference for all available configuration options.
Let's deploy GCP Vertex AI Endpoints
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Networking & Connectivity
network and privateServiceConnectConfig are mutually exclusive. You must choose one connectivity method or the other.network to the full network path (format: projects/{project}/global/networks/{network}). Ensure private services access is already configured for the network, and use dependsOn to reference the VPC connection resource to avoid race conditions.privateServiceConnectConfig with enablePrivateServiceConnect: true, specify projectAllowlists for allowed projects, and configure pscAutomationConfigs with the project ID and network.dedicatedEndpointEnabled isolates your traffic through a dedicated DNS endpoint (available in dedicatedEndpointDns output) with better performance and reliability. However, you won’t be able to send requests to the shared DNS {region}-aiplatform.googleapis.com afterward.Traffic & Deployment
trafficSplit to "{}" and apply, then remove the field from your configuration. This avoids configuration drift.Configuration & Constraints
name must be numeric with no leading zeros and can be at most 10 digits.location, name, project, encryptionSpec, network, and region. Changing these requires recreating the endpoint.Security & Logging
predictRequestResponseLoggingConfig with bigqueryDestination.outputUri pointing to your BigQuery dataset, set enabled to true, and specify a samplingRate (e.g., 0.1 for 10% sampling).encryptionSpec.kmsKeyName to your KMS key name. You’ll also need to grant the Vertex AI service account the roles/cloudkms.cryptoKeyEncrypterDecrypter role on the key, as shown in the network example.Using a different cloud?
Explore analytics guides for other cloud providers: