Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update aws-ts-oidc example #1707

Merged
merged 5 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion aws-ts-oidc-provider-pulumi-cloud/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/bin/
/node_modules/
test/
test/
Pulumi.test.yaml
14 changes: 2 additions & 12 deletions aws-ts-oidc-provider-pulumi-cloud/Pulumi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,9 @@ description: ${DESCRIPTION}
runtime: nodejs

template:
description: A minimal TypeScript Pulumi program to set up AWS OIDC+Pulumi ESC
description: A minimal TypeScript Pulumi program to set up AWS OIDC
config:
aws:region:
description: The AWS region to deploy into
description: AWS Region
default: us-west-2
oidcIdpUrl:
description: The URL of the OIDC IdP to use
default: https://api.pulumi.com/oidc
thumbprint:
description: The thumbprint of the OIDC IdP SSL certificate.
# This is a valid AWS OIDC thumbprint as of June 2024.
default: 9e99a48a9960b14926bb7f3b02e22da2b0ab7280
escEnv:
description: The Pulumi ESC Environment to create ('.' to skip)
default: aws-oidc-env

22 changes: 3 additions & 19 deletions aws-ts-oidc-provider-pulumi-cloud/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
A Pulumi template to:

- Create AWS resources for AWS OIDC (IdP + Role)
- Create a new Pulumi Cloud ESC Environment (optional)
- Create a new Pulumi Cloud ESC Environment

Last update: July 2024
Last update: September 2024

## 📋 Pre-requisites

Expand All @@ -32,23 +32,7 @@ Once copied to your machine, feel free to edit as needed.

## 🎬 How to run

This template will pick up the thumbprint from the URL that you set in the stack configuration. By default it will use the OIDC IDP URL for Pulumi Cloud, unless you set a different one.

To set a different URL you can run the following command:

```bash
pulumi config set oidcIdpUrl {url}
```

(where `{url}` is the URL for the OIDC IDP)

You must also set the name of the environment that you would like to use:

```bash
pulumi config set escEnv {environment-name}
```

(Note that `{environment-name}` must be in the format `{orgname}/environmentname}` where `orgname` can be your individual account name or the the organization that you are adding the environment to)
This template will pick up the thumbprint from the URL that you set in the stack configuration. By default it will use the OIDC IDP URL for Pulumi Cloud.

To deploy your infrastructure, run:

Expand Down
134 changes: 74 additions & 60 deletions aws-ts-oidc-provider-pulumi-cloud/index.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,103 @@
// Copyright 2024, Pulumi Corporation. All rights reserved.

import * as aws from "@pulumi/aws";
import * as command from "@pulumi/command";
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 oidcIdpUrl: string = config.get("oidcIdpUrl") || "https://api.pulumi.com/oidc";
const escEnv: string = config.require("escEnv");
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;

// Create a new OIDC Provider
const oidcProvider = new aws.iam.OpenIdConnectProvider("oidcProvider", {
clientIdLists: [audience],
url: oidcIdpUrl,
thumbprintLists: [thumbprint],
}, {
protect: true,
});
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}`,
});
return existingProvider.arn;
} else {
console.log("Creating OIDC Provider ...");
const provider = new aws.iam.OpenIdConnectProvider("oidcProvider", {
clientIdLists: [audience],
url: oidcIdpUrl,
thumbprintLists: [thumbprint],
}, {
protect: true,
});
return provider.arn;
}
}

// Create a new role that can be assumed by the OIDC provider
const role = new aws.iam.Role("oidcProviderRole", {
assumeRolePolicy: pulumi.all([oidcProvider.url, oidcProvider.arn, audience]).apply(([url, arn, audience]) => JSON.stringify({
Version: "2012-10-17",
Statement: [{
Effect: "Allow",
Principal: { Federated: arn },
Action: "sts:AssumeRoleWithWebIdentity",
Condition: { StringEquals: { [`${url}:aud`]: [audience] } },
export const arn: pulumi.Output<string> = getProviderArn();

const policyDocument = arn.apply(arn => aws.iam.getPolicyDocument({
version: "2012-10-17",
statements: [{
effect: "Allow",
actions: ["sts:AssumeRoleWithWebIdentity"],
principals: [{
type: "Federated",
identifiers: [arn],
}],
})),
});
conditions: [{
test: "StringEquals",
variable: `api.pulumi.com/oidc:aud`,
values: [`aws:${audience}`], // new format
}],
}],
}));

// Get the existing AdministratorAccess policy
const existingPolicy = aws.iam.getPolicy({
arn: "arn:aws:iam::aws:policy/AdministratorAccess",
// // Create a new role that can be assumed by the OIDC provider
const role = new aws.iam.Role("role", {
assumeRolePolicy: policyDocument.json,
});


// Attach other policies to the role as needed
const attach = new aws.iam.RolePolicyAttachment("oidcProviderRolePolicyAttachment", {
role: role,
policyArn: existingPolicy.then(policy => policy.arn),
// Attach the AWS managed policy "AdministratorAccess" to the role.
const rpa = new aws.iam.RolePolicyAttachment("policy", {
policyArn: "arn:aws:iam::aws:policy/AdministratorAccess",
role: role.name,
});


if (escEnv === ".") {
console.log("Skipping ESC Environment creation ...");
}
else {
const envJson = pulumi.jsonStringify({
"values": {
"aws": {
"login": {
"fn::open::aws-login": {
"oidc": {
"duration": "1h",
"roleArn": role.arn,
"sessionName": "pulumi-environments-session",
},
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));
"environmentVariables": {
"AWS_ACCESS_KEY_ID": "${aws.login.accessKeyId}",
"AWS_SECRET_ACCESS_KEY": "${aws.login.secretAccessKey}",
"AWS_SESSION_TOKEN": "${aws.login.sessionToken}",
},
},
});

const env = new pulumiservice.Environment("oidcEnvironment", {
name: escEnv,
organization: audience,
yaml: envAsset,
});
const envAsset = envJson.apply(json => new pulumi.asset.StringAsset(json));

} // end of else
// Create a new environment
const env = new pulumiservice.Environment("aws-oidc-admin", {
name: "test",
// project: "auth", // post esc-GA
organization: audience,
yaml: envAsset,
});
13 changes: 7 additions & 6 deletions aws-ts-oidc-provider-pulumi-cloud/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"name": "aws-ts-oidc-provider-pulumi-cloud",
"main": "index.ts",
"devDependencies": {
"@types/node": "^20",
"typescript": "^5.4.5"
"@types/node": "^22",
"typescript": "^5.6.2"
},
"dependencies": {
"@pulumi/aws": "^6.40.0",
"@pulumi/pulumi": "^3.120.0",
"@pulumi/pulumiservice": "^0.21.2",
"@pulumi/tls": "^5.0.3"
"@pulumi/aws": "^6.52.0",
"@pulumi/command": "^1.0.1",
"@pulumi/pulumi": "^3.133.0",
"@pulumi/pulumiservice": "0.23.2",
"@pulumi/tls": "^5.0.6"
}
}
Loading