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

upgrade nodejs to 18 and aws-sdk to v3 #65

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
6 changes: 5 additions & 1 deletion usecases/mwaa-public-webserver-custom-domain/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@types/aws-lambda": "^8.10.77",
"@types/cookie": "^0.4.0",
"@types/fs-extra": "^9.0.11",
"@types/node": "^15.12.5",
"@types/node": "^20.11.17",
"aws-sdk": "^2.935.0",
"html-loader": "^2.1.2",
"prettier": "^2.3.2",
Expand All @@ -32,7 +32,11 @@
"webpack-cli": "^4.7.2"
},
"dependencies": {
"@aws-sdk/client-cloudformation": "^3.529.1",
"@aws-sdk/client-cognito-identity-provider": "^3.530.0",
"@aws-sdk/client-lambda": "^3.529.1",
"@aws-sdk/client-mwaa": "^3.49.0",
"@aws-sdk/client-s3": "^3.529.1",
"adm-zip": "^0.5.5",
"aws-jwt-verify": "^1.0.2",
"cookie": "^0.4.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: MIT-0

import { CloudFormationCustomResourceHandler } from "aws-lambda";
import CognitoIdentityServiceProvider from "aws-sdk/clients/cognitoidentityserviceprovider";
import { CognitoIdentityProvider, DescribeUserPoolClientCommandInput } from "@aws-sdk/client-cognito-identity-provider";
import { sendCfnResponse, Status } from "./cfn-response";

async function retrieveClientSecret(
Expand All @@ -17,17 +17,16 @@ async function retrieveClientSecret(
}
const userPoolId = userPoolArn.split("/")[1];
const userPoolRegion = userPoolArn.split(":")[3];
const cognitoClient = new CognitoIdentityServiceProvider({
const cognitoClient = new CognitoIdentityProvider({
region: userPoolRegion,
});
const input: CognitoIdentityServiceProvider.Types.DescribeUserPoolClientRequest =
const input: DescribeUserPoolClientCommandInput =
{
UserPoolId: userPoolId,
ClientId: clientId,
};
const { UserPoolClient } = await cognitoClient
.describeUserPoolClient(input)
.promise();
.describeUserPoolClient(input);
if (!UserPoolClient?.ClientSecret) {
throw new Error(
`User Pool client ${clientId} is not set up with a client secret`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
CloudFormationCustomResourceDeleteEvent,
CloudFormationCustomResourceUpdateEvent,
} from "aws-lambda";
import Lambda from "aws-sdk/clients/lambda";
import { Lambda } from "@aws-sdk/client-lambda";
import Zip from "adm-zip";
import { writeFileSync, mkdtempSync } from "fs";
import { resolve } from "path";
Expand All @@ -27,15 +27,16 @@ async function updateLambdaCode(
`Adding configuration to Lambda function ${lambdaFunction}:\n${stringifiedConfig}`
);
const region = lambdaFunction.split(":")[3];
const lambdaClient = new Lambda({ region });
const lambdaClient = new Lambda({
region,
});
// Parse the JSON to ensure it's validity (and avoid ugly errors at runtime)
const config = JSON.parse(stringifiedConfig);
// Fetch and extract Lambda zip contents to temporary folder, add configuration.json, and rezip
const { Code } = await lambdaClient
.getFunction({
FunctionName: lambdaFunction,
})
.promise();
});
const data = await fetch(Code!.Location!);
const lambdaZip = new Zip(data);
console.log(
Expand All @@ -61,8 +62,7 @@ async function updateLambdaCode(
FunctionName: lambdaFunction,
ZipFile: newLambdaZip.toBuffer(),
Publish: true,
})
.promise();
});
console.log({ CodeSha256, Version, FunctionArn });
return {
physicalResourceId: lambdaFunction,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,26 @@ import {
CloudFormationCustomResourceDeleteEvent,
CloudFormationCustomResourceUpdateEvent,
} from "aws-lambda";
import CloudFormation from "aws-sdk/clients/cloudformation";
import S3 from "aws-sdk/clients/s3";
import Lambda from "aws-sdk/clients/lambda";
import {
CloudFormation,
Stack,
waitUntilChangeSetCreateComplete,
waitUntilStackCreateComplete,
waitUntilStackUpdateComplete,
} from "@aws-sdk/client-cloudformation";
import { Lambda } from "@aws-sdk/client-lambda";
import { S3 } from "@aws-sdk/client-s3";
import { sendCfnResponse, Status } from "./cfn-response";
import { fetch } from "./https";

const CFN_CLIENT = new CloudFormation();
const CFN_CLIENT_US_EAST_1 = new CloudFormation({ region: "us-east-1" });
const CFN_CLIENT_US_EAST_1 = new CloudFormation({
region: "us-east-1",
});
const LAMBDA_CLIENT = new Lambda();
const S3_CLIENT_US_EAST_1 = new S3({ region: "us-east-1" });
const S3_CLIENT_US_EAST_1 = new S3({
region: "us-east-1",
});

interface CfnTemplateBase {
Resources: {
Expand Down Expand Up @@ -122,13 +132,12 @@ async function ensureUsEast1LambdaStack(props: {
const { Stacks: stacks } = await CFN_CLIENT_US_EAST_1.describeStacks({
StackName: props.stackName,
})
.promise()
.catch(() => ({ Stacks: undefined }));
if (stacks?.length) {
console.log("Deleting us-east-1 stack ...");
await CFN_CLIENT_US_EAST_1.deleteStack({
StackName: props.stackName,
}).promise();
});
console.log("us-east-1 stack deleted");
} else {
console.log("us-east-1 stack already deleted");
Expand All @@ -146,7 +155,7 @@ async function ensureUsEast1LambdaStack(props: {
const { TemplateBody: originalTemplate } = await CFN_CLIENT.getTemplate({
StackName: props.stackId,
TemplateStage: "Processed",
}).promise();
});
if (!originalTemplate)
throw new Error(
`Failed to get template for stack ${props.stackName} (${props.stackId})`
Expand Down Expand Up @@ -227,18 +236,20 @@ async function ensureLambdaUsEast1Stack(props: {
TemplateBody: props.newTemplate,
ChangeSetType: "UPDATE",
ResourceTypes: ["AWS::Lambda::Function"],
}).promise();
});
if (!changeSetArn)
throw new Error(
"Failed to create change set for lambda handlers deployment"
);
console.log(
"Waiting for completion of change set for adding lambda functions to us-east-1 stack ..."
);
await CFN_CLIENT_US_EAST_1.waitFor("changeSetCreateComplete", {
await waitUntilChangeSetCreateComplete({
client: CFN_CLIENT_US_EAST_1,
maxWaitTime: 200,
}, {
ChangeSetName: changeSetArn,
})
.promise()
.catch((err) =>
console.log(
`Caught exception while waiting for change set create completion: ${err}`
Expand All @@ -247,7 +258,7 @@ async function ensureLambdaUsEast1Stack(props: {
const { Status: status, StatusReason: reason } =
await CFN_CLIENT_US_EAST_1.describeChangeSet({
ChangeSetName: changeSetArn,
}).promise();
});
if (status === "FAILED") {
// The only reason we'll allow a FAILED change set is if there were no changes
if (!reason?.includes("didn't contain changes")) {
Expand All @@ -256,13 +267,13 @@ async function ensureLambdaUsEast1Stack(props: {
// No changes to make to the Lambda@Edge functions, clean up the change set then
await CFN_CLIENT_US_EAST_1.deleteChangeSet({
ChangeSetName: changeSetArn,
}).promise();
});

// Need to get the outputs (Lambda ARNs) from the existing stack then
const { Stacks: existingStacks } =
await CFN_CLIENT_US_EAST_1.describeStacks({
StackName: props.stackName,
}).promise();
});
const existingOutputs = extractOutputsFromStackResponse(existingStacks);
console.log(
`us-east-1 stack unchanged. Stack outputs: ${JSON.stringify(
Expand All @@ -281,16 +292,20 @@ async function ensureLambdaUsEast1Stack(props: {
);
await CFN_CLIENT_US_EAST_1.executeChangeSet({
ChangeSetName: changeSetArn,
}).promise();
});
console.log(
"Waiting for completion of execute change set for adding lambda functions to us-east-1 stack ..."
);
const { Stacks: updatedStacks } = await CFN_CLIENT_US_EAST_1.waitFor(
"stackUpdateComplete",
{
await waitUntilStackUpdateComplete({
client: CFN_CLIENT_US_EAST_1,
maxWaitTime: 200,
}, {
StackName: props.stackName,
});
const { Stacks: updatedStacks } =
await CFN_CLIENT_US_EAST_1.describeStacks({
StackName: props.stackName,
}
).promise();
});
const outputs = extractOutputsFromStackResponse(updatedStacks);
console.log(
`us-east-1 stack succesfully updated. Stack outputs: ${JSON.stringify(
Expand All @@ -302,7 +317,7 @@ async function ensureLambdaUsEast1Stack(props: {
return outputs as { [key: string]: string };
}

function extractOutputsFromStackResponse(stacks?: CloudFormation.Stack[]) {
function extractOutputsFromStackResponse(stacks?: Stack[]) {
// find the ARNs for all Lambda functions, which will be output from this custom resource

const outputs = LAMBDA_NAMES.reduce((acc, lambdaName) => {
Expand All @@ -329,7 +344,6 @@ async function ensureDeploymentUsEast1Stack(props: {
const { Stacks: usEast1Stacks } = await CFN_CLIENT_US_EAST_1.describeStacks({
StackName: props.stackName,
})
.promise()
.catch(() => ({ Stacks: undefined }));
if (usEast1Stacks?.length) {
const deploymentBucket = usEast1Stacks[0].Outputs?.find(
Expand All @@ -347,7 +361,7 @@ async function ensureDeploymentUsEast1Stack(props: {
console.log("Getting CFN stack tags ...");
const { Stacks: mainRegionStacks } = await CFN_CLIENT.describeStacks({
StackName: props.stackId,
}).promise();
});
if (!mainRegionStacks?.length) {
throw new Error(
`Failed to describe stack ${props.stackName} (${props.stackId})`
Expand All @@ -363,24 +377,31 @@ async function ensureDeploymentUsEast1Stack(props: {
ChangeSetType: "CREATE",
ResourceTypes: ["AWS::S3::Bucket"],
Tags: mainRegionStacks[0].Tags,
}).promise();
});
if (!changeSetArn)
throw new Error("Failed to create change set for bucket deployment");
console.log("Waiting for change set create complete for us-east-1 stack ...");
await CFN_CLIENT_US_EAST_1.waitFor("changeSetCreateComplete", {
await waitUntilChangeSetCreateComplete({
client: CFN_CLIENT_US_EAST_1,
maxWaitTime: 200,
}, {
ChangeSetName: changeSetArn,
}).promise();
});
console.log("Executing change set for us-east-1 stack ...");
await CFN_CLIENT_US_EAST_1.executeChangeSet({
ChangeSetName: changeSetArn,
}).promise();
});
console.log("Waiting for creation of us-east-1 stack ...");
const { Stacks: createdStacks } = await CFN_CLIENT_US_EAST_1.waitFor(
"stackCreateComplete",
{
await waitUntilStackCreateComplete({
client: CFN_CLIENT_US_EAST_1,
maxWaitTime: 200,
}, {
StackName: props.stackName,
});
const { Stacks: createdStacks } =
await CFN_CLIENT_US_EAST_1.describeStacks({
StackName: props.stackName,
}
).promise();
});
const deploymentBucket = createdStacks?.[0].Outputs?.find(
(output) => output.OutputKey === "DeploymentBucket"
)?.OutputValue;
Expand All @@ -397,7 +418,7 @@ async function copyLambdaCodeToUsEast1(props: {
console.log(`Copying Lambda code: ${JSON.stringify(props, null, 2)}`);
const { Code } = await LAMBDA_CLIENT.getFunction({
FunctionName: props.lambdaArn,
}).promise();
});
console.log(
`Downloading lambda code for ${props.lambdaArn} from ${Code!.Location!}`
);
Expand All @@ -406,7 +427,7 @@ async function copyLambdaCodeToUsEast1(props: {
Bucket: props.toBucket,
Key: props.key,
Body: data,
}).promise();
});
return props;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import {
CloudFormationCustomResourceHandler,
CloudFormationCustomResourceUpdateEvent,
} from "aws-lambda";
import CognitoIdentityServiceProvider from "aws-sdk/clients/cognitoidentityserviceprovider";
import {
CognitoIdentityProvider,
UpdateUserPoolClientCommandInput,
UserPoolClientType,
} from "@aws-sdk/client-cognito-identity-provider";
import { sendCfnResponse, Status } from "./cfn-response";

const CUSTOM_RESOURCE_CURRENT_VERSION_NAME = "UpdatedUserPoolClientV2";
Expand All @@ -22,7 +26,7 @@ const SENTINEL_DOMAIN = "example.com";
async function getUserPoolClient(props: Props) {
const userPoolId = props.UserPoolArn.split("/")[1];
const userPoolRegion = props.UserPoolArn.split(":")[3];
const cognitoClient = new CognitoIdentityServiceProvider({
const cognitoClient = new CognitoIdentityProvider({
region: userPoolRegion,
});
const input = {
Expand All @@ -31,8 +35,7 @@ async function getUserPoolClient(props: Props) {
};
console.debug("Describing User Pool Client", JSON.stringify(input, null, 4));
const { UserPoolClient } = await cognitoClient
.describeUserPoolClient(input)
.promise();
.describeUserPoolClient(input);
if (!UserPoolClient) {
throw new Error("User Pool Client not found!");
}
Expand All @@ -43,11 +46,11 @@ async function updateUserPoolClient(
props: Props,
redirectUrisSignIn: string[],
redirectUrisSignOut: string[],
existingUserPoolClient: CognitoIdentityServiceProvider.UserPoolClientType
existingUserPoolClient: UserPoolClientType
) {
const userPoolId = props.UserPoolArn.split("/")[1];
const userPoolRegion = props.UserPoolArn.split(":")[3];
const cognitoClient = new CognitoIdentityServiceProvider({
const cognitoClient = new CognitoIdentityProvider({
region: userPoolRegion,
});

Expand All @@ -60,7 +63,7 @@ async function updateUserPoolClient(

// To be able to set the redirect URL's, we must enable OAuth––required by Cognito
// Vice versa, when removing redirect URL's, we must disable OAuth if there's no more redirect URL's left
let AllowedOAuthFlows: string[];
let AllowedOAuthFlows: ("code"|"client_credentials"|"implicit")[];
let AllowedOAuthFlowsUserPoolClient: boolean;
let AllowedOAuthScopes: string[];
if (CallbackURLs.length) {
Expand All @@ -81,7 +84,7 @@ async function updateUserPoolClient(
delete existingFields.LastModifiedDate;
delete existingFields.ClientSecret;

const input: CognitoIdentityServiceProvider.Types.UpdateUserPoolClientRequest =
const input: UpdateUserPoolClientCommandInput =
{
...existingFields,
AllowedOAuthFlows,
Expand All @@ -93,7 +96,7 @@ async function updateUserPoolClient(
LogoutURLs,
};
console.debug("Updating User Pool Client", JSON.stringify(input, null, 4));
await cognitoClient.updateUserPoolClient(input).promise();
await cognitoClient.updateUserPoolClient(input);
}

async function undoPriorUpdate(
Expand Down
Loading