Aws Cdk Important Concepts

Page content

Intro

CDK is an opinionated framework for developing aws infrastructure as code.

It is an abstraction on top of AWS Cloudformation that enables developers to write infrastructure as code in their programming language of choice (Typescript, Python, .NET, Java etc.)

Getting started

npm install -g aws-cdk

cdk --version

npx npm-check-updates -u

Hollo World! App

mkdir HelloApp && cd HelloApp

cdk init --language typescript

  • set an outDir in tsconfig.json before running cdk diff or deploy. Helps with orgranising your files
  • add the outDir to exclude section of the tsconfig file
  • rm package-lock.json && yarn
  • Listing the Stacks in the App. cdk list
  • Adding a package for a aws service. npm install @aws-cdk/aws-s3
  • cdk to cfn. cdk synth
  • cdk to yaml cdk synth --no-staging > template.yaml
  • in dev mode: npm run watch
  • compare deployed stack with current state: cdk diff
  • deploy: cdk deploys OH WAIT! Run bootstrap as shown below
  • run cdk bootstrap for the first time. It sets up the artifact bucket
  • enable resolveJsonModule in tsconfig.json if you want to import a json file(say dev-params.json)
  • use export AWS_PROFILE or cdk deploy –profile «profilename»

Other useful packages to install

npm i --save @aws-cdk/aws-apigateway;
npm i --save @aws-cdk/aws-lambda;
npm i --save @aws-cdk/aws-ec2;
npm i --save @aws-cdk/aws-ecs;
npm i --save @aws-cdk/aws-ecs-patterns;

Why?

  • cfn, tf lots of code, less abstraction

  • config syntax

  • When creating a resource, jumping between editor to documentation.

  • Composition: pack the key enterprise best practices into a construct or pattern into a library and let others build on top it. Few examples could be common tags, naming convention, say prefixes, enforcing security etx. Fix bugs at one place and developers could update the package and go with it.

CDK structure

  • App(Root)
  • Stack1(similar to AWS Cfn stack)
    • resource
    • contruct(single s3 bucket) or abstract constructs(s3, sns, sqs, lambda)
    • pattern
  • Stack2

Concepts:

App:

Root level element, comprises of all other element

Constructs - single or a high level component that includes a combination of multiple aws resources(s3, lambda, sqs and sns)

eg:

  • s3.CfnBucket represents the AWS::S3::Bucket
  • dynamodb.table The construct library also includes a much higher level construct called patterns which has most common aws patterns built in. For example, aws-apigateway.LambdaRestApi construct represents an aws API Gateway API that’s linked to aws Lambda function. So you don’t have to wire things manually. Initialization:
    • scope(Required): the construct within which this construct is defined. you can blindly pass this as the value
    • id(Required): Unique identifier used as a namespace and used for resource names and cfn logical ids
    • props(Optional): a set of properties,

Level 1. Single resource

new s3.cfnBucket(this, "bucketname", {})
ec2.cfnVpc()

Level 2: CDK Built in

new s3.Bucket(this, 'MyEncryptedBucket', {
  encryption: s3.BucketEncryption.KMS,
  websiteIndexDocument: 'index.html'
});

new ec2.vpc()
new lambda.RestApi()

Level 3. Build your own

BucketWithSNSNotificationWithAlarms

Stacks:

Equivalent of CFN stacks. Same limits apply.

cdk ls # to list all the stacks in a app
  • Stack.of(construct)
  • stack.stackName
  • stack.region and stack.account
  • stack.addDependency(stack)
  • stack.tags
  • stack.partition, stack.urlSuffix, stack.stackId, and stack.notificationArn – Return tokens that resolve to the respective AWS CloudFormation pseudo-parameters
  • stack.availabilityZones
  • stack.parseArn(arn) & stack.formatArn(comps)
  • stack.toJsonString(obj)
  • stack.templateOptions

Environments:

const envdev  = {
  account: process.env.CDK_DEPLOY_ACCOUNT || '747XXXX',
  region: process.env.CDK_DEPLOY_REGION || 'ap-southeast-2'
};
new AvailabilityStack(app, 'availability', { env: envdev })

Resources:

const queue = new sqs.Queue(this, 'MyQueue');
const url = queue.queueUrl;

// Construct a resource (bucket) just by its name (must be same account)
s3.Bucket.fromBucketName(this, 'MyBucket', 'my-bucket-name');

// Construct a resource (bucket) by its full ARN (can be cross account)
s3.Bucket.fromArn(this, 'MyBucket', 'arn:aws:s3:::my-bucket-name');

// Construct a resource by giving attribute(s) (complex resources)
ec2.Vpc.fromVpcAttributes(this, 'MyVpc', {
  vpcId: 'vpc-1234567890abcde',
});

// exception is VPC, you can query using tags
ec2.Vpc.fromLookup(this, 'DefaultVpc', {
  isDefault: true
})
ec2.Vpc.fromLookup(this, 'PublicVpc',
  {tags: {'aws-cdk:subnet-type': "Public"}
});

Idenitifiers:

Ids for different elements resources, stacks etc. Need to be unique within the stack not necessary to be unique globally

  • Construct IDs - passed on the second arg
  • Paths -
  • Unique IDs
  • Logical IDs

Tokens:

Tokens represent values that can only be resolved at a later time in the lifecycle of an app. const bucket = new s3.Bucket(this, “somebucket”, {}) bucket.bucketName = is stored as a token = ${TOKEN[Bucket.Name.1234]} and resolved at a later stage. In Cfn it tranforms to { "Ref": "MyBucket" } So do not manipulate the bucket.bucketName like trying to get the prefix or suffix of a bucket name.

Parameters:

CDK recommend’s against using AWS CloudFormation parameters with the AWS CDK. Parameter values are not available at synthesis time and thus cannot be easily used in other parts of your AWS CDK app, particularly for control flow. An ideal AWS CDK-generated AWS CloudFormation template is concrete, with no values remaining to be specified at deployment time.

Tagging:

Tag.add()

Tag.add(myConstruct, 'SpecialS3Tag', 'IamAnS3ObjectYouKnow', {
  includeResourceTypes: ['AWS::S3::*'],
  excludeResourceTypes: ['AWS::S3::*/'],
  priority: 100, // Priority over other params
});

Permissions

IAM resources such as Role, User, and Group

const role = new iam.Role(this, 'Role', {
  assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),   // required
});

bucket.addToResourcePolicy(new iam.PolicyStatement({
  effect: iam.Effect.ALLOW,
  actions: ['s3:SomeAction'],
  resources: [bucket.bucketArn],
  principals: [role]
}));

Assets

  • local files, directories or docker images that can be bundled into cdk
  • eg: lambda.Function { code : asset(DIR)}
  • eg2 : ecs.containerImage.fromAsset() // docker image built from local dir Types:
    • s3 assets, docker image
// Archived and uploaded to Amazon S3 as a .zip file
const directoryAsset = new Asset(this, "SampleZippedDirAsset", {
  path: path.join(__dirname, "sample-asset-directory")
});

// Uploaded to Amazon S3 as-is
const fileAsset = new Asset(this, 'SampleSingleFileAsset', {
  path: path.join(__dirname, 'file-asset.txt')
});

Context

Gets information such as availability zones in your acc or AMI ID’s to start your instance. Context entries are kv pairs. The retrieved values are stored in cdk.context.json. This can be feed into the cdk app in 5 different ways.

  • from AWS acc
  • --context option of the cdk command
  • in the context key of ~/cdk.json file
  • in the context key projects cdk.json file
  • in code using the construct.node.setContext method

to get the context value call construct.node.tryGetContext method. hint: tryGetContext? which means can be undefined if not found

cdk context // to view the contexts
cdk context reset --key-number to reset
cdk context clear // to clear all

Commonly used one is to get the vpcId

const vpcid = this.node.tryGetContext('vpcid');
const vpc = ec2.Vpc.fromLookup(this, 'VPC', {
  vpcId: vpcid,
});

Feature Flags

The AWS CDK uses feature flags to enable potentially breaking behaviors in a release. Bleeding edge?

Aspects

Aspects are a way to apply an operation to all constructs in a given scope.

Escape hatches

  • If there is no equivalent construct for cfn or some features are missing or when there is no cfn solution for a resource new s3.CfnBucket(this, 'MyBucket', {})

Gotchas:

  • make sure the aws-core and other packages are same version. Incompatibility with version number can sometimes cause issues.
  • AWS CloudFormation parameters are generally discouraged when using CDK because they are resolved only during deployment
  • To conditionally include a resource in your app when using CDK use, if condition not cfn condition. CDK provides as much resolution as possible during synthesis.

Tools & Tips: ;)

  • Use AWS CDK explorer VSCode
  • cdk-watchful