Bootstrap AWS backend for Terraform state, ECR, and IAM
Backend Setup
One-time per AWS account. Creates shared infrastructure for all Astrolock sites.
Info
After this setup, you can create unlimited sites.
Quick Bootstrap
Two steps: Create IAM user in CloudShell (~2 min), then run Terraform locally (~5 min).
Step 1: CloudShell
# 1. Open AWS CloudShell
# - Log into console.aws.amazon.com with admin account
# - Select us-east-1 region
# - Click CloudShell icon (>_) in top nav
# 2. Download and run bootstrap script
curl -O https://raw.githubusercontent.com/YOUR-ORG/astrolock-template/main/terraform/astrolock_backend/bootstrap-cloudshell.sh
chmod +x bootstrap-cloudshell.sh
./bootstrap-cloudshell.sh
# 3. Save the displayed credentials (shown only once!)
# Access Key ID: AKIA...
# Secret Access Key: wJalr...
Warning
Save credentials securely - they have full backend permissions.
Step 2: Local Terraform
# 1. Configure AWS credentials on your machine
aws configure --profile astrolock-terraform-admin
# Enter: Access Key, Secret Key, region=us-east-1, output=json
# 2. Verify credentials
export AWS_PROFILE=astrolock-terraform-admin
aws sts get-caller-identity
# 3. Run Terraform to create infrastructure
cd terraform/astrolock_backend
make bootstrap-init # Init with local state
make plan # Preview
make bootstrap-apply # Create S3, DynamoDB, ECR, IAM groups
# 4. Migrate to remote state
make migrate-state # Answer 'yes' to copy state
# 5. Create your operational user
make create-user USER=yourname GROUP=astrolock-backend-provisioners
make create-access-key USER=yourname
aws configure --profile astrolock-backend-provisioner
# Enter the new access keys
# 6. Switch to operational profile and test
export AWS_PROFILE=astrolock-backend-provisioner
make plan # Should work!
# 7. Delete bootstrap user (security best practice)
make delete-bootstrap-user USER=terraform-admin
Success
Bootstrap complete! Now use astrolock-backend-provisioner profile for backend management.
IAM Groups
| Group | Purpose | Key Permissions | Use For |
|---|---|---|---|
backend-provisioners | Manage backend infra | S3, DynamoDB, ECR, IAM | DevOps engineers |
sites-provisioners | Create sites | S3 buckets, CloudFront, ACM, Route53, IAM site users | Site creation |
sites-deployers | Deploy content | S3 uploads, CloudFront invalidations | CI/CD, deploys |
Create users: make create-user USER=name GROUP=group-name && make create-access-key USER=name
Day-to-Day Operations
export AWS_PROFILE=astrolock-backend-provisioner
cd terraform/astrolock_backend
make plan # Preview
make apply # Apply
make output # View outputs
Managing Users
# Create user
make create-user USER=alice GROUP=astrolock-backend-provisioners
make create-access-key USER=alice
# List users
make list-users
# Remove user
aws iam remove-user-from-group --user-name alice --group-name GROUP
aws iam delete-access-key --user-name alice --access-key-id AKIA...
aws iam delete-user --user-name aliceDocker Registry (ECR)
# Login
make docker-login
# Push images
make ecr-urls # Get repository URLs
docker tag astrolock-cli:latest ACCOUNT.dkr.ecr.us-east-1.amazonaws.com/astrolock-cli:latest
docker push ACCOUNT.dkr.ecr.us-east-1.amazonaws.com/astrolock-cli:latestNext Steps
Create site provisioner:
make create-user USER=yourname GROUP=astrolock-sites-provisioners
make create-access-key USER=yourname
aws configure --profile astrolock-sites-provisioner
Tip
Use astrolock-sites-provisioner as profile name for consistency.
Then: Provision sites → Deploy content → Automate deployments
Alternative: Direct Admin Bootstrap
export AWS_PROFILE=admin # Use your admin profile
cd terraform/astrolock_backend
make bootstrap-init && make plan && make bootstrap-apply && make migrate-state
make create-user USER=yourname GROUP=astrolock-backend-provisioners
make create-access-key USER=yourname
aws configure --profile astrolock-backend-provisionerIf full admin access unavailable, request this temporary policy:
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["s3:*", "dynamodb:*", "ecr:*", "iam:CreateGroup", "iam:CreatePolicy", "iam:AttachGroupPolicy", "iam:GetGroup", "iam:GetPolicy", "iam:ListAttachedGroupPolicies"],
"Resource": "*"
}]
}Troubleshooting
- Access Denied in CloudShell: Verify admin account with
aws sts get-caller-identity - User Already Exists: Delete user with
aws iam delete-access-key/delete-user, re-run script - Terraform Permission Denied: Check
$AWS_PROFILEandaws sts get-caller-identity - ECR Errors: Verify profile and check attached policies with
aws iam list-attached-user-policies
Cost Estimate
$0.07/month: S3 state ($0.01), DynamoDB locking ($0.01), ECR images ($0.05)
Security
- Least privilege: Users get minimum permissions, resources scoped to astrolock namespace
- Encryption: S3 (AES256), DynamoDB at-rest, ECR images with scanning
- Audit: S3 versioning, DynamoDB locking, CloudTrail logging
Reference
See terraform/astrolock_backend/: bootstrap-cloudshell.sh, CLOUDSHELL-SETUP.md, BOOTSTRAP.md, README.md, Makefile