Deploying different CloudFormation stacks based on different AWS accounts with AWS CDK

#AWS  

#CDK  

#javascript  

#devops  

Thu Jan 16 2020

AWS CDK is a great tool to write AWS infrastructure as code in your favorite language. Apart from all the awesome features that CDK offers, one of the things that I personally like is that it helps us to make sure we don't repeat ourselves or DRY principal

As most of the teams use multiple environments to build a product, we need to deploy resources to all those environments. Not that always the environments have the same resources or configurations, in fact, most of the time you'd have different resources or setups for your dev compared to prod or staging. In the AWS, you would have different accounts for different environments due to various reasons such as security, access distribution and etc.

In my case, I wanted to deploy to these environments as efficiently as possible. I have some common resources between these environments and some resources that are specific to each one. On the other hand, I want to have only one CDK app handling my deployments to different environments.

The solution that I came up with was using assume role I can figure out which account we want to deploy and based on that account number and a simple mapping between environments and accounts, I figure out which environment is the one we want to deploy so I just deploy the stacks that I want for that environment.

As you can see this is very easy since we're writing the infrastructure imperatively:

/* eslint-disable no-new */

const AWS = require("aws-sdk");
const cdk = require("@aws-cdk/core");
const { CommonStack } = require("./stack");
const { DevStack } = require("./dev-stack");
const { ProdStack } = require("./prod-stack");


const sts = new AWS.STS({});

const TEST_REGION = "eu-west-1";
const DEV_REGION = "eu-west-1";

const AWS_ACCOUNT_IDS = {
  development: "000000000",
  quality: "00000000",
  production: "000000000",
};

class App extends cdk.App {

  deployCommonStacks() {
    this.commonStack = new CommonStack(
      this,
      "commonStack",
      {}
    );
  }
  
  deployDevStacks() {
    this.devStack = new DevStack(
      this,
      "devStack",
      {}
    );    
  }
  
  deployProdStacks() {
    this.prodStack = new ProdStack(
      this,
      "prodStack",
      {}
    );    
    
  }

  async deployStacks() {
    const assumed = await sts.getCallerIdentity({}).promise();
    console.log("deployStacks() caller identity:", assumed);

    this.deployCommonStacks();

    if (assumed.Account === AWS_ACCOUNT_IDS.development) {
      console.log("Deploying to development account:");
      this.deployDevStacks();
    }

    if (assumed.Account === AWS_ACCOUNT_IDS.production) {
      console.log("Deploying to production account:");
      this.deployProdStacks();
    }

    return assumed.Account;
  }
}

const app = new App();
app
  .deployStacks()
  .then(acc => {
    console.log(`deployStacks() completed for account: ${acc}`);
  })
  .catch(e => {
    console.log("error in deployStacks():", e);
  });

© Copyright 2022 Farmin Farzin