The gcp:cloudbuild/bitbucketServerConfig:BitbucketServerConfig resource, part of the Pulumi GCP provider, establishes the connection between Cloud Build and a self-hosted Bitbucket Server instance, including authentication, webhook configuration, and optional private network connectivity. This guide focuses on three capabilities: basic authentication and webhook setup, repository registration for build triggers, and VPC peering for on-premises instances.
All configurations require pre-existing Secret Manager secrets for authentication tokens and webhook secrets. The VPC peering example additionally requires a configured VPC network with service networking enabled. The examples are intentionally small. Combine them with your own secret management, repository structure, and network topology.
Connect Cloud Build to a Bitbucket Server host
Teams using self-hosted Bitbucket Server need to connect Cloud Build to enable automated builds from repository events.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const bbs_config = new gcp.cloudbuild.BitbucketServerConfig("bbs-config", {
configId: "bbs-config",
location: "us-central1",
hostUri: "https://bbs.com",
secrets: {
adminAccessTokenVersionName: "projects/myProject/secrets/mybbspat/versions/1",
readAccessTokenVersionName: "projects/myProject/secrets/mybbspat/versions/1",
webhookSecretVersionName: "projects/myProject/secrets/mybbspat/versions/1",
},
username: "test",
apiKey: "<api-key>",
});
import pulumi
import pulumi_gcp as gcp
bbs_config = gcp.cloudbuild.BitbucketServerConfig("bbs-config",
config_id="bbs-config",
location="us-central1",
host_uri="https://bbs.com",
secrets={
"admin_access_token_version_name": "projects/myProject/secrets/mybbspat/versions/1",
"read_access_token_version_name": "projects/myProject/secrets/mybbspat/versions/1",
"webhook_secret_version_name": "projects/myProject/secrets/mybbspat/versions/1",
},
username="test",
api_key="<api-key>")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuild"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cloudbuild.NewBitbucketServerConfig(ctx, "bbs-config", &cloudbuild.BitbucketServerConfigArgs{
ConfigId: pulumi.String("bbs-config"),
Location: pulumi.String("us-central1"),
HostUri: pulumi.String("https://bbs.com"),
Secrets: &cloudbuild.BitbucketServerConfigSecretsArgs{
AdminAccessTokenVersionName: pulumi.String("projects/myProject/secrets/mybbspat/versions/1"),
ReadAccessTokenVersionName: pulumi.String("projects/myProject/secrets/mybbspat/versions/1"),
WebhookSecretVersionName: pulumi.String("projects/myProject/secrets/mybbspat/versions/1"),
},
Username: pulumi.String("test"),
ApiKey: pulumi.String("<api-key>"),
})
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 bbs_config = new Gcp.CloudBuild.BitbucketServerConfig("bbs-config", new()
{
ConfigId = "bbs-config",
Location = "us-central1",
HostUri = "https://bbs.com",
Secrets = new Gcp.CloudBuild.Inputs.BitbucketServerConfigSecretsArgs
{
AdminAccessTokenVersionName = "projects/myProject/secrets/mybbspat/versions/1",
ReadAccessTokenVersionName = "projects/myProject/secrets/mybbspat/versions/1",
WebhookSecretVersionName = "projects/myProject/secrets/mybbspat/versions/1",
},
Username = "test",
ApiKey = "<api-key>",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudbuild.BitbucketServerConfig;
import com.pulumi.gcp.cloudbuild.BitbucketServerConfigArgs;
import com.pulumi.gcp.cloudbuild.inputs.BitbucketServerConfigSecretsArgs;
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 bbs_config = new BitbucketServerConfig("bbs-config", BitbucketServerConfigArgs.builder()
.configId("bbs-config")
.location("us-central1")
.hostUri("https://bbs.com")
.secrets(BitbucketServerConfigSecretsArgs.builder()
.adminAccessTokenVersionName("projects/myProject/secrets/mybbspat/versions/1")
.readAccessTokenVersionName("projects/myProject/secrets/mybbspat/versions/1")
.webhookSecretVersionName("projects/myProject/secrets/mybbspat/versions/1")
.build())
.username("test")
.apiKey("<api-key>")
.build());
}
}
resources:
bbs-config:
type: gcp:cloudbuild:BitbucketServerConfig
properties:
configId: bbs-config
location: us-central1
hostUri: https://bbs.com
secrets:
adminAccessTokenVersionName: projects/myProject/secrets/mybbspat/versions/1
readAccessTokenVersionName: projects/myProject/secrets/mybbspat/versions/1
webhookSecretVersionName: projects/myProject/secrets/mybbspat/versions/1
username: test
apiKey: <api-key>
The hostUri points to your Bitbucket Server instance. The secrets block references three Secret Manager secret versions: an admin token for configuration, a read token for repository access, and a webhook secret for validating incoming events. The apiKey attaches to webhooks for additional validation. Once set, hostUri and apiKey cannot be changed without recreating the resource.
Register specific repositories for build triggers
After establishing the connection, specify which repositories should trigger Cloud Build workflows.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const bbs_config_with_repos = new gcp.cloudbuild.BitbucketServerConfig("bbs-config-with-repos", {
configId: "bbs-config",
location: "us-central1",
hostUri: "https://bbs.com",
secrets: {
adminAccessTokenVersionName: "projects/myProject/secrets/mybbspat/versions/1",
readAccessTokenVersionName: "projects/myProject/secrets/mybbspat/versions/1",
webhookSecretVersionName: "projects/myProject/secrets/mybbspat/versions/1",
},
username: "test",
apiKey: "<api-key>",
connectedRepositories: [
{
projectKey: "DEV",
repoSlug: "repo1",
},
{
projectKey: "PROD",
repoSlug: "repo1",
},
],
});
import pulumi
import pulumi_gcp as gcp
bbs_config_with_repos = gcp.cloudbuild.BitbucketServerConfig("bbs-config-with-repos",
config_id="bbs-config",
location="us-central1",
host_uri="https://bbs.com",
secrets={
"admin_access_token_version_name": "projects/myProject/secrets/mybbspat/versions/1",
"read_access_token_version_name": "projects/myProject/secrets/mybbspat/versions/1",
"webhook_secret_version_name": "projects/myProject/secrets/mybbspat/versions/1",
},
username="test",
api_key="<api-key>",
connected_repositories=[
{
"project_key": "DEV",
"repo_slug": "repo1",
},
{
"project_key": "PROD",
"repo_slug": "repo1",
},
])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuild"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cloudbuild.NewBitbucketServerConfig(ctx, "bbs-config-with-repos", &cloudbuild.BitbucketServerConfigArgs{
ConfigId: pulumi.String("bbs-config"),
Location: pulumi.String("us-central1"),
HostUri: pulumi.String("https://bbs.com"),
Secrets: &cloudbuild.BitbucketServerConfigSecretsArgs{
AdminAccessTokenVersionName: pulumi.String("projects/myProject/secrets/mybbspat/versions/1"),
ReadAccessTokenVersionName: pulumi.String("projects/myProject/secrets/mybbspat/versions/1"),
WebhookSecretVersionName: pulumi.String("projects/myProject/secrets/mybbspat/versions/1"),
},
Username: pulumi.String("test"),
ApiKey: pulumi.String("<api-key>"),
ConnectedRepositories: cloudbuild.BitbucketServerConfigConnectedRepositoryArray{
&cloudbuild.BitbucketServerConfigConnectedRepositoryArgs{
ProjectKey: pulumi.String("DEV"),
RepoSlug: pulumi.String("repo1"),
},
&cloudbuild.BitbucketServerConfigConnectedRepositoryArgs{
ProjectKey: pulumi.String("PROD"),
RepoSlug: pulumi.String("repo1"),
},
},
})
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 bbs_config_with_repos = new Gcp.CloudBuild.BitbucketServerConfig("bbs-config-with-repos", new()
{
ConfigId = "bbs-config",
Location = "us-central1",
HostUri = "https://bbs.com",
Secrets = new Gcp.CloudBuild.Inputs.BitbucketServerConfigSecretsArgs
{
AdminAccessTokenVersionName = "projects/myProject/secrets/mybbspat/versions/1",
ReadAccessTokenVersionName = "projects/myProject/secrets/mybbspat/versions/1",
WebhookSecretVersionName = "projects/myProject/secrets/mybbspat/versions/1",
},
Username = "test",
ApiKey = "<api-key>",
ConnectedRepositories = new[]
{
new Gcp.CloudBuild.Inputs.BitbucketServerConfigConnectedRepositoryArgs
{
ProjectKey = "DEV",
RepoSlug = "repo1",
},
new Gcp.CloudBuild.Inputs.BitbucketServerConfigConnectedRepositoryArgs
{
ProjectKey = "PROD",
RepoSlug = "repo1",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudbuild.BitbucketServerConfig;
import com.pulumi.gcp.cloudbuild.BitbucketServerConfigArgs;
import com.pulumi.gcp.cloudbuild.inputs.BitbucketServerConfigSecretsArgs;
import com.pulumi.gcp.cloudbuild.inputs.BitbucketServerConfigConnectedRepositoryArgs;
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 bbs_config_with_repos = new BitbucketServerConfig("bbs-config-with-repos", BitbucketServerConfigArgs.builder()
.configId("bbs-config")
.location("us-central1")
.hostUri("https://bbs.com")
.secrets(BitbucketServerConfigSecretsArgs.builder()
.adminAccessTokenVersionName("projects/myProject/secrets/mybbspat/versions/1")
.readAccessTokenVersionName("projects/myProject/secrets/mybbspat/versions/1")
.webhookSecretVersionName("projects/myProject/secrets/mybbspat/versions/1")
.build())
.username("test")
.apiKey("<api-key>")
.connectedRepositories(
BitbucketServerConfigConnectedRepositoryArgs.builder()
.projectKey("DEV")
.repoSlug("repo1")
.build(),
BitbucketServerConfigConnectedRepositoryArgs.builder()
.projectKey("PROD")
.repoSlug("repo1")
.build())
.build());
}
}
resources:
bbs-config-with-repos:
type: gcp:cloudbuild:BitbucketServerConfig
properties:
configId: bbs-config
location: us-central1
hostUri: https://bbs.com
secrets:
adminAccessTokenVersionName: projects/myProject/secrets/mybbspat/versions/1
readAccessTokenVersionName: projects/myProject/secrets/mybbspat/versions/1
webhookSecretVersionName: projects/myProject/secrets/mybbspat/versions/1
username: test
apiKey: <api-key>
connectedRepositories:
- projectKey: DEV
repoSlug: repo1
- projectKey: PROD
repoSlug: repo1
The connectedRepositories array lists Bitbucket repositories by projectKey and repoSlug. Each entry enables Cloud Build to receive webhook events from that repository. This example connects two repositories across different projects, allowing selective automation rather than monitoring all repositories on the server.
Connect to on-premises Bitbucket via VPC peering
Organizations hosting Bitbucket Server on-premises without public internet access need VPC peering for private connectivity.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as std from "@pulumi/std";
const project = gcp.organizations.getProject({});
const servicenetworking = new gcp.projects.Service("servicenetworking", {service: "servicenetworking.googleapis.com"});
const vpcNetwork = new gcp.compute.Network("vpc_network", {name: "vpc-network"}, {
dependsOn: [servicenetworking],
});
const privateIpAlloc = new gcp.compute.GlobalAddress("private_ip_alloc", {
name: "private-ip-alloc",
purpose: "VPC_PEERING",
addressType: "INTERNAL",
prefixLength: 16,
network: vpcNetwork.id,
});
const _default = new gcp.servicenetworking.Connection("default", {
network: vpcNetwork.id,
service: "servicenetworking.googleapis.com",
reservedPeeringRanges: [privateIpAlloc.name],
}, {
dependsOn: [servicenetworking],
});
const bbs_config_with_peered_network = new gcp.cloudbuild.BitbucketServerConfig("bbs-config-with-peered-network", {
configId: "bbs-config",
location: "us-central1",
hostUri: "https://bbs.com",
secrets: {
adminAccessTokenVersionName: "projects/myProject/secrets/mybbspat/versions/1",
readAccessTokenVersionName: "projects/myProject/secrets/mybbspat/versions/1",
webhookSecretVersionName: "projects/myProject/secrets/mybbspat/versions/1",
},
username: "test",
apiKey: "<api-key>",
peeredNetwork: pulumi.all([vpcNetwork.id, project, project]).apply(([id, project, project1]) => std.replaceOutput({
text: id,
search: project.name,
replace: project1.number,
})).apply(invoke => invoke.result),
sslCa: `-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
`,
}, {
dependsOn: [_default],
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std
project = gcp.organizations.get_project()
servicenetworking = gcp.projects.Service("servicenetworking", service="servicenetworking.googleapis.com")
vpc_network = gcp.compute.Network("vpc_network", name="vpc-network",
opts = pulumi.ResourceOptions(depends_on=[servicenetworking]))
private_ip_alloc = gcp.compute.GlobalAddress("private_ip_alloc",
name="private-ip-alloc",
purpose="VPC_PEERING",
address_type="INTERNAL",
prefix_length=16,
network=vpc_network.id)
default = gcp.servicenetworking.Connection("default",
network=vpc_network.id,
service="servicenetworking.googleapis.com",
reserved_peering_ranges=[private_ip_alloc.name],
opts = pulumi.ResourceOptions(depends_on=[servicenetworking]))
bbs_config_with_peered_network = gcp.cloudbuild.BitbucketServerConfig("bbs-config-with-peered-network",
config_id="bbs-config",
location="us-central1",
host_uri="https://bbs.com",
secrets={
"admin_access_token_version_name": "projects/myProject/secrets/mybbspat/versions/1",
"read_access_token_version_name": "projects/myProject/secrets/mybbspat/versions/1",
"webhook_secret_version_name": "projects/myProject/secrets/mybbspat/versions/1",
},
username="test",
api_key="<api-key>",
peered_network=vpc_network.id.apply(lambda id: std.replace(text=id,
search=project.name,
replace=project.number)).apply(lambda invoke: invoke.result),
ssl_ca="""-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
""",
opts = pulumi.ResourceOptions(depends_on=[default]))
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuild"
"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/projects"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/servicenetworking"
"github.com/pulumi/pulumi-std/sdk/go/std"
"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
}
servicenetworking, err := projects.NewService(ctx, "servicenetworking", &projects.ServiceArgs{
Service: pulumi.String("servicenetworking.googleapis.com"),
})
if err != nil {
return err
}
vpcNetwork, err := compute.NewNetwork(ctx, "vpc_network", &compute.NetworkArgs{
Name: pulumi.String("vpc-network"),
}, pulumi.DependsOn([]pulumi.Resource{
servicenetworking,
}))
if err != nil {
return err
}
privateIpAlloc, err := compute.NewGlobalAddress(ctx, "private_ip_alloc", &compute.GlobalAddressArgs{
Name: pulumi.String("private-ip-alloc"),
Purpose: pulumi.String("VPC_PEERING"),
AddressType: pulumi.String("INTERNAL"),
PrefixLength: pulumi.Int(16),
Network: vpcNetwork.ID(),
})
if err != nil {
return err
}
_default, err := servicenetworking.NewConnection(ctx, "default", &servicenetworking.ConnectionArgs{
Network: vpcNetwork.ID(),
Service: pulumi.String("servicenetworking.googleapis.com"),
ReservedPeeringRanges: pulumi.StringArray{
privateIpAlloc.Name,
},
}, pulumi.DependsOn([]pulumi.Resource{
servicenetworking,
}))
if err != nil {
return err
}
invokeReplace, err := std.Replace(ctx, &std.ReplaceArgs{
Text: id,
Search: project.Name,
Replace: project.Number,
}, nil)
if err != nil {
return err
}
_, err = cloudbuild.NewBitbucketServerConfig(ctx, "bbs-config-with-peered-network", &cloudbuild.BitbucketServerConfigArgs{
ConfigId: pulumi.String("bbs-config"),
Location: pulumi.String("us-central1"),
HostUri: pulumi.String("https://bbs.com"),
Secrets: &cloudbuild.BitbucketServerConfigSecretsArgs{
AdminAccessTokenVersionName: pulumi.String("projects/myProject/secrets/mybbspat/versions/1"),
ReadAccessTokenVersionName: pulumi.String("projects/myProject/secrets/mybbspat/versions/1"),
WebhookSecretVersionName: pulumi.String("projects/myProject/secrets/mybbspat/versions/1"),
},
Username: pulumi.String("test"),
ApiKey: pulumi.String("<api-key>"),
PeeredNetwork: pulumi.String(vpcNetwork.ID().ApplyT(func(id string) (std.ReplaceResult, error) {
%!v(PANIC=Format method: runtime error: invalid memory address or nil pointer dereference)).(std.ReplaceResultOutput).ApplyT(func(invoke std.ReplaceResult) (*string, error) {
return invoke.Result, nil
}).(pulumi.StringPtrOutput)),
SslCa: pulumi.String("-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n-----END CERTIFICATE-----\n"),
}, pulumi.DependsOn([]pulumi.Resource{
_default,
}))
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Std = Pulumi.Std;
return await Deployment.RunAsync(() =>
{
var project = Gcp.Organizations.GetProject.Invoke();
var servicenetworking = new Gcp.Projects.Service("servicenetworking", new()
{
ServiceName = "servicenetworking.googleapis.com",
});
var vpcNetwork = new Gcp.Compute.Network("vpc_network", new()
{
Name = "vpc-network",
}, new CustomResourceOptions
{
DependsOn =
{
servicenetworking,
},
});
var privateIpAlloc = new Gcp.Compute.GlobalAddress("private_ip_alloc", new()
{
Name = "private-ip-alloc",
Purpose = "VPC_PEERING",
AddressType = "INTERNAL",
PrefixLength = 16,
Network = vpcNetwork.Id,
});
var @default = new Gcp.ServiceNetworking.Connection("default", new()
{
Network = vpcNetwork.Id,
Service = "servicenetworking.googleapis.com",
ReservedPeeringRanges = new[]
{
privateIpAlloc.Name,
},
}, new CustomResourceOptions
{
DependsOn =
{
servicenetworking,
},
});
var bbs_config_with_peered_network = new Gcp.CloudBuild.BitbucketServerConfig("bbs-config-with-peered-network", new()
{
ConfigId = "bbs-config",
Location = "us-central1",
HostUri = "https://bbs.com",
Secrets = new Gcp.CloudBuild.Inputs.BitbucketServerConfigSecretsArgs
{
AdminAccessTokenVersionName = "projects/myProject/secrets/mybbspat/versions/1",
ReadAccessTokenVersionName = "projects/myProject/secrets/mybbspat/versions/1",
WebhookSecretVersionName = "projects/myProject/secrets/mybbspat/versions/1",
},
Username = "test",
ApiKey = "<api-key>",
PeeredNetwork = Output.Tuple(vpcNetwork.Id, project, project).Apply(values =>
{
var id = values.Item1;
var project = values.Item2;
var project1 = values.Item3;
return Std.Replace.Invoke(new()
{
Text = id,
Search = project.Apply(getProjectResult => getProjectResult.Name),
Replace = project1.Number,
});
}).Apply(invoke => invoke.Result),
SslCa = @"-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
",
}, new CustomResourceOptions
{
DependsOn =
{
@default,
},
});
});
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.projects.Service;
import com.pulumi.gcp.projects.ServiceArgs;
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.cloudbuild.BitbucketServerConfig;
import com.pulumi.gcp.cloudbuild.BitbucketServerConfigArgs;
import com.pulumi.gcp.cloudbuild.inputs.BitbucketServerConfigSecretsArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.ReplaceArgs;
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) {
final var project = OrganizationsFunctions.getProject(GetProjectArgs.builder()
.build());
var servicenetworking = new Service("servicenetworking", ServiceArgs.builder()
.service("servicenetworking.googleapis.com")
.build());
var vpcNetwork = new Network("vpcNetwork", NetworkArgs.builder()
.name("vpc-network")
.build(), CustomResourceOptions.builder()
.dependsOn(servicenetworking)
.build());
var privateIpAlloc = new GlobalAddress("privateIpAlloc", GlobalAddressArgs.builder()
.name("private-ip-alloc")
.purpose("VPC_PEERING")
.addressType("INTERNAL")
.prefixLength(16)
.network(vpcNetwork.id())
.build());
var default_ = new Connection("default", ConnectionArgs.builder()
.network(vpcNetwork.id())
.service("servicenetworking.googleapis.com")
.reservedPeeringRanges(privateIpAlloc.name())
.build(), CustomResourceOptions.builder()
.dependsOn(servicenetworking)
.build());
var bbs_config_with_peered_network = new BitbucketServerConfig("bbs-config-with-peered-network", BitbucketServerConfigArgs.builder()
.configId("bbs-config")
.location("us-central1")
.hostUri("https://bbs.com")
.secrets(BitbucketServerConfigSecretsArgs.builder()
.adminAccessTokenVersionName("projects/myProject/secrets/mybbspat/versions/1")
.readAccessTokenVersionName("projects/myProject/secrets/mybbspat/versions/1")
.webhookSecretVersionName("projects/myProject/secrets/mybbspat/versions/1")
.build())
.username("test")
.apiKey("<api-key>")
.peeredNetwork(vpcNetwork.id().applyValue(_id -> StdFunctions.replace(ReplaceArgs.builder()
.text(_id)
.search(project.name())
.replace(project.number())
.build())).applyValue(_invoke -> _invoke.result()))
.sslCa("""
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
""")
.build(), CustomResourceOptions.builder()
.dependsOn(default_)
.build());
}
}
resources:
servicenetworking:
type: gcp:projects:Service
properties:
service: servicenetworking.googleapis.com
vpcNetwork:
type: gcp:compute:Network
name: vpc_network
properties:
name: vpc-network
options:
dependsOn:
- ${servicenetworking}
privateIpAlloc:
type: gcp:compute:GlobalAddress
name: private_ip_alloc
properties:
name: private-ip-alloc
purpose: VPC_PEERING
addressType: INTERNAL
prefixLength: 16
network: ${vpcNetwork.id}
default:
type: gcp:servicenetworking:Connection
properties:
network: ${vpcNetwork.id}
service: servicenetworking.googleapis.com
reservedPeeringRanges:
- ${privateIpAlloc.name}
options:
dependsOn:
- ${servicenetworking}
bbs-config-with-peered-network:
type: gcp:cloudbuild:BitbucketServerConfig
properties:
configId: bbs-config
location: us-central1
hostUri: https://bbs.com
secrets:
adminAccessTokenVersionName: projects/myProject/secrets/mybbspat/versions/1
readAccessTokenVersionName: projects/myProject/secrets/mybbspat/versions/1
webhookSecretVersionName: projects/myProject/secrets/mybbspat/versions/1
username: test
apiKey: <api-key>
peeredNetwork:
fn::invoke:
function: std:replace
arguments:
text: ${vpcNetwork.id}
search: ${project.name}
replace: ${project.number}
return: result
sslCa: |
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
options:
dependsOn:
- ${default}
variables:
project:
fn::invoke:
function: gcp:organizations:getProject
arguments: {}
The peeredNetwork property enables private connectivity by routing Cloud Build requests through a VPC network. This example creates the necessary VPC infrastructure: a network, a reserved IP range for peering, and a service networking connection. The sslCa property provides the SSL certificate for validating HTTPS connections to the Bitbucket Server instance. Without peeredNetwork, Cloud Build attempts to reach the instance over the public internet.
Beyond these examples
These snippets focus on specific Bitbucket Server configuration features: authentication and webhook configuration, repository registration, and VPC peering for private connectivity. They’re intentionally minimal rather than full CI/CD pipelines.
The examples rely on pre-existing infrastructure such as Secret Manager secrets (admin token, read token, webhook secret), Bitbucket Server instance with projects and repositories, and VPC network and service networking API (for peered network example). They focus on establishing the connection rather than provisioning the surrounding infrastructure.
To keep things focused, common configuration patterns are omitted, including:
- SSL certificate management and rotation
- Multiple repository configurations across projects
- Network security and firewall rules
- Webhook validation and troubleshooting
These omissions are intentional: the goal is to illustrate how each Bitbucket Server connection feature is wired, not provide drop-in CI/CD modules. See the BitbucketServerConfig resource reference for all available configuration options.
Let's configure GCP Cloud Build Bitbucket Server Integration
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Immutability
apiKey, hostUri, configId, location, and project properties cannot be changed after creation. Modifying apiKey or hostUri will delete and recreate the resource.hostUri is immutable. To change it, you must create a new BitbucketServerConfig resource.apiKey is immutable. Changing it will result in deleting and recreating the resource.Networking & Connectivity
peeredNetwork to your VPC network in the format projects/{project}/global/networks/{network}. The VPC must be enabled for private service connection, as shown in the peered network example.peeredNetwork must be in the format projects/{project}/global/networks/{network}, where {project} is a project number or ID and {network} is the VPC network name.peeredNetwork when your Bitbucket Server instance is hosted on-premises and not reachable by public internet. If left empty, calls will be made over the public internet.Authentication & Secrets
The secrets object requires three Secret Manager version names:
adminAccessTokenVersionNamereadAccessTokenVersionNamewebhookSecretVersionName
sslCa property accepts PEM format certificates with extensions .pem, .cer, or .crt.Repository Management
connectedRepositories array with objects containing projectKey and repoSlug for each repository you want to connect.connectedRepositories is not immutable and can be updated after creation.Using a different cloud?
Explore integration guides for other cloud providers: