{"componentChunkName":"component---src-gatsby-theme-chronoblog-templates-note-js","path":"/notes/infrastructure-as-code-iac-cdk/","result":{"data":{"mdx":{"parent":{"__typename":"File","fields":{"gitLogLatestDate":"2026-06-11 00:18:10 +0200"}},"id":"7d110d34-0d2c-5777-9ea1-18493d121479","excerpt":"Infrastructure as Code (IaC) is a DevOps approach where infrastructure is defined and managed using code instead of manual setup. This makes…","frontmatter":{"title":"Infrastructure as Code (IaC) with AWS CDK (EC2 Example)","date":"2026-06-11 00:02:00 UTC","job_ad":null,"job_ad_id":null,"job_ad_url":null,"tags":["devops","iac","cdk","aws","ec2"],"cover":{"childImageSharp":{"fluid":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAA+UlEQVQoz31S2XKDMBDz//9n03D6wPha2+p4GdqSBGtGD4CQtPaKWivu2PD2Hve6BtE3PESv6BriBu37+UPwBfuemZTqx4ATwm4ZxhALiQgxRubZrpSMZfYYB8f0rsBowjQmyJVQyrWtWKYm3pFigbUb1lVCSgmjA7TO8C5htwStCYafCfNk8fiymEZ3accNlSSsS+DUf0NArgHj4GFMgFaBQxt3mzi8mYfQpjoat8AYK8TMDS2UTDxyY0rpN7mNrJVH0y1zPCbZIh4PC6MTgicMT4fnt4Vz5f5S/g67wrsMpSKUSsiELrprc/AtpqsXr/t0XZnPBj3TH6EPEycle1xgAAAAAElFTkSuQmCC","aspectRatio":2.0869565217391304,"src":"/static/20a62c974977a52722be75c12fb5b401/c4ecb/cover.png","srcSet":"/static/20a62c974977a52722be75c12fb5b401/57ab0/cover.png 192w,\n/static/20a62c974977a52722be75c12fb5b401/f4739/cover.png 384w,\n/static/20a62c974977a52722be75c12fb5b401/c4ecb/cover.png 768w","srcWebp":"/static/20a62c974977a52722be75c12fb5b401/dd090/cover.webp","srcSetWebp":"/static/20a62c974977a52722be75c12fb5b401/ae504/cover.webp 192w,\n/static/20a62c974977a52722be75c12fb5b401/fef30/cover.webp 384w,\n/static/20a62c974977a52722be75c12fb5b401/dd090/cover.webp 768w","sizes":"(max-width: 768px) 100vw, 768px","presentationWidth":768,"presentationHeight":366},"resize":{"src":"/static/20a62c974977a52722be75c12fb5b401/c4ecb/cover.png"}}}},"fields":{"slug":"/notes/infrastructure-as-code-iac-cdk/","readingTime":{"text":"3 min read"}},"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {\n  \"title\": \"Infrastructure as Code (IaC) with AWS CDK (EC2 Example)\",\n  \"date\": \"2026-06-11 00:02:00 UTC\",\n  \"cover\": \"./cover.png\",\n  \"tags\": [\"devops\", \"iac\", \"cdk\", \"aws\", \"ec2\"],\n  \"canonical_url\": \"https://sevic.dev/notes/infrastructure-as-code-iac-cdk/\"\n};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"Infrastructure as Code (IaC) is a DevOps approach where infrastructure is defined and managed using code instead of manual setup. This makes environments reproducible, version-controlled, and easy to scale.\"), mdx(\"p\", null, \"In this guide, you'll provision an AWS EC2 instance using the \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://docs.aws.amazon.com/cdk/v2/guide/home.html\"\n  }), \"AWS Cloud Development Kit (CDK)\"), \". CDK lets you define infrastructure in TypeScript (or other languages), synthesize CloudFormation templates, and deploy stacks through the CDK CLI.\"), mdx(\"h3\", {\n    \"id\": \"requirements\"\n  }, \"Requirements\"), mdx(\"p\", null, \"Before starting, install:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Node.js version 26\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"AWS CDK CLI (\", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"npm i -g aws-cdk\"), \")\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"AWS CLI\")), mdx(\"h3\", {\n    \"id\": \"aws-credentials-setup\"\n  }, \"AWS Credentials Setup\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Go to IAM \\u2192 Security credentials in AWS\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Create access keys\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Configure locally:\")), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), \"aws configure\\n\")), mdx(\"p\", null, \"This stores credentials in:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"~/.aws/credentials\")), mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"~/.aws/config\"))), mdx(\"p\", null, \"CDK requires CloudFormation permissions (and bootstrap-related IAM/S3 access). An IAM user scoped only for Terraform EC2 is often insufficient - attach broader permissions or use a dedicated CDK user.\"), mdx(\"h3\", {\n    \"id\": \"project-structure\"\n  }, \"Project Structure\"), mdx(\"p\", null, \"A simple CDK TypeScript setup:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {}), \".\\n\\u251C\\u2500\\u2500 bin/\\n\\u2502   \\u2514\\u2500\\u2500 app.ts\\n\\u251C\\u2500\\u2500 lib/\\n\\u2502   \\u2514\\u2500\\u2500 ec2-stack.ts\\n\\u251C\\u2500\\u2500 cdk.json\\n\\u251C\\u2500\\u2500 package.json\\n\\u2514\\u2500\\u2500 tsconfig.json\\n\")), mdx(\"p\", null, \"Install dependencies:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), \"npm i\\n\")), mdx(\"h3\", {\n    \"id\": \"app-entry\"\n  }, \"App Entry\"), mdx(\"p\", null, \"The CDK app wires stacks together in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"bin/app.ts\"), \":\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-typescript\"\n  }), \"#!/usr/bin/env node\\nimport * as cdk from 'aws-cdk-lib';\\nimport { Ec2Stack } from '../lib/ec2-stack';\\n\\nconst app = new cdk.App();\\n\\nnew Ec2Stack(app, 'Ec2Stack', {\\n  env: {\\n    account: process.env.CDK_DEFAULT_ACCOUNT,\\n    region: process.env.CDK_DEFAULT_REGION ?? 'eu-north-1',\\n  },\\n  instanceName: app.node.tryGetContext('instanceName') ?? 'MyEC2Name',\\n});\\n\")), mdx(\"p\", null, \"Set the target account and region once per shell session:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-bash\"\n  }), \"export CDK_DEFAULT_ACCOUNT=$(aws sts get-caller-identity --query Account --output text)\\nexport CDK_DEFAULT_REGION=eu-north-1\\n\")), mdx(\"p\", null, \"On Windows PowerShell:\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-powershell\"\n  }), \"$env:CDK_DEFAULT_ACCOUNT = aws sts get-caller-identity --query Account --output text\\n$env:CDK_DEFAULT_REGION = \\\"eu-north-1\\\"\\n\")), mdx(\"h3\", {\n    \"id\": \"stack-and-ec2-instance\"\n  }, \"Stack and EC2 Instance\"), mdx(\"p\", null, \"Define the stack in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"lib/ec2-stack.ts\"), \":\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-typescript\"\n  }), \"import * as cdk from 'aws-cdk-lib';\\nimport * as ec2 from 'aws-cdk-lib/aws-ec2';\\nimport { Construct } from 'constructs';\\n\\nexport interface Ec2StackProps extends cdk.StackProps {\\n  instanceName?: string;\\n}\\n\\nexport class Ec2Stack extends cdk.Stack {\\n  constructor(scope: Construct, id: string, props?: Ec2StackProps) {\\n    super(scope, id, props);\\n\\n    const instanceName = props?.instanceName ?? 'MyEC2Name';\\n\\n    const instance = new ec2.Instance(this, 'AppServer', {\\n      vpc: ec2.Vpc.fromLookup(this, 'DefaultVpc', { isDefault: true }),\\n      instanceType: ec2.InstanceType.of(\\n        ec2.InstanceClass.T3,\\n        ec2.InstanceSize.MICRO,\\n      ),\\n      machineImage: ec2.MachineImage.latestAmazonLinux2023(),\\n      instanceName,\\n    });\\n\\n    new cdk.CfnOutput(this, 'InstanceId', {\\n      value: instance.instanceId,\\n      description: 'EC2 instance ID',\\n    });\\n\\n    new cdk.CfnOutput(this, 'InstancePublicIp', {\\n      value: instance.instancePublicIp,\\n      description: 'Public IP address',\\n    });\\n  }\\n}\\n\")), mdx(\"p\", null, \"CDK resolves the default VPC during synthesis. Amazon Linux 2023 is selected automatically for the current region.\"), mdx(\"h3\", {\n    \"id\": \"configuration\"\n  }, \"Configuration\"), mdx(\"p\", null, \"CDK settings live in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"cdk.json\"), \":\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-json\"\n  }), \"{\\n  \\\"app\\\": \\\"npx ts-node --prefer-ts-exts bin/app.ts\\\",\\n  \\\"context\\\": {\\n    \\\"instanceName\\\": \\\"MyEC2Name\\\"\\n  }\\n}\\n\")), mdx(\"p\", null, \"Change \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"instanceName\"), \" in \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"context\"), \" to override the default tag without editing stack code.\"), mdx(\"h3\", {\n    \"id\": \"cdk-workflow\"\n  }, \"CDK Workflow\"), mdx(\"p\", null, \"Bootstrap the environment (once per account/region):\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"cdk bootstrap\"))), mdx(\"p\", null, \"Preview the CloudFormation template:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"cdk synth\"))), mdx(\"p\", null, \"Compare deployed stack with local changes:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"cdk diff\"))), mdx(\"p\", null, \"Deploy the stack:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"cdk deploy\"))), mdx(\"p\", null, \"Destroy infrastructure:\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"cdk destroy\"))), mdx(\"h3\", {\n    \"id\": \"important-notes\"\n  }, \"Important Notes\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"State management\")), mdx(\"p\", null, \"CDK deploys through CloudFormation. Stack state lives in AWS, not in a local file like Terraform's \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"terraform.tfstate\"), \".\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Bootstrap stack\")), mdx(\"p\", null, \"The first \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"cdk bootstrap\"), \" creates an S3 bucket and IAM roles CDK uses for deployments. Keep the bootstrap stack in place while you use CDK in that account/region.\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Idempotency\")), mdx(\"p\", null, \"Running \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"cdk deploy\"), \" again updates the stack in place when possible instead of recreating resources unnecessarily.\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Version control\")), mdx(\"p\", null, \"Treat CDK code like application code. Commit \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"cdk.json\"), \" and lockfiles; do not commit \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"cdk.out/\"), \" or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"node_modules/\"), \".\"), mdx(\"h3\", {\n    \"id\": \"demo\"\n  }, \"Demo\"), mdx(\"p\", null, \"CDK project files for this post live in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"cdk-aws-ec2\"), \" folder. Get access via \", mdx(\"a\", _extends({\n    parentName: \"p\"\n  }, {\n    \"href\": \"https://sevic.dev/demos\"\n  }), \"code demos\"), \".\"));\n}\n;\nMDXContent.isMDXComponent = true;"}},"pageContext":{"id":"7d110d34-0d2c-5777-9ea1-18493d121479"}},"staticQueryHashes":["1961101537","2542493696"]}