Lab 1: Terraform Fundamentals & State Security
Install and verify Terraform
If not installed, refer to the Week 0 setup lab.
$ terraform version # Should return v1.x.x
Initialize project structure
Create a new Terraform project with the AWS provider pinned to a stable version.
$ mkdir -p ~/bootcamp-terraform && cd ~/bootcamp-terraform $ cat > main.tf << 'EOF' terraform { required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } } } provider "aws" { region = "us-east-1" } EOF $ terraform init
Create S3 backend for remote state
State files contain secrets in plaintext. Never store locally or in git.
$ ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) $ STATE_BUCKET="bootcamp-tf-state-${ACCOUNT_ID}" $ aws s3api create-bucket --bucket $STATE_BUCKET --region us-east-1 $ aws s3api put-bucket-versioning --bucket $STATE_BUCKET \ --versioning-configuration Status=Enabled $ aws s3api put-bucket-encryption --bucket $STATE_BUCKET \ --server-side-encryption-configuration \ '{"Rules":[{"ApplyServerSideEncryptionByDefault":{"SSEAlgorithm":"AES256"}}]}' $ aws s3api put-public-access-block --bucket $STATE_BUCKET \ --public-access-block-configuration \ "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true" # Create DynamoDB table for state locking $ aws dynamodb create-table \ --table-name bootcamp-tf-locks \ --attribute-definitions AttributeName=LockID,AttributeType=S \ --key-schema AttributeName=LockID,KeyType=HASH \ --billing-mode PAY_PER_REQUEST
Terraform state contains every secret, every resource ID, every configuration. Encrypt it, lock it, restrict access to only the CI/CD pipeline role.
Configure backend in Terraform
Replace ACCOUNT_ID with your actual account ID. Run terraform init to migrate.
$ cat > backend.tf << 'EOF' terraform { backend "s3" { bucket = "bootcamp-tf-state-ACCOUNT_ID" key = "bootcamp/terraform.tfstate" region = "us-east-1" encrypt = true dynamodb_table = "bootcamp-tf-locks" } } EOF # Migrate to remote backend $ terraform init -migrate-state
Create variables with validation
Input validation blocks reject insecure inputs at plan time.
$ cat > variables.tf << 'EOF' variable "environment" { type = string description = "Environment name" validation { condition = contains(["lab", "staging", "production"], var.environment) error_message = "Environment must be lab, staging, or production." } } variable "vpc_cidr" { type = string default = "10.0.0.0/16" validation { condition = can(cidrhost(var.vpc_cidr, 0)) error_message = "Must be a valid CIDR block." } } EOF