Why this matters
Worked examples
Example 1: Storage bucket with versioning (Terraform HCL)
# variables.tf
variable "bucket_name" {
type = string
description = "Name of the data lake bucket"
}
# main.tf (AWS example)
provider "aws" {
region = "us-east-1"
}
resource "aws_s3_bucket" "data_lake" {
bucket = var.bucket_name
tags = {
project = "analytics"
env = "dev"
}
}
resource "aws_s3_bucket_versioning" "ver" {
bucket = aws_s3_bucket.data_lake.id
versioning_configuration {
status = "Enabled"
}
}
output "bucket_arn" {
value = aws_s3_bucket.data_lake.arn
}
Run: terraform init → terraform validate → terraform plan. You should see: “Plan: 2 to add, 0 to change, 0 to destroy.”
Example 2: IAM policy for read-only access to that bucket
data "aws_iam_policy_document" "read_only" {
statement {
actions = ["s3:GetObject", "s3:ListBucket"]
resources = [
aws_s3_bucket.data_lake.arn,
"${aws_s3_bucket.data_lake.arn}/*"
]
}
}
resource "aws_iam_policy" "read_only_policy" {
name = "data-lake-read-only"
policy = data.aws_iam_policy_document.read_only.json
}
This attaches least-privilege permissions for consumers who only need to read data.
Example 3: GCP bucket with labels (Terraform)
provider "google" {
project = "your-project-id"
region = "us-central1"
}
resource "google_storage_bucket" "lake" {
name = "my-data-lake-dev"
location = "US"
storage_class = "STANDARD"
labels = {
project = "analytics"
env = "dev"
}
versioning {
enabled = true
}
}
The idea is identical: declare the bucket, labels, and versioning. Different provider, same IaC workflow.
Learning path
- Understand declarative IaC, state, plan/apply, and idempotency.
- Create small resources (buckets, tags/labels, versioning, lifecycle).
- Add IAM: least privilege policies and roles.
- Refactor into modules and variables for reuse.
- Introduce environments: dev → stage → prod with workspaces or separate state.
- Automate: run fmt/validate/plan in CI and require review before apply.
Exercises
Note: You can take the quick test below without signing in. To save your progress and resume later, sign in to your LuvvHelp account.
Exercise 1: Bucket with versioning, lifecycle, and output
Create a Terraform project that declares a storage bucket with:
- Versioning enabled.
- A lifecycle rule that deletes noncurrent versions after 30 days.
- Tags/labels for project and environment.
- An output that prints the bucket ARN (or self_link on GCP).
Use a variable for the bucket name. Run init → validate → plan. Do not apply to a real account unless you fully understand the consequences.
Checklist
- [ ] variables.tf contains bucket_name.
- [ ] Versioning enabled resource present.
- [ ] Lifecycle rule handles noncurrent versions in 30 days.
- [ ] Tags/labels set for project and env.
- [ ] Output prints bucket identifier (ARN or self_link).
- [ ] terraform validate passes.
- [ ] terraform plan shows only adds, no destroys in a new workspace.
Common mistakes and self-check
- Forgetting version control: Always commit IaC to Git to review and roll back.
- Hardcoding names: Use variables; keep provider/region abstract when possible.
- Skipping plan review: Never apply without reading the plan in PR or locally.
- Ignoring state: Do not delete or manually edit state. Use remote state for teams.
- Over-permissive IAM: Start with least privilege; expand only if needed.
- Drift blindness: Schedule regular plans to detect drift (changes made outside IaC).
Self-check: If you run plan twice with no code changes, it should show “0 to add, 0 to change, 0 to destroy.” If not, identify drift or non-idempotent code.
Practical projects
- Data Lake Starter: One bucket per layer (raw, curated), standard tags/labels, versioning, lifecycle; outputs for ARNs/links.
- Read-Only Consumer Role: A reusable module that grants limited access to curated data.
- Sandbox Environment: Dev environment that mirrors prod structure with smaller sizes and fewer permissions.
Next steps
- Extract your bucket and IAM patterns into modules.
- Add CI checks: fmt, validate, plan on pull requests.
- Introduce environments with workspaces or separate state files.
Mini challenge
Design a minimal IaC layout for three environments (dev/stage/prod) that reuses the same module for buckets and IAM, differing only by variables. Write down your directory structure and the variables you would expose (e.g., bucket prefix, lifecycle days, tags/labels, permissions).
Quick test notice
Everyone can take the quick test below for free. Sign in if you want your score and progress to be saved.