# Infrastructure as Code on AWS: A Practical Introduction
Key Takeaways
- AWS infrastructure as code (IaC) means defining cloud resources in version-controlled files instead of clicking through the console.
- CloudFormation, AWS CDK, and Terraform are the three mainstream ways to do AWS IaC — each trades off differently between native integration and multi-cloud flexibility.
- A minimal IaC pipeline needs three things: a template, a state/drift mechanism, and a CI step that plans before it applies.
- Start small: codify one low-risk stack (like an S3 bucket or a VPC) before migrating critical infrastructure.
What Is AWS Infrastructure as Code?
AWS infrastructure as code is the practice of defining every AWS resource — VPCs, EC2 instances, IAM roles, Lambda functions, S3 buckets — as declarative configuration files rather than manual console clicks or ad hoc scripts. Those files live in Git, get reviewed in pull requests, and are applied through an automated pipeline. The result: your infrastructure becomes reproducible, auditable, and diffable, the same way your application code already is.
Teams adopt AWS infra as code for a handful of very concrete reasons:
- Reproducibility. Spin up an identical staging environment in minutes, not days.
- Auditability. Every change is a commit with an author, a timestamp, and a reason.
- Drift detection. You can prove what's actually running matches what's declared.
- Disaster recovery. Rebuild an entire environment from code if a region or account is lost.
The Three Main Tools
AWS CloudFormation
CloudFormation is AWS's native IaC service — JSON or YAML templates, no third-party state file, deep AWS service coverage on day one of a new feature launch.
AWSTemplateFormatVersion: "2010-09-09"
Description: Minimal S3 bucket with versioning and encryption
Resources:
AppBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: f9infotech-app-assets-prod
VersioningConfiguration:
Status: Enabled
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
Outputs:
BucketArn:
Value: !GetAtt AppBucket.Arn
Deploy it with the CLI:
aws cloudformation deploy \
--template-file bucket.yaml \
--stack-name app-assets-stack \
--capabilities CAPABILITY_NAMED_IAM
AWS CDK (Cloud Development Kit)
CDK lets you write infrastructure in TypeScript, Python, Java, or Go, and it compiles down to a CloudFormation template under the hood. You get loops, conditionals, and real abstractions — a huge win once your stacks grow past a handful of resources.
from aws_cdk import Stack, aws_s3 as s3
from constructs import Construct
class AppAssetsStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
s3.Bucket(
self, "AppBucket",
bucket_name="f9infotech-app-assets-prod",
versioned=True,
encryption=s3.BucketEncryption.S3_MANAGED,
)
Terraform
Terraform (HashiCorp Configuration Language) is cloud-agnostic, backed by a large open-source provider ecosystem, and the most common choice for teams running AWS alongside other clouds or SaaS platforms.
resource "aws_s3_bucket" "app_bucket" {
bucket = "f9infotech-app-assets-prod"
}
resource "aws_s3_bucket_versioning" "app_bucket_versioning" {
bucket = aws_s3_bucket.app_bucket.id
versioning_configuration {
status = "Enabled"
}
}
terraform init
terraform plan -out=tfplan
terraform apply tfplan
Choosing Between Them
| Factor | CloudFormation | CDK | Terraform |
|---|---|---|---|
| AWS-only shop | Good fit | Great fit | Overkill but fine |
| Multi-cloud / SaaS | Weak | Weak | Strong |
| Team already codes in Python/TS | Fine | Great fit | Fine (HCL is its own language) |
| New AWS service support | Day one | Day one (wraps CFN) | Often a short lag |
| State management | AWS-managed | AWS-managed | You manage (S3 + DynamoDB lock, or Terraform Cloud) |
Architecture: A Minimal IaC Pipeline
<svg viewBox="0 0 760 220" xmlns="http://www.w3.org/2000/svg" style="width:100%;max-width:760px;font-family:sans-serif;color:inherit">
<style>
.box { fill: none; stroke: currentColor; stroke-width:1.5; rx:8; }
.lbl { fill: currentColor; font-size:13px; }
.arrow { stroke: currentColor; stroke-width:1.5; marker-end:url(#arrow); }
</style>
<defs>
<marker id="arrow" markerWidth="10" markerHeight="10" refX="8" refY="3" orient="auto">
<path d="M0,0 L8,3 L0,6 Z" fill="currentColor"/>
</marker>
</defs>
<rect class="box" x="10" y="80" width="130" height="60"/>
<text class="lbl" x="30" y="115">Git Commit</text>
<rect class="box" x="190" y="80" width="130" height="60"/>
<text class="lbl" x="205" y="105">CI Pipeline</text>
<text class="lbl" x="205" y="122">terraform plan</text>
<rect class="box" x="370" y="20" width="150" height="60"/>
<text class="lbl" x="385" y="50">Manual Approval</text>
<text class="lbl" x="385" y="67">(prod only)</text>
<rect class="box" x="370" y="140" width="150" height="60"/>
<text class="lbl" x="385" y="170">Auto-apply</text>
<text class="lbl" x="385" y="187">(dev/staging)</text>
<rect class="box" x="580" y="80" width="160" height="60"/>
<text class="lbl" x="600" y="105">AWS Account</text>
<text class="lbl" x="600" y="122">Resources live</text>
<line class="arrow" x1="140" y1="110" x2="188" y2="110"/>
<line class="arrow" x1="320" y1="95" x2="368" y2="60"/>
<line class="arrow" x1="320" y1="125" x2="368" y2="165"/>
<line class="arrow" x1="520" y1="50" x2="580" y2="95"/>
<line class="arrow" x1="520" y1="170" x2="580" y2="120"/>
</svg>
A Practical Adoption Path
- Pick one tool and commit. Mixing CloudFormation and Terraform for the same resources creates drift fights. CDK and CloudFormation can coexist since CDK compiles to CFN.
- Codify something low-risk first. An S3 bucket, a VPC, a security group — not your production RDS instance.
- Set up remote state. For Terraform, an S3 backend with DynamoDB locking. For CDK/CloudFormation, this is managed for you.
- Add a CI plan step. Every pull request should run
terraform planorcdk diffand post the output as a comment before merge. - Gate production applies behind manual approval. Automatic applies are fine for dev/staging; production should have a human in the loop.
- Import existing resources gradually. Use
terraform importor CloudFormation's resource import feature rather than recreating everything from scratch.
# Import an existing S3 bucket into Terraform state instead of recreating it
terraform import aws_s3_bucket.app_bucket f9infotech-app-assets-prod
Common Pitfalls
- Treating state as disposable. A lost Terraform state file is a production incident. Back it up, lock it, version it.
- No plan-before-apply gate. Applying straight from a feature branch without review is how a typo deletes a VPC.
- Giant single stacks. One 5,000-line template covering every resource in the account becomes unreviewable and slow to apply. Split by lifecycle and blast radius.
- Secrets in plaintext templates. Use AWS Secrets Manager or SSM Parameter Store references, never hardcoded credentials.
FAQ
Is CloudFormation or Terraform better for AWS-only infrastructure? For a pure AWS shop, CloudFormation (or CDK on top of it) gives you day-one support for new AWS services and no separate state file to manage. Terraform is still a solid choice if your team already knows HCL or you anticipate adding other providers later.
Does AWS IaC replace the AWS Console entirely? Not for everything — it's common to use the console for one-off investigation and read-only exploration, while all resource creation and changes flow through code. The rule of thumb: if a change should be repeatable or auditable, it belongs in code.
How do I handle infrastructure that already exists in the console? Import it. Both Terraform and CloudFormation support importing unmanaged resources into state/stack management so you don't have to destroy and recreate production infrastructure to adopt IaC.
What's the fastest way to start with AWS infrastructure as code? Pick a single non-critical stack — a logging bucket or a dev VPC — and write it in CloudFormation or Terraform this week. Momentum on one real stack beats a perfect plan for codifying everything at once.
---
Rolling out infrastructure as code across a large AWS estate touches security, cost, and migration planning all at once. f9infotech's AWS consulting and managed services team can help you design an IaC adoption plan that fits your existing environment — get in touch to talk through your infrastructure.