1+ import * as pulumi from "@pulumi/pulumi" ;
2+ import * as gcp from "@pulumi/gcp" ;
3+ import * as random from "@pulumi/random" ;
4+ import * as pcloud from "@pulumi/pulumiservice" ;
5+
6+ const config = new pulumi . Config ( ) ;
7+ const gcpConfig = new pulumi . Config ( "gcp" ) ;
8+
9+ const gcpProjectName = gcpConfig . require ( "project" ) ;
10+
11+ // In most cases, it's safe to assume that this stack is run in the same Pulumi
12+ // org in which the OIDC environment is being configured. If not, set the
13+ // escEnvOrg config to the name of the org where the environment is going to be
14+ // configured.
15+ const escEnvOrg = config . get ( "escEnvOrg" ) || pulumi . getOrganization ( ) ;
16+ const escEnvProject = config . get ( "escEnvProject" ) || `gcloud` ;
17+ const escEnvName = config . get ( "escEnvName" ) || `${ gcpProjectName } -admin` ;
18+
19+ // We use a shorter name for the Workload Identity Pool and Service Account IDs
20+ // because they have character limits of 30 and 32 respectively, and the Google
21+ // Cloud project name is redundant in this context anyway, since we already know
22+ // what Google Cloud project we are in:
23+ const workloadIdentityPoolId = `${ escEnvOrg } -admin` ;
24+ const serviceAccountId = workloadIdentityPoolId . replace ( "-" , "" ) ;
25+
26+ const randomSuffix = new random . RandomString ( `random-suffix` , {
27+ length : 5 ,
28+ lower : true ,
29+ upper : false ,
30+ special : false
31+ } ) ;
32+
33+ // The Workload Identity Pool id uses a random suffix so that this stack can be
34+ // brought up and down repeatably: Workload Identity Pools only soft deletes and
35+ // will auto-purge after 30 days. It is not possible to force a hard delete:
36+ const identityPool = new gcp . iam . WorkloadIdentityPool ( `identity-pool` , {
37+ workloadIdentityPoolId : pulumi . interpolate `${ workloadIdentityPoolId } -${ randomSuffix . result } `
38+ } ) ;
39+
40+ const oidcProvider = new gcp . iam . WorkloadIdentityPoolProvider ( `identity-pool-provider` , {
41+ workloadIdentityPoolId : identityPool . workloadIdentityPoolId ,
42+ workloadIdentityPoolProviderId : `pulumi-cloud-${ pulumi . getOrganization ( ) } -oidc` ,
43+ oidc : {
44+ issuerUri : "https://api.pulumi.com/oidc" ,
45+ allowedAudiences : [ `gcp:${ pulumi . getOrganization ( ) } ` ]
46+ } ,
47+ attributeMapping : {
48+ "google.subject" : "assertion.sub"
49+ }
50+ } ) ;
51+
52+ const serviceAccount = new gcp . serviceaccount . Account ( "service-account" , {
53+ accountId : serviceAccountId ,
54+ project : gcpProjectName
55+ } ) ;
56+
57+ new gcp . projects . IAMMember ( "service-account" , {
58+ member : pulumi . interpolate `serviceAccount:${ serviceAccount . email } ` ,
59+ role : "roles/admin" ,
60+ project : gcpProjectName
61+ } ) ;
62+
63+ new gcp . serviceaccount . IAMBinding ( "service-account" , {
64+ serviceAccountId : serviceAccount . id ,
65+ role : "roles/iam.workloadIdentityUser" ,
66+ members : [ pulumi . interpolate `principalSet://iam.googleapis.com/${ identityPool . name } /*` ]
67+ } ) ;
68+
69+ // fn::open::gcp-login requires project number instead of project name:
70+ const projectNumber = gcp . projects . getProjectOutput ( {
71+ filter : `name:${ gcpProjectName } `
72+ } ) . projects [ 0 ] . number
73+ . apply ( projectNumber => + projectNumber ) ; // this casts it from string to a number
74+
75+ const envYaml = pulumi . interpolate `
76+ values:
77+ gcp:
78+ login:
79+ fn::open::gcp-login:
80+ project: ${ projectNumber }
81+ oidc:
82+ workloadPoolId: ${ oidcProvider . workloadIdentityPoolId }
83+ providerId: ${ oidcProvider . workloadIdentityPoolProviderId }
84+ serviceAccount: ${ serviceAccount . email }
85+ subjectAttributes:
86+ - currentEnvironment.name
87+ pulumiConfig:
88+ gpc:project: \${gcp.login.project}
89+ environmentVariables:
90+ # The Google Cloud SDK (which is used by the Pulumi provider) requires the project to be set by number:
91+ GOOGLE_CLOUD_PROJECT: \${gcp.login.project}
92+ # The gcloud CLI requires the project be set by name, and via a different env var.
93+ # See: https://cloud.google.com/sdk/docs/properties#setting_properties_using_environment_variables
94+ CLOUDSDK_CORE_PROJECT: ${ gcpProjectName }
95+ GOOGLE_OAUTH_ACCESS_TOKEN: \${gcp.login.accessToken}
96+ CLOUDSDK_AUTH_ACCESS_TOKEN: \${gcp.login.accessToken}
97+ USE_GKE_GCLOUD_AUTH_PLUGIN: True
98+ ` ;
99+
100+ const environment = new pcloud . Environment ( "environment" , {
101+ organization : escEnvOrg ,
102+ project : escEnvProject ,
103+ name : escEnvName ,
104+ yaml : envYaml ,
105+ } ) ;
106+
107+ export const escEnvId = environment . id ;
0 commit comments