DEV Community

Markus Loupeen for AWS Community Builders

Posted on

Managing multiple AWS Accounts and Environments with CDK.

This is just a small post that will be followed up later with pipeline examples.

We do not want our CDK applications to know much about how and where they are deployed, instead it is all defined in a small private npm package that contains all account information.

Here is how we have it, so we can import it in multiple projects and pipelines.

import { Annotations, Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export const DeploymentRegion = {
  EU_NORTH_1: 'eu-north-1',
  EU_CENTRAL_1: 'eu-central-1',
};

export const ApplicationStack = {
  DEV: 'dev',
  TEST: 'test',
  QA: 'qa',
  PRODUCTION: 'production',
};

type ApplicationStackType = (typeof ApplicationStack)[keyof typeof ApplicationStack];
type DeploymentRegionType = (typeof DeploymentRegion)[keyof typeof DeploymentRegion];

export class AwsAccount {
  private static accounts: AwsAccount[] = [];

  // -- Applications --
  // - Production -
  static readonly APP1_PRODUCTION = new AwsAccount('APP1_Production', '100000000001', ApplicationStack.PRODUCTION, [DeploymentRegion.EU_NORTH_1, DeploymentRegion.EU_CENTRAL_1], true);

  // - QA -
  static readonly APP1_QA = new AwsAccount('APP1_QA', '100000000002', ApplicationStack.QA, [DeploymentRegion.EU_NORTH_1, DeploymentRegion.EU_CENTRAL_1], true,);

  // - Test -
  static readonly APP1_TEST = new AwsAccount('APP1_Test', '100000000003', ApplicationStack.TEST);

  // - Dev -
  static readonly APP1_DEV = new AwsAccount('APP1_Dev', '100000000004', ApplicationStack.TEST);
  static readonly APP2_DEV = new AwsAccount('APP2_Dev', '200000000001', ApplicationStack.TEST);

  // -- Aws Core --
  static readonly AUDIT = new AwsAccount('Audit', '900000000010', ApplicationStack.PRODUCTION);
  static readonly LOG_ARCHIVE = new AwsAccount('Log archive', '900000000011', ApplicationStack.PRODUCTION);

  // -- Infrastructure --
  static readonly OPS = new AwsAccount('OPS', '000000000001', ApplicationStack.PRODUCTION);

  private constructor(
    public readonly name: string,
    public readonly accountId: string,
    public readonly stack: ApplicationStackType,
    public readonly deploymentRegions: DeploymentRegionType[] = [DeploymentRegion.EU_NORTH_1],
    public readonly approveBeforeDeploy: boolean = false,
  ) {
    AwsAccount.accounts.push(this);
  }

  static fromScope(scope?: Construct): AwsAccount | undefined {
    if (!scope) {
      return undefined;
    }
    const accountNumber = Stack.of(scope).account;
    const account = this.accounts.find((acc) => acc.accountId === accountNumber);
    if (account) return account;
    Annotations.of(scope).addError(`Couldn't find account [${account}] in AwsAccount array!`);
    return undefined;
  }
}
Enter fullscreen mode Exit fullscreen mode

In next post I will show you how we utilize this in pipelines to make life esier.

Top comments (0)