The gcp:cloudbuildv2/connection:Connection resource, part of the Pulumi GCP provider, establishes authenticated connections between Cloud Build and source control platforms: GitHub, GitHub Enterprise, Bitbucket, or GitLab. This guide focuses on three capabilities: GitHub.com connections via GitHub App, GitHub Enterprise Server connections with webhook secrets, and personal access token authentication.
Connections depend on pre-configured GitHub Apps, Secret Manager secrets containing credentials, and IAM policies granting the Cloud Build service account access to those secrets. The examples are intentionally small. Combine them with your own secret management and IAM configuration.
Connect to GitHub with an app installation
Teams using GitHub.com for source control establish connections that Cloud Build uses to access repositories. The GitHub App installation model provides scoped access without requiring personal access tokens.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const my_connection = new gcp.cloudbuildv2.Connection("my-connection", {
location: "us-central1",
name: "tf-test-connection",
githubConfig: {
appInstallationId: 0,
authorizerCredential: {
oauthTokenSecretVersion: "projects/gcb-terraform-creds/secrets/github-pat/versions/1",
},
},
});
import pulumi
import pulumi_gcp as gcp
my_connection = gcp.cloudbuildv2.Connection("my-connection",
location="us-central1",
name="tf-test-connection",
github_config={
"app_installation_id": 0,
"authorizer_credential": {
"oauth_token_secret_version": "projects/gcb-terraform-creds/secrets/github-pat/versions/1",
},
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuildv2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := cloudbuildv2.NewConnection(ctx, "my-connection", &cloudbuildv2.ConnectionArgs{
Location: pulumi.String("us-central1"),
Name: pulumi.String("tf-test-connection"),
GithubConfig: &cloudbuildv2.ConnectionGithubConfigArgs{
AppInstallationId: pulumi.Int(0),
AuthorizerCredential: &cloudbuildv2.ConnectionGithubConfigAuthorizerCredentialArgs{
OauthTokenSecretVersion: pulumi.String("projects/gcb-terraform-creds/secrets/github-pat/versions/1"),
},
},
})
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 my_connection = new Gcp.CloudBuildV2.Connection("my-connection", new()
{
Location = "us-central1",
Name = "tf-test-connection",
GithubConfig = new Gcp.CloudBuildV2.Inputs.ConnectionGithubConfigArgs
{
AppInstallationId = 0,
AuthorizerCredential = new Gcp.CloudBuildV2.Inputs.ConnectionGithubConfigAuthorizerCredentialArgs
{
OauthTokenSecretVersion = "projects/gcb-terraform-creds/secrets/github-pat/versions/1",
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudbuildv2.Connection;
import com.pulumi.gcp.cloudbuildv2.ConnectionArgs;
import com.pulumi.gcp.cloudbuildv2.inputs.ConnectionGithubConfigArgs;
import com.pulumi.gcp.cloudbuildv2.inputs.ConnectionGithubConfigAuthorizerCredentialArgs;
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 my_connection = new Connection("my-connection", ConnectionArgs.builder()
.location("us-central1")
.name("tf-test-connection")
.githubConfig(ConnectionGithubConfigArgs.builder()
.appInstallationId(0)
.authorizerCredential(ConnectionGithubConfigAuthorizerCredentialArgs.builder()
.oauthTokenSecretVersion("projects/gcb-terraform-creds/secrets/github-pat/versions/1")
.build())
.build())
.build());
}
}
resources:
my-connection:
type: gcp:cloudbuildv2:Connection
properties:
location: us-central1
name: tf-test-connection
githubConfig:
appInstallationId: 0
authorizerCredential:
oauthTokenSecretVersion: projects/gcb-terraform-creds/secrets/github-pat/versions/1
The githubConfig block specifies GitHub.com as the target platform. The appInstallationId identifies which GitHub App installation to use, and authorizerCredential points to an OAuth token stored in Secret Manager. Cloud Build retrieves the token at runtime to authenticate API requests.
Connect to GitHub Enterprise with webhook secrets
Organizations running GitHub Enterprise Server need connections that authenticate to self-hosted instances using private keys and webhook secrets for event delivery.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as std from "@pulumi/std";
const private_key_secret = new gcp.secretmanager.Secret("private-key-secret", {
secretId: "ghe-pk-secret",
replication: {
auto: {},
},
});
const private_key_secret_version = new gcp.secretmanager.SecretVersion("private-key-secret-version", {
secret: private_key_secret.id,
secretData: std.file({
input: "private-key.pem",
}).then(invoke => invoke.result),
});
const webhook_secret_secret = new gcp.secretmanager.Secret("webhook-secret-secret", {
secretId: "github-token-secret",
replication: {
auto: {},
},
});
const webhook_secret_secret_version = new gcp.secretmanager.SecretVersion("webhook-secret-secret-version", {
secret: webhook_secret_secret.id,
secretData: "<webhook-secret-data>",
});
const p4sa_secretAccessor = gcp.organizations.getIAMPolicy({
bindings: [{
role: "roles/secretmanager.secretAccessor",
members: ["serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com"],
}],
});
const policy_pk = new gcp.secretmanager.SecretIamPolicy("policy-pk", {
secretId: private_key_secret.secretId,
policyData: p4sa_secretAccessor.then(p4sa_secretAccessor => p4sa_secretAccessor.policyData),
});
const policy_whs = new gcp.secretmanager.SecretIamPolicy("policy-whs", {
secretId: webhook_secret_secret.secretId,
policyData: p4sa_secretAccessor.then(p4sa_secretAccessor => p4sa_secretAccessor.policyData),
});
const my_connection = new gcp.cloudbuildv2.Connection("my-connection", {
location: "us-central1",
name: "my-terraform-ghe-connection",
githubEnterpriseConfig: {
hostUri: "https://ghe.com",
privateKeySecretVersion: private_key_secret_version.id,
webhookSecretSecretVersion: webhook_secret_secret_version.id,
appId: 200,
appSlug: "gcb-app",
appInstallationId: 300,
},
}, {
dependsOn: [
policy_pk,
policy_whs,
],
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std
private_key_secret = gcp.secretmanager.Secret("private-key-secret",
secret_id="ghe-pk-secret",
replication={
"auto": {},
})
private_key_secret_version = gcp.secretmanager.SecretVersion("private-key-secret-version",
secret=private_key_secret.id,
secret_data=std.file(input="private-key.pem").result)
webhook_secret_secret = gcp.secretmanager.Secret("webhook-secret-secret",
secret_id="github-token-secret",
replication={
"auto": {},
})
webhook_secret_secret_version = gcp.secretmanager.SecretVersion("webhook-secret-secret-version",
secret=webhook_secret_secret.id,
secret_data="<webhook-secret-data>")
p4sa_secret_accessor = gcp.organizations.get_iam_policy(bindings=[{
"role": "roles/secretmanager.secretAccessor",
"members": ["serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com"],
}])
policy_pk = gcp.secretmanager.SecretIamPolicy("policy-pk",
secret_id=private_key_secret.secret_id,
policy_data=p4sa_secret_accessor.policy_data)
policy_whs = gcp.secretmanager.SecretIamPolicy("policy-whs",
secret_id=webhook_secret_secret.secret_id,
policy_data=p4sa_secret_accessor.policy_data)
my_connection = gcp.cloudbuildv2.Connection("my-connection",
location="us-central1",
name="my-terraform-ghe-connection",
github_enterprise_config={
"host_uri": "https://ghe.com",
"private_key_secret_version": private_key_secret_version.id,
"webhook_secret_secret_version": webhook_secret_secret_version.id,
"app_id": 200,
"app_slug": "gcb-app",
"app_installation_id": 300,
},
opts = pulumi.ResourceOptions(depends_on=[
policy_pk,
policy_whs,
]))
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuildv2"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
"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 {
private_key_secret, err := secretmanager.NewSecret(ctx, "private-key-secret", &secretmanager.SecretArgs{
SecretId: pulumi.String("ghe-pk-secret"),
Replication: &secretmanager.SecretReplicationArgs{
Auto: &secretmanager.SecretReplicationAutoArgs{},
},
})
if err != nil {
return err
}
invokeFile, err := std.File(ctx, &std.FileArgs{
Input: "private-key.pem",
}, nil)
if err != nil {
return err
}
private_key_secret_version, err := secretmanager.NewSecretVersion(ctx, "private-key-secret-version", &secretmanager.SecretVersionArgs{
Secret: private_key_secret.ID(),
SecretData: pulumi.String(invokeFile.Result),
})
if err != nil {
return err
}
webhook_secret_secret, err := secretmanager.NewSecret(ctx, "webhook-secret-secret", &secretmanager.SecretArgs{
SecretId: pulumi.String("github-token-secret"),
Replication: &secretmanager.SecretReplicationArgs{
Auto: &secretmanager.SecretReplicationAutoArgs{},
},
})
if err != nil {
return err
}
webhook_secret_secret_version, err := secretmanager.NewSecretVersion(ctx, "webhook-secret-secret-version", &secretmanager.SecretVersionArgs{
Secret: webhook_secret_secret.ID(),
SecretData: pulumi.String("<webhook-secret-data>"),
})
if err != nil {
return err
}
p4sa_secretAccessor, err := organizations.LookupIAMPolicy(ctx, &organizations.LookupIAMPolicyArgs{
Bindings: []organizations.GetIAMPolicyBinding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
"serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com",
},
},
},
}, nil)
if err != nil {
return err
}
policy_pk, err := secretmanager.NewSecretIamPolicy(ctx, "policy-pk", &secretmanager.SecretIamPolicyArgs{
SecretId: private_key_secret.SecretId,
PolicyData: pulumi.String(p4sa_secretAccessor.PolicyData),
})
if err != nil {
return err
}
policy_whs, err := secretmanager.NewSecretIamPolicy(ctx, "policy-whs", &secretmanager.SecretIamPolicyArgs{
SecretId: webhook_secret_secret.SecretId,
PolicyData: pulumi.String(p4sa_secretAccessor.PolicyData),
})
if err != nil {
return err
}
_, err = cloudbuildv2.NewConnection(ctx, "my-connection", &cloudbuildv2.ConnectionArgs{
Location: pulumi.String("us-central1"),
Name: pulumi.String("my-terraform-ghe-connection"),
GithubEnterpriseConfig: &cloudbuildv2.ConnectionGithubEnterpriseConfigArgs{
HostUri: pulumi.String("https://ghe.com"),
PrivateKeySecretVersion: private_key_secret_version.ID(),
WebhookSecretSecretVersion: webhook_secret_secret_version.ID(),
AppId: pulumi.Int(200),
AppSlug: pulumi.String("gcb-app"),
AppInstallationId: pulumi.Int(300),
},
}, pulumi.DependsOn([]pulumi.Resource{
policy_pk,
policy_whs,
}))
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 private_key_secret = new Gcp.SecretManager.Secret("private-key-secret", new()
{
SecretId = "ghe-pk-secret",
Replication = new Gcp.SecretManager.Inputs.SecretReplicationArgs
{
Auto = null,
},
});
var private_key_secret_version = new Gcp.SecretManager.SecretVersion("private-key-secret-version", new()
{
Secret = private_key_secret.Id,
SecretData = Std.File.Invoke(new()
{
Input = "private-key.pem",
}).Apply(invoke => invoke.Result),
});
var webhook_secret_secret = new Gcp.SecretManager.Secret("webhook-secret-secret", new()
{
SecretId = "github-token-secret",
Replication = new Gcp.SecretManager.Inputs.SecretReplicationArgs
{
Auto = null,
},
});
var webhook_secret_secret_version = new Gcp.SecretManager.SecretVersion("webhook-secret-secret-version", new()
{
Secret = webhook_secret_secret.Id,
SecretData = "<webhook-secret-data>",
});
var p4sa_secretAccessor = Gcp.Organizations.GetIAMPolicy.Invoke(new()
{
Bindings = new[]
{
new Gcp.Organizations.Inputs.GetIAMPolicyBindingInputArgs
{
Role = "roles/secretmanager.secretAccessor",
Members = new[]
{
"serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com",
},
},
},
});
var policy_pk = new Gcp.SecretManager.SecretIamPolicy("policy-pk", new()
{
SecretId = private_key_secret.SecretId,
PolicyData = p4sa_secretAccessor.Apply(p4sa_secretAccessor => p4sa_secretAccessor.Apply(getIAMPolicyResult => getIAMPolicyResult.PolicyData)),
});
var policy_whs = new Gcp.SecretManager.SecretIamPolicy("policy-whs", new()
{
SecretId = webhook_secret_secret.SecretId,
PolicyData = p4sa_secretAccessor.Apply(p4sa_secretAccessor => p4sa_secretAccessor.Apply(getIAMPolicyResult => getIAMPolicyResult.PolicyData)),
});
var my_connection = new Gcp.CloudBuildV2.Connection("my-connection", new()
{
Location = "us-central1",
Name = "my-terraform-ghe-connection",
GithubEnterpriseConfig = new Gcp.CloudBuildV2.Inputs.ConnectionGithubEnterpriseConfigArgs
{
HostUri = "https://ghe.com",
PrivateKeySecretVersion = private_key_secret_version.Id,
WebhookSecretSecretVersion = webhook_secret_secret_version.Id,
AppId = 200,
AppSlug = "gcb-app",
AppInstallationId = 300,
},
}, new CustomResourceOptions
{
DependsOn =
{
policy_pk,
policy_whs,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.secretmanager.Secret;
import com.pulumi.gcp.secretmanager.SecretArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretReplicationArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretReplicationAutoArgs;
import com.pulumi.gcp.secretmanager.SecretVersion;
import com.pulumi.gcp.secretmanager.SecretVersionArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetIAMPolicyArgs;
import com.pulumi.gcp.secretmanager.SecretIamPolicy;
import com.pulumi.gcp.secretmanager.SecretIamPolicyArgs;
import com.pulumi.gcp.cloudbuildv2.Connection;
import com.pulumi.gcp.cloudbuildv2.ConnectionArgs;
import com.pulumi.gcp.cloudbuildv2.inputs.ConnectionGithubEnterpriseConfigArgs;
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 private_key_secret = new Secret("private-key-secret", SecretArgs.builder()
.secretId("ghe-pk-secret")
.replication(SecretReplicationArgs.builder()
.auto(SecretReplicationAutoArgs.builder()
.build())
.build())
.build());
var private_key_secret_version = new SecretVersion("private-key-secret-version", SecretVersionArgs.builder()
.secret(private_key_secret.id())
.secretData(StdFunctions.file(FileArgs.builder()
.input("private-key.pem")
.build()).result())
.build());
var webhook_secret_secret = new Secret("webhook-secret-secret", SecretArgs.builder()
.secretId("github-token-secret")
.replication(SecretReplicationArgs.builder()
.auto(SecretReplicationAutoArgs.builder()
.build())
.build())
.build());
var webhook_secret_secret_version = new SecretVersion("webhook-secret-secret-version", SecretVersionArgs.builder()
.secret(webhook_secret_secret.id())
.secretData("<webhook-secret-data>")
.build());
final var p4sa-secretAccessor = OrganizationsFunctions.getIAMPolicy(GetIAMPolicyArgs.builder()
.bindings(GetIAMPolicyBindingArgs.builder()
.role("roles/secretmanager.secretAccessor")
.members("serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com")
.build())
.build());
var policy_pk = new SecretIamPolicy("policy-pk", SecretIamPolicyArgs.builder()
.secretId(private_key_secret.secretId())
.policyData(p4sa_secretAccessor.policyData())
.build());
var policy_whs = new SecretIamPolicy("policy-whs", SecretIamPolicyArgs.builder()
.secretId(webhook_secret_secret.secretId())
.policyData(p4sa_secretAccessor.policyData())
.build());
var my_connection = new Connection("my-connection", ConnectionArgs.builder()
.location("us-central1")
.name("my-terraform-ghe-connection")
.githubEnterpriseConfig(ConnectionGithubEnterpriseConfigArgs.builder()
.hostUri("https://ghe.com")
.privateKeySecretVersion(private_key_secret_version.id())
.webhookSecretSecretVersion(webhook_secret_secret_version.id())
.appId(200)
.appSlug("gcb-app")
.appInstallationId(300)
.build())
.build(), CustomResourceOptions.builder()
.dependsOn(
policy_pk,
policy_whs)
.build());
}
}
resources:
private-key-secret:
type: gcp:secretmanager:Secret
properties:
secretId: ghe-pk-secret
replication:
auto: {}
private-key-secret-version:
type: gcp:secretmanager:SecretVersion
properties:
secret: ${["private-key-secret"].id}
secretData:
fn::invoke:
function: std:file
arguments:
input: private-key.pem
return: result
webhook-secret-secret:
type: gcp:secretmanager:Secret
properties:
secretId: github-token-secret
replication:
auto: {}
webhook-secret-secret-version:
type: gcp:secretmanager:SecretVersion
properties:
secret: ${["webhook-secret-secret"].id}
secretData: <webhook-secret-data>
policy-pk:
type: gcp:secretmanager:SecretIamPolicy
properties:
secretId: ${["private-key-secret"].secretId}
policyData: ${["p4sa-secretAccessor"].policyData}
policy-whs:
type: gcp:secretmanager:SecretIamPolicy
properties:
secretId: ${["webhook-secret-secret"].secretId}
policyData: ${["p4sa-secretAccessor"].policyData}
my-connection:
type: gcp:cloudbuildv2:Connection
properties:
location: us-central1
name: my-terraform-ghe-connection
githubEnterpriseConfig:
hostUri: https://ghe.com
privateKeySecretVersion: ${["private-key-secret-version"].id}
webhookSecretSecretVersion: ${["webhook-secret-secret-version"].id}
appId: 200
appSlug: gcb-app
appInstallationId: 300
options:
dependsOn:
- ${["policy-pk"]}
- ${["policy-whs"]}
variables:
p4sa-secretAccessor:
fn::invoke:
function: gcp:organizations:getIAMPolicy
arguments:
bindings:
- role: roles/secretmanager.secretAccessor
members:
- serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com
The githubEnterpriseConfig block targets a self-hosted GitHub Enterprise instance via hostUri. The privateKeySecretVersion and webhookSecretSecretVersion properties reference Secret Manager secrets containing the GitHub App’s private key and webhook secret. The example creates these secrets, grants the Cloud Build service account access via IAM policies, then establishes the connection with explicit dependsOn to ensure secrets are accessible before connection creation.
Connect to GitHub with a personal access token
Some workflows use personal access tokens stored in Secret Manager rather than GitHub App installations, providing an alternative authentication method for GitHub.com connections.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as std from "@pulumi/std";
const github_token_secret = new gcp.secretmanager.Secret("github-token-secret", {
secretId: "github-token-secret",
replication: {
auto: {},
},
});
const github_token_secret_version = new gcp.secretmanager.SecretVersion("github-token-secret-version", {
secret: github_token_secret.id,
secretData: std.file({
input: "my-github-token.txt",
}).then(invoke => invoke.result),
});
const p4sa_secretAccessor = gcp.organizations.getIAMPolicy({
bindings: [{
role: "roles/secretmanager.secretAccessor",
members: ["serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com"],
}],
});
const policy = new gcp.secretmanager.SecretIamPolicy("policy", {
secretId: github_token_secret.secretId,
policyData: p4sa_secretAccessor.then(p4sa_secretAccessor => p4sa_secretAccessor.policyData),
});
const my_connection = new gcp.cloudbuildv2.Connection("my-connection", {
location: "us-central1",
name: "my-connection",
githubConfig: {
appInstallationId: 123123,
authorizerCredential: {
oauthTokenSecretVersion: github_token_secret_version.id,
},
},
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std
github_token_secret = gcp.secretmanager.Secret("github-token-secret",
secret_id="github-token-secret",
replication={
"auto": {},
})
github_token_secret_version = gcp.secretmanager.SecretVersion("github-token-secret-version",
secret=github_token_secret.id,
secret_data=std.file(input="my-github-token.txt").result)
p4sa_secret_accessor = gcp.organizations.get_iam_policy(bindings=[{
"role": "roles/secretmanager.secretAccessor",
"members": ["serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com"],
}])
policy = gcp.secretmanager.SecretIamPolicy("policy",
secret_id=github_token_secret.secret_id,
policy_data=p4sa_secret_accessor.policy_data)
my_connection = gcp.cloudbuildv2.Connection("my-connection",
location="us-central1",
name="my-connection",
github_config={
"app_installation_id": 123123,
"authorizer_credential": {
"oauth_token_secret_version": github_token_secret_version.id,
},
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudbuildv2"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/organizations"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/secretmanager"
"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 {
github_token_secret, err := secretmanager.NewSecret(ctx, "github-token-secret", &secretmanager.SecretArgs{
SecretId: pulumi.String("github-token-secret"),
Replication: &secretmanager.SecretReplicationArgs{
Auto: &secretmanager.SecretReplicationAutoArgs{},
},
})
if err != nil {
return err
}
invokeFile, err := std.File(ctx, &std.FileArgs{
Input: "my-github-token.txt",
}, nil)
if err != nil {
return err
}
github_token_secret_version, err := secretmanager.NewSecretVersion(ctx, "github-token-secret-version", &secretmanager.SecretVersionArgs{
Secret: github_token_secret.ID(),
SecretData: pulumi.String(invokeFile.Result),
})
if err != nil {
return err
}
p4sa_secretAccessor, err := organizations.LookupIAMPolicy(ctx, &organizations.LookupIAMPolicyArgs{
Bindings: []organizations.GetIAMPolicyBinding{
{
Role: "roles/secretmanager.secretAccessor",
Members: []string{
"serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com",
},
},
},
}, nil)
if err != nil {
return err
}
_, err = secretmanager.NewSecretIamPolicy(ctx, "policy", &secretmanager.SecretIamPolicyArgs{
SecretId: github_token_secret.SecretId,
PolicyData: pulumi.String(p4sa_secretAccessor.PolicyData),
})
if err != nil {
return err
}
_, err = cloudbuildv2.NewConnection(ctx, "my-connection", &cloudbuildv2.ConnectionArgs{
Location: pulumi.String("us-central1"),
Name: pulumi.String("my-connection"),
GithubConfig: &cloudbuildv2.ConnectionGithubConfigArgs{
AppInstallationId: pulumi.Int(123123),
AuthorizerCredential: &cloudbuildv2.ConnectionGithubConfigAuthorizerCredentialArgs{
OauthTokenSecretVersion: github_token_secret_version.ID(),
},
},
})
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 github_token_secret = new Gcp.SecretManager.Secret("github-token-secret", new()
{
SecretId = "github-token-secret",
Replication = new Gcp.SecretManager.Inputs.SecretReplicationArgs
{
Auto = null,
},
});
var github_token_secret_version = new Gcp.SecretManager.SecretVersion("github-token-secret-version", new()
{
Secret = github_token_secret.Id,
SecretData = Std.File.Invoke(new()
{
Input = "my-github-token.txt",
}).Apply(invoke => invoke.Result),
});
var p4sa_secretAccessor = Gcp.Organizations.GetIAMPolicy.Invoke(new()
{
Bindings = new[]
{
new Gcp.Organizations.Inputs.GetIAMPolicyBindingInputArgs
{
Role = "roles/secretmanager.secretAccessor",
Members = new[]
{
"serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com",
},
},
},
});
var policy = new Gcp.SecretManager.SecretIamPolicy("policy", new()
{
SecretId = github_token_secret.SecretId,
PolicyData = p4sa_secretAccessor.Apply(p4sa_secretAccessor => p4sa_secretAccessor.Apply(getIAMPolicyResult => getIAMPolicyResult.PolicyData)),
});
var my_connection = new Gcp.CloudBuildV2.Connection("my-connection", new()
{
Location = "us-central1",
Name = "my-connection",
GithubConfig = new Gcp.CloudBuildV2.Inputs.ConnectionGithubConfigArgs
{
AppInstallationId = 123123,
AuthorizerCredential = new Gcp.CloudBuildV2.Inputs.ConnectionGithubConfigAuthorizerCredentialArgs
{
OauthTokenSecretVersion = github_token_secret_version.Id,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.secretmanager.Secret;
import com.pulumi.gcp.secretmanager.SecretArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretReplicationArgs;
import com.pulumi.gcp.secretmanager.inputs.SecretReplicationAutoArgs;
import com.pulumi.gcp.secretmanager.SecretVersion;
import com.pulumi.gcp.secretmanager.SecretVersionArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
import com.pulumi.gcp.organizations.OrganizationsFunctions;
import com.pulumi.gcp.organizations.inputs.GetIAMPolicyArgs;
import com.pulumi.gcp.secretmanager.SecretIamPolicy;
import com.pulumi.gcp.secretmanager.SecretIamPolicyArgs;
import com.pulumi.gcp.cloudbuildv2.Connection;
import com.pulumi.gcp.cloudbuildv2.ConnectionArgs;
import com.pulumi.gcp.cloudbuildv2.inputs.ConnectionGithubConfigArgs;
import com.pulumi.gcp.cloudbuildv2.inputs.ConnectionGithubConfigAuthorizerCredentialArgs;
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 github_token_secret = new Secret("github-token-secret", SecretArgs.builder()
.secretId("github-token-secret")
.replication(SecretReplicationArgs.builder()
.auto(SecretReplicationAutoArgs.builder()
.build())
.build())
.build());
var github_token_secret_version = new SecretVersion("github-token-secret-version", SecretVersionArgs.builder()
.secret(github_token_secret.id())
.secretData(StdFunctions.file(FileArgs.builder()
.input("my-github-token.txt")
.build()).result())
.build());
final var p4sa-secretAccessor = OrganizationsFunctions.getIAMPolicy(GetIAMPolicyArgs.builder()
.bindings(GetIAMPolicyBindingArgs.builder()
.role("roles/secretmanager.secretAccessor")
.members("serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com")
.build())
.build());
var policy = new SecretIamPolicy("policy", SecretIamPolicyArgs.builder()
.secretId(github_token_secret.secretId())
.policyData(p4sa_secretAccessor.policyData())
.build());
var my_connection = new Connection("my-connection", ConnectionArgs.builder()
.location("us-central1")
.name("my-connection")
.githubConfig(ConnectionGithubConfigArgs.builder()
.appInstallationId(123123)
.authorizerCredential(ConnectionGithubConfigAuthorizerCredentialArgs.builder()
.oauthTokenSecretVersion(github_token_secret_version.id())
.build())
.build())
.build());
}
}
resources:
github-token-secret:
type: gcp:secretmanager:Secret
properties:
secretId: github-token-secret
replication:
auto: {}
github-token-secret-version:
type: gcp:secretmanager:SecretVersion
properties:
secret: ${["github-token-secret"].id}
secretData:
fn::invoke:
function: std:file
arguments:
input: my-github-token.txt
return: result
policy:
type: gcp:secretmanager:SecretIamPolicy
properties:
secretId: ${["github-token-secret"].secretId}
policyData: ${["p4sa-secretAccessor"].policyData}
my-connection:
type: gcp:cloudbuildv2:Connection
properties:
location: us-central1
name: my-connection
githubConfig:
appInstallationId: 123123
authorizerCredential:
oauthTokenSecretVersion: ${["github-token-secret-version"].id}
variables:
p4sa-secretAccessor:
fn::invoke:
function: gcp:organizations:getIAMPolicy
arguments:
bindings:
- role: roles/secretmanager.secretAccessor
members:
- serviceAccount:service-123456789@gcp-sa-cloudbuild.iam.gserviceaccount.com
This configuration uses githubConfig like the first example but demonstrates the full Secret Manager setup: creating the secret, storing the token from a file, granting the Cloud Build service account access, and referencing the secret version in the connection. The authorizerCredential property accepts either OAuth tokens from GitHub Apps or personal access tokens.
Beyond these examples
These snippets focus on specific connection-level features: GitHub and GitHub Enterprise authentication, Secret Manager integration for credentials, and IAM policy configuration for service accounts. They’re intentionally minimal rather than full CI/CD pipelines.
The examples rely on pre-existing infrastructure such as GitHub App installations, Secret Manager secrets with OAuth tokens or private keys, and the Cloud Build service account with appropriate permissions. They focus on configuring the connection rather than provisioning the surrounding authentication infrastructure.
To keep things focused, common connection patterns are omitted, including:
- Bitbucket Cloud and Bitbucket Data Center connections
- GitLab connections (gitlab.com or self-hosted)
- Connection disabling (disabled property)
- Custom annotations for metadata
These omissions are intentional: the goal is to illustrate how each connection type is wired, not provide drop-in CI/CD modules. See the Cloud Build Connection resource reference for all available configuration options.
Let's configure GCP Cloud Build Connections
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Secrets & IAM
service-PROJECT_NUMBER@gcp-sa-cloudbuild.iam.gserviceaccount.com) needs roles/secretmanager.secretAccessor on all secrets used for connection credentials.dependsOn to ensure Secret Manager IAM policies are in place first, as shown in the GitHub Enterprise example.Configuration & Setup
githubConfig with appInstallationId and authorizerCredential.oauthTokenSecretVersion pointing to your GitHub token stored in Secret Manager.githubEnterpriseConfig with hostUri, privateKeySecretVersion, webhookSecretSecretVersion, appId, appSlug, and appInstallationId.Immutability & Lifecycle
location, name, and project properties cannot be changed after creation. Modifying these will force resource replacement.annotations field is non-authoritative and only manages annotations in your configuration. Use effectiveAnnotations to see all annotations present on the resource in GCP.Using a different cloud?
Explore integration guides for other cloud providers: