Skip to content
/ cdk-template Public template

This is a template for CDK related projects.

License

Notifications You must be signed in to change notification settings

bmacher/cdk-template

Repository files navigation

Node CI GitHub release GitHub license Dependabot Enabled

CDK Template

Implementation Guidelines

  • Naming conventions:
    • Functions = camelCase
    • Classes = PascalCase
    • Interfaces/Types = PascalCase
    • Constants = UPPER_CASE_SNAKE_CASE
    • File names like what the export (e.g. class FooBarFoobar.ts)
    • AWS Stacks, Resources, IDs = PascalCase
  • Avoid concrete resource names as long as possible to prevent names clashes
  • Use resource-names.ts to define name of resources
  • Use destructoring imports over * as foobar to get proper intellisense
  • Name the file of a stack with suffix -stack.ts but omit suffixes on constructs
  • Use git commit message convention
  • ...

Sharing resources between stacks

Resources shared across stacks should be exchanged either directly or if not possible with SSM Parameter or concrete names. There are pseudo code snippets under Resolve dependencies to how it could be implemented. Concrete names should be used in case of cross account deployments (e.g. granting some permissions to a role). Directly resolved dependencies can be traced directly in the code but those with SSM Parameter or concrete names not, however you could express those with filling the table under Dependencies between stacks. I would recommend to use a single place for parameter and resource names and import them from there (e.g. lib/shared/resource-names.ts)

Anyways, be sure to follow this order when exchanging resources between stacks.

  1. Directly
  2. SSM Parameter
  3. Concrete names (can lead to name clashes)

Dependencies between stacks

Between What? Resolved with
StackA → StackB some resource SSM Parameter
StackA (Account1) → StackC (Account2) some resource Concrete name

Resolve dependencies

Directly

class StackA {
  puplic readonly resource: Resource;

  constructor() {
    this.resource = new Resource();
  }
}

interface StackBProps {
  resource: Resource,
}

class StackB {
  constructor(props: StackBProps) {
    // Do something with props.resouce from StackA
  }
}

const stack = new StackA();
new StackB({ resouce: stack.resource })

SSM Parameter

import ssmParamNames from 'shared';

class StackA {
  constructor() {
    const resource = new Resource();

    new StringParameter({
      parameterName: ssmParamNames.PARAM_NAME,
      strinValue: resource.Arn,
    });
  }
}

class StackB {
  constructor() {
    const bucket = new Bucket();
    const resourceArn = StringParameter.fromStringParameterName(ssmParamNames.PARAM_NAME);

    bucket.grantRead(Resource.fromArn(resourceArn.stringValue));
  }
}

Concrete name

import roleNames from 'shared';

class StackA {
  constructor() {
    new Role({
      roleName: roleNames.ROLE_XYZ,
    });
  }
}

class StackB {
  constructor() {
    const bucket = new Bucket();
    // Could also use new ArnPrincipal()
    const role = Role.fromRoleArn(`arn:aws:iam::${this.account}:role/${roleNames.ROLE_XYZ}`)

    bucket.grantRead(role);
  }
}