Skip to content
Closed
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
4 changes: 4 additions & 0 deletions .github/workflows/build.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .github/workflows/release.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions .github/workflows/upgrade-main.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 46 additions & 1 deletion .projen/deps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions .projen/tasks.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion .projenrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,31 @@ const project = new typescript.TypeScriptProject({
deps: [
"@aws-sdk/client-cloudcontrol",
"@aws-sdk/client-ssm",
"@aws-sdk/client-eventbridge",
"@aws-sdk/client-iam",
"@aws-sdk/client-sts",
"@aws-sdk/client-sqs",
"@aws-sdk/client-secrets-manager",
"@aws-sdk/client-lambda",
"chalk@4",
"short-uuid",
"commander",
"fast-json-patch",
"immutable",
"cdk-assets",
"aws-sdk",
],
devDeps: ["@types/immutable", "ts-node"],
devDeps: ["@types/immutable", "ts-node", "@types/node"],
eslintOptions: {
prettier: true,
},
releaseToNpm: true,
docgen: true,
minNodeVersion: "16.0.0",
gitignore: [".DS_Store"],
tsconfig: {
compilerOptions: { target: "es2020", lib: ["es2020"] },
},
});

project.synth();
9 changes: 7 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.quickSuggestions": true,
"editor.quickSuggestions": {
"comments": "on",
"strings": "on",
"other": "on"
},
"editor.suggest.showReferences": true,
"editor.wordWrap": "on"
},
Expand All @@ -29,5 +33,6 @@
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.formatOnSave": true,
"eslint.format.enable": false
"eslint.format.enable": false,
"typescript.tsdk": "node_modules/typescript/lib"
}
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# node-cfn

This is a toy-implementation of the AWS CloudFormation deployment engine in TypeScript and Node-JS. It was built as an experiment to better underestand why CloudFormation is so slow and to also experiment locally with new features.
This is a toy-implementation of the AWS CloudFormation deployment engine in TypeScript and Node-JS. It was built as an experiment to better understand why CloudFormation is so slow and to also experiment locally with new features.

It is built on top of the [AWS Cloud Control API](https://aws.amazon.com/cloudcontrolapi/) and thus only supports the [resources that are supported by the Cloud Control API](https://docs.aws.amazon.com/cloudcontrolapi/latest/userguide/supported-resources.html).

The most important missing feature right now is Rollbacks, so this tool should not be considered useful for any type of production service. The hope is that it can become a playground for CloudFormation enhancements and to stand as a performance benchmark for the official AWS CloudFormation sevice. I dream of the day when CloudFormation is as fast as Terraform and Pulumi's provisioning engines.
The most important missing feature right now is Rollbacks, so this tool should not be considered useful for any type of production service. The hope is that it can become a playground for CloudFormation enhancements and to stand as a performance benchmark for the official AWS CloudFormation service. I dream of the day when CloudFormation is as fast as Terraform and Pulumi's provisioning engines.

## Supported Features

Expand All @@ -14,6 +14,7 @@ The most important missing feature right now is Rollbacks, so this tool should n
- [x] Intrinsic Functions (`Ref`, `!Ref`, `Fn::GetAtt`, `Fn::Join`, `Fn::Split`, `Fn::Select`, `Fn::FindInMap`, `Fn::Sub`, etc.)
- [ ] Rollbacks on failure
- [ ] Outputs and cross-stack references
- [ ] Assets

## Usage

Expand Down
3 changes: 3 additions & 0 deletions bin/node-cfn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/usr/bin/env node

require("../lib/cli");
5 changes: 3 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ <h1>node-cfn</h1>
<a href="#node-cfn" id="node-cfn" style="color: inherit; text-decoration: none;">
<h1>node-cfn</h1>
</a>
<p>This is a toy-implementation of the AWS CloudFormation deployment engine in TypeScript and Node-JS. It was built as an experiment to better underestand why CloudFormation is so slow and to also experiment locally with new features.</p>
<p>This is a toy-implementation of the AWS CloudFormation deployment engine in TypeScript and Node-JS. It was built as an experiment to better understand why CloudFormation is so slow and to also experiment locally with new features.</p>
<p>It is built on top of the <a href="https://aws.amazon.com/cloudcontrolapi/">AWS Cloud Control API</a> and thus only supports the <a href="https://docs.aws.amazon.com/cloudcontrolapi/latest/userguide/supported-resources.html">resources that are supported by the Cloud Control API</a>.</p>
<p>The most important missing feature right now is Rollbacks, so this tool should not be considered useful for any type of production service. The hope is that it can become a playground for CloudFormation enhancements and to stand as a performance benchmark for the official AWS CloudFormation sevice. I dream of the day when CloudFormation is as fast as Terraform and Pulumi&#39;s provisioning engines.</p>
<p>The most important missing feature right now is Rollbacks, so this tool should not be considered useful for any type of production service. The hope is that it can become a playground for CloudFormation enhancements and to stand as a performance benchmark for the official AWS CloudFormation service. I dream of the day when CloudFormation is as fast as Terraform and Pulumi&#39;s provisioning engines.</p>
<a href="#supported-features" id="supported-features" style="color: inherit; text-decoration: none;">
<h2>Supported Features</h2>
</a>
Expand All @@ -74,6 +74,7 @@ <h2>Supported Features</h2>
<li><input checked="" disabled="" type="checkbox"> Intrinsic Functions (<code>Ref</code>, <code>!Ref</code>, <code>Fn::GetAtt</code>, <code>Fn::Join</code>, <code>Fn::Split</code>, <code>Fn::Select</code>, <code>Fn::FindInMap</code>, <code>Fn::Sub</code>, etc.)</li>
<li><input disabled="" type="checkbox"> Rollbacks on failure</li>
<li><input disabled="" type="checkbox"> Outputs and cross-stack references</li>
<li><input disabled="" type="checkbox"> Assets</li>
</ul>
<a href="#usage" id="usage" style="color: inherit; text-decoration: none;">
<h2>Usage</h2>
Expand Down
21 changes: 18 additions & 3 deletions package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

109 changes: 109 additions & 0 deletions src/aws.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { Account, ClientOptions, IAws } from "cdk-assets";
import s3_v2 from "aws-sdk/clients/s3";
import secrets_manager_v2 from "aws-sdk/clients/secretsmanager";
import ecr_v2 from "aws-sdk/clients/ecr";
import sts from "@aws-sdk/client-sts";
import * as os from "os";
import { ChainableTemporaryCredentials, Credentials } from "aws-sdk";

export default class AwsClient implements IAws {
constructor(
private account: string,
private region: string,
private sdkConfig?: any
) {}

async discoverPartition(): Promise<string> {
return "aws";
}
async discoverDefaultRegion(): Promise<string> {
return this.region;
}
async discoverCurrentAccount(): Promise<Account> {
return {
accountId: this.account,
partition: await this.discoverPartition(),
};
}
async discoverTargetAccount(options: ClientOptions): Promise<Account> {
const stsClient = await this.stsClient(await this.awsOptions(options));
const response = await stsClient.send(new sts.GetCallerIdentityCommand({}));
if (!response.Account || !response.Arn) {
throw new Error(
`Unrecognized response from STS: '${JSON.stringify(response)}'`
);
}
return {
accountId: response.Account!,
partition: response.Arn!.split(":")[1],
};
}
async s3Client(options: ClientOptions): Promise<s3_v2> {
return new s3_v2(options);
}
async stsClient(options: ClientOptions): Promise<sts.STSClient> {
return new sts.STSClient(options);
}
async ecrClient(options: ClientOptions): Promise<ecr_v2> {
return new ecr_v2(options);
}
async secretsManagerClient(
options: ClientOptions
): Promise<secrets_manager_v2> {
return new secrets_manager_v2(await this.awsOptions(options));
}
async awsOptions(options: ClientOptions) {
let credentials;
if (options.assumeRoleArn) {
credentials = await this.assumeRole(
options.region,
options.assumeRoleArn,
options.assumeRoleExternalId
);
}
return {
...this.sdkConfig,
region: options.region,
customUserAgent: "node-cfn",
credentials,
};
}
/**
* Explicit manual AssumeRole call
*
* Necessary since I can't seem to get the built-in support for ChainableTemporaryCredentials to work.
*
* It needs an explicit configuration of `masterCredentials`, we need to put
* a `DefaultCredentialProverChain()` in there but that is not possible.
*/
async assumeRole(
region: string | undefined,
roleArn: string,
externalId?: string
): Promise<Credentials> {
return new ChainableTemporaryCredentials({
params: {
RoleArn: roleArn,
ExternalId: externalId,
RoleSessionName: `node-cfn-${safeUsername()}`,
},
stsConfig: {
region,
customUserAgent: "node-cfn",
},
});
}
}

/**
* Return the username with characters invalid for a RoleSessionName removed
*
* @see https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html#API_AssumeRole_RequestParameters
*/
function safeUsername() {
try {
return os.userInfo().username.replace(/[^\w+=,.@-]/g, "@");
} catch (e) {
return "noname";
}
}
Loading