One-time procedure to create the Terraform state backend and bring it under Terraform management.
- AWS CLI v2 installed
- AWS profile
javabinconfigured (Identity Center SSO or IAM credentials) - Permissions:
s3:*,dynamodb:*in eu-central-1 - Terraform >= 1.7 installed
cd /path/to/javaBin/platform
./scripts/bootstrap.shThis creates four resources via AWS CLI:
javabin-terraform-state-553637109631(S3 bucket, versioned, KMS encrypted, public blocked)javabin-terraform-infra-lock(DynamoDB table, PAY_PER_REQUEST)javabin-terraform-app-locks(DynamoDB table, PAY_PER_REQUEST)javabin-ci-plan-artifacts-553637109631(S3 bucket, public blocked, 24h lifecycle)
cd terraform/state
terraform initThe backend.tf starts as backend "local" {}. This is intentional -- we need local state to import the bootstrapped resources.
Import the resources created by the bootstrap script into Terraform state:
# State bucket
terraform import aws_s3_bucket.state javabin-terraform-state-553637109631
terraform import aws_s3_bucket_versioning.state javabin-terraform-state-553637109631
terraform import aws_s3_bucket_server_side_encryption_configuration.state javabin-terraform-state-553637109631
terraform import aws_s3_bucket_public_access_block.state javabin-terraform-state-553637109631
# Infra lock table
terraform import aws_dynamodb_table.infra_lock javabin-terraform-infra-lock
# App lock table
terraform import aws_dynamodb_table.app_locks javabin-terraform-app-locks
# Plan artifacts bucket
terraform import aws_s3_bucket.plan_artifacts javabin-ci-plan-artifacts-553637109631
terraform import aws_s3_bucket_public_access_block.plan_artifacts javabin-ci-plan-artifacts-553637109631
terraform import aws_s3_bucket_lifecycle_configuration.plan_artifacts javabin-ci-plan-artifacts-553637109631terraform planThe plan should show no changes (or very minor drift to reconcile). Fix any differences before proceeding.
Edit terraform/state/backend.tf. Replace the entire file with:
terraform {
backend "s3" {
bucket = "javabin-terraform-state-553637109631"
key = "state/terraform.tfstate"
region = "eu-central-1"
dynamodb_table = "javabin-terraform-infra-lock"
encrypt = true
}
}terraform init -migrate-stateTerraform will ask to copy the local state to S3. Confirm with yes.
rm -f terraform.tfstate terraform.tfstate.backupterraform planShould show no changes, and state is now stored in S3.
cd ../..
git add terraform/state/ scripts/bootstrap.sh docs/bootstrap-runbook.md
git commit -m "Bootstrap state backend: S3 + DynamoDB + plan artifacts"After bootstrap, the state bucket holds:
javabin-terraform-state-553637109631/
state/terraform.tfstate # this module (state management)
infra/terraform.tfstate # platform module (Phase 2+)
org/terraform.tfstate # org module (SCPs, Organizations)
apps/{repo-name}/terraform.tfstate # one per registered app repo
"BucketAlreadyOwnedByYou": The bootstrap script is idempotent for bucket creation. If the bucket already exists in your account, this error is harmless. Proceed with the remaining steps.
DynamoDB table already exists: If a table already exists, the create-table call will fail. Skip that step and proceed with the import.
Import drift: If terraform plan shows changes after import, review them carefully. Minor attribute differences (e.g., tags) are expected and safe to apply.