@inizioevoke/evosynth
v2.3.3
Published
EvoSynth is an npm package providing reusable AWS CDK stacks for deploying static serverless websites. It targets S3 + CloudFront + Route53 + ACM + WAF + CodePipeline architectures.
Downloads
590
Keywords
Readme
@inizioevoke/evosynth
EvoSynth is an npm package providing reusable AWS CDK stacks for deploying static serverless websites. It targets S3 + CloudFront + Route53 + ACM + WAF + CodePipeline architectures.
Prerequisites
- Node version 22+
- AWS Account ID, a configured profile, or other credentials
- CodeConnection ARN or SSM Parameter Store path of a shared connection ARN
- A WAF web ACL ARN or SSM Parameter Store path of a shared ACL ARN
- The Bitbucket or GitHub repository
Project configuration
- Copy the buildspec.yml on your Bitbucket Repo and the build configuration
- Update/Configure the Stack example below
CLI - evosynth (preferred)
This library includes a cli tool evosynth to support a more streamlined configuration approach than the version 1 process, although the version 1 process is still supported.
Instructions
In your project:
Install the library
> npm install @inizioevoke/evosynthCreate the config file in your project root directory.
[ENV]should be your environment name (e.g..evosynth.dev.ts).evosynth.[ENV].(js|mjs|ts|mts)It is also possible to use 1 config file for multiple environments. Named exports should match your environment names.
.evosynth.(js|mjs|ts|mts)Compile your config. Add standard AWS flags like
--profileif necessary.> npx evosynth synth [ENV]> npx evosynth synth [ENV] --profile my-profileDeploy
> npx evosynth deploy [ENV]Destroy
> npx evosynth destroy [ENV]
Example config file - single environment
// .evosynth.dev.ts
import type { WebStaticServerlessAppConfig } from '@inizioevoke/evosynth';
export default async function(): Promise<WebStaticServerlessAppConfig> {
return {
type: 'web-static-serverless',
envType: 'dev',
name: 'my-project',
description: 'My Project',
region: 'us-east-1',
tags: {
Account: 'Account Name',
Brand: 'Brand Name'
},
dns: {
record: 'my-project.dev.client',
zone: 'evodev.net'
},
security: {
basicAuthParam: '/evosynth/web/security/basicauth',
webAclParam: '/evosynth/web/security/webacl'
},
pipeline: {
source: {
codestarConnectionParam: '/evosynth/bitbucket/codeconnection',
owner: 'evokegroup',
repo: 'my-project',
branch: 'develop'
}
}
}
}Example config file - multiple environments
// .evosynth.ts
import { mergeConfigs, type WebStaticServerlessAppConfig, type DeepPartial } from '@inizioevoke/evosynth';
const config: DeepPartial<WebStaticServerlessAppConfig> = {
type: 'web-static-serverless',
name: 'my-project',
description: 'My Project',
region: 'us-east-1',
tags: {
Account: 'Account Name',
Brand: 'Brand Name'
},
dns: {
zone: 'evodev.net'
},
security: {
basicAuthParam: '/evosynth/web/security/basicauth',
webAclParam: '/evosynth/web/security/webacl'
},
pipeline: {
source: {
codestarConnectionParam: '/evosynth/bitbucket/codeconnection',
owner: 'evokegroup',
repo: 'my-project'
}
}
};
// dev environment
export async function dev(): Promise<WebStaticServerlessAppConfig> {
return mergeConfigs<WebStaticServerlessAppConfig>(config, {
envType: 'dev',
dns: {
record: 'my-project.dev.client'
},
pipeline: {
source: {
branch: 'develop'
}
}
});
}
// uat environment
export async function uat(): Promise<WebStaticServerlessAppConfig> {
return mergeConfigs<WebStaticServerlessAppConfig>(config, {
envType: 'uat',
dns: {
record: 'my-project.uat.client'
},
pipeline: {
source: {
branch: 'uat'
}
}
});
}Content Security Policy Headers
You can configure Content Security Policy (CSP) headers through the cloudfront.cspHeaders option. CSP headers can be defined as either an object or a string format.
Inline CSP Headers (Object Format)
Define CSP directives as an object where each key is a directive and values are arrays of policies:
cloudfront: {
cspHeaders: {
'default-src': ["'self'"],
'script-src': ["'self'", "'unsafe-inline'", 'https://trusted.com'],
'style-src': ["'self'", "'unsafe-inline'"],
'img-src': ["'self'", 'data:', 'https:']
}
}Inline CSP Headers (String Format)
Alternatively, define CSP as a single string:
cloudfront: {
cspHeaders: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';"
}Import from TypeScript/JavaScript File
Create a separate file with your CSP configuration and import it:
// csp.ts
export default {
"default-src": ["'self'"],
"script-src": ["'self'", "*.trusted.com"]
};
// or grouped by source similar to CSV format
export default {
"'self'": ["default-src","script-src"],
"*.trusted.com": ["script-src"]
}
// .evosynth.dev.ts
import cspHeaders from './csp';
export default async function(): Promise<WebStaticServerlessAppConfig> {
return {
// ... other config
cloudfront: {
cspHeaders
}
}
}Import from CSV File
You can also load CSP headers from a CSV file. See samples/csp.csv for the expected format:
// .evosynth.dev.ts
import { readFile } from 'node:fs/promises';
import { join } from 'node:path';
export default async function(): Promise<WebStaticServerlessAppConfig> {
const cspHeaders = await readFile(
join(import.meta.dirname, 'csp.csv'),
'utf8'
);
return {
// ... other config
cloudfront: {
cspHeaders
}
}
}CDK App
Use evosynth in a traditional CDK app script by instantiating a stage or stack. Use individual constructs for custom apps.
Requires CDK v2.238.x installed locally
Example App
import * as cdk from 'aws-cdk-lib/core';
import { CloudFrontFunctionRedirects } from '@inizioevoke/evosynth/constructs/cloudfront';
import { WebStaticServerlessStage } from '@inizioevoke/evosynth/stages/web-static-serverless-stage';
import { AddSourceStageParams } from '@inizioevoke/evosynth/constructs/codepipeline';
const app = new cdk.App();
const env = getEnv('us-east-1');
// const env = getEnv('000000000000');
// const env = getEnv({ account: '000000000000', region: 'us-east-1' });
const tags: Record<string, string> = {
'Account': 'Account Name',
'Brand': 'Brand Name'
};
const repository: Omit<AddSourceStageParams, 'branch'> = {
codestarConnection: { path: '/evosynth/provider/codeconnection' },
// codestarConnection: 'ARN',
repoOwner: 'orgname',
repo: 'myproject-v1'
};
const redirects: CloudFrontFunctionRedirects = {
paths: {
'/hello': '/world',
'/redirect': ['/here', 302]
}
};
new WebStaticServerlessStage(app, 'dev', {
env,
stageName: 'myproject-v1-dev',
tags,
envType: 'NOT_PROD',
description: 'My Project DEV',
hostedZone: 'evodev.net',
domainName: 'myproject-v1.evodev.net',
basicAuth: { path: '/evosynth/web/security/basicauth' },
// basicAuth: {
// user: 'user',
// password: 'password'
// },
// basicAuth: 'dXNlcjpwYXNzd29yZA==',
webAcl: { path: '/evosynth/web/security/webacl' },
// webAcl: 'ARN',
// webAcl: true, // create new, but you probably should reuse one,
// Use a custom CloudFront Viewer Request/Response function
// viewerRequestResponse: 'function handler(event) { /* do something */ }',
redirects,
pipeline: {
sourceStage: {
...repository,
branch: 'develop'
},
// Grant read access to Parameter Store parameters
// codeBuildProject: {
// ssmParameters: [{
// path: '/my/parameter',
// encrypted: true
// }, {
// path: '/my/other/parameter'
// }]
// }
}
});
new WebStaticServerlessStage(app, 'uat', {
env,
stageName: 'myproject-v1-uat',
tags,
envType: 'NOT_PROD',
description: 'My Project UAT',
hostedZone: 'evostg.net',
domainName: 'myproject-v1.evostg.net',
basicAuth: { path: '/evosynth/web/security/basicauth' },
// basicAuth: {
// user: 'user',
// password: 'password'
// },
// basicAuth: 'dXNlcjpwYXNzd29yZA==',
webAcl: { path: '/evosynth/web/security/webacl' },
// webAcl: 'ARN',
// webAcl: true, // create new, but you probably should reuse one,
redirects,
pipeline: {
sourceStage: {
...repository,
branch: 'uat'
}
}
});
new WebStaticServerlessStage(app, 'prd', {
env,
stageName: 'myproject-v1-prd',
tags,
envType: 'PROD',
description: 'My Project PRD',
hostedZone: 'myproject.com',
domainName: 'www.myproject.com',
webAcl: { path: '/evosynth/web/security/webacl' },
// webAcl: 'ARN',
// webAcl: true, // create new, but you probably should reuse one
redirects,
pipeline: {
sourceStage: {
...repository,
branch: 'prod'
}
}
});Win
cdk deploy dev/*cdk deploy uat/*cdk deploy prd/*MacOS
cdk deploy "dev/*" cdk deploy "uat/*" cdk deploy "prd/*" 