diff --git a/aws-ts-oidc-provider-pulumi-cloud/Pulumi.yaml b/aws-ts-oidc-provider-pulumi-cloud/Pulumi.yaml index eabe384c0..625a021a3 100644 --- a/aws-ts-oidc-provider-pulumi-cloud/Pulumi.yaml +++ b/aws-ts-oidc-provider-pulumi-cloud/Pulumi.yaml @@ -3,9 +3,11 @@ description: ${DESCRIPTION} runtime: nodejs template: - description: A minimal TypeScript Pulumi program to set up AWS OIDC + description: AWS OIDC setup for Pulumi ESC config: aws:region: description: AWS Region default: us-west-2 - \ No newline at end of file + escProject: + description: The name of the ESC project in which to place a generated environment. + default: aws diff --git a/aws-ts-oidc-provider-pulumi-cloud/index.ts b/aws-ts-oidc-provider-pulumi-cloud/index.ts index 4cfc82a37..27546ff8c 100644 --- a/aws-ts-oidc-provider-pulumi-cloud/index.ts +++ b/aws-ts-oidc-provider-pulumi-cloud/index.ts @@ -6,36 +6,42 @@ import * as pulumi from "@pulumi/pulumi"; import * as pulumiservice from "@pulumi/pulumiservice"; import * as tls from "@pulumi/tls"; -// Configurations -const audience = pulumi.getOrganization(); +const config = new pulumi.Config(); +const escProject = config.require("escProject"); + +const pulumiOrg = pulumi.getOrganization(); + +// NOTE: At the time of writing, if you are still using the legacy "default" +// organization, the format for the audience OIDC claim is different. Best +// practice is to avoid using the legacy default project. +const oidcAudience = escProject == "default" ? pulumiOrg : `aws:${pulumiOrg}`; + const oidcIdpUrl: string = "https://api.pulumi.com/oidc"; -// Get TLS thumbprint for OIDC Provider const certs = tls.getCertificateOutput({ url: oidcIdpUrl, }); + const thumbprint = certs.certificates[0].sha1Fingerprint; function getProviderArn() { const existingProvider = aws.iam.getOpenIdConnectProviderOutput({ url: oidcIdpUrl, }); + if (existingProvider) { - console.log("OIDC Provider already exists ..."); - // upsert audience - const cmd = new command.local.Command("oidc-client-id", { - create: pulumi.interpolate`aws iam add-client-id-to-open-id-connect-provider --open-id-connect-provider-arn ${existingProvider.arn} --client-id aws:${audience}`, - delete: pulumi.interpolate`aws iam remove-client-id-from-open-id-connect-provider --open-id-connect-provider-arn ${existingProvider.arn} --client-id aws:${audience}`, + console.log("OIDC Provider already exists. Adding current Pulumi org as an audience to the existing provider."); + + new command.local.Command("oidc-client-id", { + create: pulumi.interpolate`aws iam add-client-id-to-open-id-connect-provider --open-id-connect-provider-arn ${existingProvider.arn} --client-id ${oidcAudience}`, + delete: pulumi.interpolate`aws iam remove-client-id-from-open-id-connect-provider --open-id-connect-provider-arn ${existingProvider.arn} --client-id ${oidcAudience}`, }); return existingProvider.arn; } else { - console.log("Creating OIDC Provider ..."); const provider = new aws.iam.OpenIdConnectProvider("oidcProvider", { - clientIdLists: [audience], + clientIdLists: [pulumiOrg], url: oidcIdpUrl, thumbprintLists: [thumbprint], - }, { - protect: true, }); return provider.arn; } @@ -55,49 +61,38 @@ const policyDocument = arn.apply(arn => aws.iam.getPolicyDocument({ conditions: [{ test: "StringEquals", variable: `api.pulumi.com/oidc:aud`, - values: [`aws:${audience}`], // new format + values: [oidcAudience], }], }], })); -// // Create a new role that can be assumed by the OIDC provider -const role = new aws.iam.Role("role", { +const role = new aws.iam.Role("pulumi-cloud-admin", { assumeRolePolicy: policyDocument.json, }); -// Attach the AWS managed policy "AdministratorAccess" to the role. -const rpa = new aws.iam.RolePolicyAttachment("policy", { +new aws.iam.RolePolicyAttachment("policy", { policyArn: "arn:aws:iam::aws:policy/AdministratorAccess", role: role.name, }); -const envJson = pulumi.jsonStringify({ - "values": { - "aws": { - "login": { - "fn::open::aws-login": { - "oidc": { - "duration": "1h", - "roleArn": role.arn, - "sessionName": "pulumi-environments-session", - }, - }, - }, - }, - "environmentVariables": { - "AWS_ACCESS_KEY_ID": "${aws.login.accessKeyId}", - "AWS_SECRET_ACCESS_KEY": "${aws.login.secretAccessKey}", - "AWS_SESSION_TOKEN": "${aws.login.sessionToken}", - }, - }, -}); - -const envAsset = envJson.apply(json => new pulumi.asset.StringAsset(json)); +export const envYaml = pulumi.interpolate` +values: + aws: + login: + fn::open::aws-login: + oidc: + duration: 1h + roleArn: ${role.arn} + sessionName: pulumi-esc + environmentVariables: + AWS_ACCESS_KEY_ID: \${aws.login.accessKeyId} + AWS_SECRET_ACCESS_KEY: \${aws.login.secretAccessKey} + AWS_SESSION_TOKEN: \${aws.login.sessionToken} +`; -// Create a new environment -const env = new pulumiservice.Environment("aws-oidc-admin", { - name: "test", - // project: "auth", // post esc-GA - organization: audience, - yaml: envAsset, +new pulumiservice.Environment("aws-oidc-admin", { + organization: pulumiOrg, + project: escProject, + name: "aws-oidc-admin", + yaml: envYaml.apply(yaml => new pulumi.asset.StringAsset(yaml)), }); diff --git a/aws-ts-oidc-provider-pulumi-cloud/package.json b/aws-ts-oidc-provider-pulumi-cloud/package.json index f53e2bea4..e421533f5 100644 --- a/aws-ts-oidc-provider-pulumi-cloud/package.json +++ b/aws-ts-oidc-provider-pulumi-cloud/package.json @@ -9,7 +9,7 @@ "@pulumi/aws": "^6.52.0", "@pulumi/command": "^1.0.1", "@pulumi/pulumi": "^3.133.0", - "@pulumi/pulumiservice": "0.23.2", + "@pulumi/pulumiservice": "^0.26.1", "@pulumi/tls": "^5.0.6" } }