Skip to content

Commit

Permalink
feat(cdk): add amplify, monitoring, signing methods
Browse files Browse the repository at this point in the history
  • Loading branch information
shellscape committed Jan 7, 2025
1 parent b3ef63e commit 550aa9a
Show file tree
Hide file tree
Showing 7 changed files with 1,065 additions and 819 deletions.
18 changes: 11 additions & 7 deletions packages/cdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,26 @@
"ts-node": "^10.9.1"
},
"dependencies": {
"@aws-cdk/aws-amplify-alpha": "2.174.1-alpha.0",
"@aws-cdk/aws-apigatewayv2-alpha": "2.114.1-alpha.0",
"@aws-cdk/aws-apigatewayv2-integrations-alpha": "2.114.1-alpha.0",
"@aws-cdk/aws-kinesisfirehose-alpha": "2.131.0-alpha.0",
"@aws-cdk/aws-kinesisfirehose-destinations-alpha": "2.131.0-alpha.0",
"@aws-cdk/cloud-assembly-schema": "^2.131.0",
"@aws-cdk/cx-api": "^2.131.0",
"@aws-sdk/client-secrets-manager": "^3.675.0",
"@aws-sdk/client-sns": "^3.675.0",
"@aws-sdk/client-ssm": "^3.675.0",
"@aws-cdk/aws-kinesisfirehose-alpha": "2.174.1-alpha.0",
"@aws-cdk/aws-kinesisfirehose-destinations-alpha": "2.174.1-alpha.0",
"@aws-cdk/aws-redshift-alpha": "2.174.1-alpha.0",
"@aws-cdk/cloud-assembly-schema": "^39.1.38",
"@aws-cdk/cx-api": "^2.174.1",
"@aws-sdk/client-secrets-manager": "^3.723.0",
"@aws-sdk/client-sns": "^3.723.0",
"@aws-sdk/client-ssm": "^3.723.0",
"@aws-solutions-constructs/aws-cloudfront-s3": "^2.76.0",
"@dot/env": "workspace:*",
"@dot/log": "workspace:^",
"@smithy/types": "^2.3.1",
"@swc-node/register": "^1.6.7",
"@swc/core": "^1.3.84",
"aws-cdk-lib": "^2.162.1",
"camelcase": "^6.3.0",
"cdk-monitoring-constructs": "^9.1.3",
"chalk": "^4.1.2",
"constructs": "^10.3.0",
"nanoid": "3.3.4",
Expand Down
2 changes: 2 additions & 0 deletions packages/cdk/src/constructs/Stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export class DotStack extends Stack {
public readonly appName: string;
public readonly env: DeployEnvironment;
public readonly envPrefix: string;
public readonly isProd: boolean;
public readonly ssmPrefix: string;

constructor(scope: App, props: DotStackProps) {
Expand All @@ -41,6 +42,7 @@ export class DotStack extends Stack {
this.appName = envPrefix + (props.appName || props.name);
this.env = env;
this.envPrefix = envPrefix;
this.isProd = env === 'prod';
this.node.setContext('appName', this.appName);
this.node.setContext('env', this.env);
this.ssmPrefix = `/${env}/${props.appName || props.name}`;
Expand Down
52 changes: 52 additions & 0 deletions packages/cdk/src/methods/amplify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import * as Amplify from '@aws-cdk/aws-amplify-alpha';
import { RemovalPolicy } from 'aws-cdk-lib';
import { Asset } from 'aws-cdk-lib/aws-s3-assets';

import { DotStack } from '../constructs/Stack';

interface AddAmplifyAppOptions {
distPath: string;
domainName?: string;
environmentVariables?: { [key: string]: string };
name: string;
pwaRedirect?: boolean;
scope: DotStack;
subdomain?: string;
}

interface AddAmplifyAppResult {
app: Amplify.App;
}

export const addAmplifyApp = (options: AddAmplifyAppOptions): AddAmplifyAppResult => {
const { distPath, domainName, environmentVariables = {}, name, pwaRedirect, scope } = options;
const subdomain = options.subdomain ?? scope.env;
const baseName = DotStack.baseName(name, '-app');
const appName = scope.resourceName(baseName);

const asset = new Asset(scope, `${appName}-asset`, { path: distPath });
const app = new Amplify.App(scope, appName, {
appName
});
const branch = app.addBranch(scope.env, { asset, environmentVariables });

app.applyRemovalPolicy(RemovalPolicy.DESTROY);

// Note: needed for PWA routing
if (pwaRedirect) {
app.addCustomRule({
source: '/<*>',
status: Amplify.RedirectStatus.NOT_FOUND_REWRITE,
target: '/index.html'
});
}

if (domainName) {
const domain = app.addDomain(domainName, {
enableAutoSubdomain: false
});
domain.mapSubDomain(branch, subdomain);
}

return { app };
};
3 changes: 3 additions & 0 deletions packages/cdk/src/methods/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './api';
export * from './amplify';
export * from './app';
export * from './backup';
export * from './cloudfront';
Expand All @@ -8,12 +9,14 @@ export * from './fargate';
export * from './function';
export * from './kinesis';
export * from './layer';
export * from './monitoring';
export * from './node-function';
export * from './output';
export * from './policy';
export * from './queue';
export * from './s3';
export * from './secret';
export * from './signing';
export * from './sns';
export * from './ssm';
export * from './stack';
Expand Down
48 changes: 48 additions & 0 deletions packages/cdk/src/methods/monitoring.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { ApplicationLoadBalancedFargateService } from 'aws-cdk-lib/aws-ecs-patterns';
import { MonitoringFacade, SnsAlarmActionStrategy } from 'cdk-monitoring-constructs';

import type { DotStack } from '../constructs/Stack';

import { addTopic } from './sns';

interface AddMonitoringOptions {
emailAddress: string;
fargateService: ApplicationLoadBalancedFargateService;
scope: DotStack;
}

export const addFargateMonitoring = (options: AddMonitoringOptions) => {
const { emailAddress, fargateService, scope } = options;

const { topic: onAlarmTopic } = addTopic({ emailAddress, name: 'alarm', scope });

const monitoring = new MonitoringFacade(scope, scope.resourceName('monitor'), {
alarmFactoryDefaults: {
action: new SnsAlarmActionStrategy({ onAlarmTopic }),
actionsEnabled: true,
alarmNamePrefix: scope.resourceName('alarm')
}
});

monitoring.monitorFargateService({
addCpuUsageAlarm: {
Warning: {
maxUsagePercent: 80
}
},
addHealthyTaskPercentAlarm: {
Warning: {
minHealthyTaskPercent: 75
}
},
addMemoryUsageAlarm: {
Warning: {
maxUsagePercent: 80
}
},
addToAlarmDashboard: true,
addToDetailDashboard: true,
addToSummaryDashboard: true,
fargateService
});
};
53 changes: 53 additions & 0 deletions packages/cdk/src/methods/signing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { generateKeyPairSync } from 'crypto';

import { PublicKey } from 'aws-cdk-lib/aws-cloudfront';

import { type DotStack } from '../constructs/Stack';

import { addSecret } from './secret';
import { addParam } from './ssm';

const generateRsaKeyPair = () => {
const { privateKey, publicKey } = generateKeyPairSync('rsa', {
modulusLength: 2048,
privateKeyEncoding: {
format: 'pem',
type: 'pkcs8'
},
publicKeyEncoding: {
format: 'pem',
type: 'spki'
}
});
return { privateKey, publicKey };
};

export const addSigningKey = (scope: DotStack) => {
// FIXME: We have to not run this for additional deploys to prod
// because for some reason it fails if the public key exists already
// https://github.com/aws/aws-cdk/issues/15301
const keyPair = generateRsaKeyPair();

addSecret({
name: `${scope.env}-signing-key-pair`,
scope,
secretName: `${scope.ssmPrefix}/key/signing`,
value: JSON.stringify(keyPair)
});

const baseName = 'signing-pubkey';
const publicKeyName = scope.resourceName(baseName);
const cfKey = new PublicKey(scope, publicKeyName, {
encodedKey: keyPair.publicKey,
publicKeyName
});

scope.overrideId(cfKey, publicKeyName);

addParam({
id: `${publicKeyName}-id`,
name: `${scope.ssmPrefix}/id/${baseName}`,
scope,
value: cfKey.publicKeyId
});
};
Loading

0 comments on commit 550aa9a

Please sign in to comment.