diff --git a/iac-template/terraform-standard/README.md b/iac-template/terraform-standard/README.md new file mode 100644 index 00000000..dd8e9f8b --- /dev/null +++ b/iac-template/terraform-standard/README.md @@ -0,0 +1,132 @@ +# Terraform Bootstrap for S3 Backend & DynamoDB Lock Table + +This repository provides bootstrap Terraform modules that must be applied before enabling a Terraform remote backend on AWS. +It creates: +- S3 bucket — to store Terraform remote state +- DynamoDB table — to store Terraform state locks + +Both modules can be run independently. + +- bootstrap-s3/ # S3 state bucket (versioning + SSE) +- bootstrap-dynamodb/ # DynamoDB lock table (LockID) + +--- +** Note: S3 bucket must be emptied before deletion. ** + +## 1. AWS Credentials Setup + +Terraform reads AWS credentials through the standard AWS credential chain. You may use either A or B. + +### A. Environment Variables (recommended for local / CI) + +``` +export AWS_ACCESS_KEY_ID="AKIAxxxxxxxxxxxx" +export AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxxxxxx" +export AWS_DEFAULT_REGION="ap-northeast-1" +``` + +Terraform will automatically detect them. + +### B. AWS CLI Credentials File (~/.aws/credentials) + +- Run: aws configure +- Credentials file: ~/.aws/credentials + +``` +Example: +[default] +aws_access_key_id = AKIAxxxxxxxxxxxx +aws_secret_access_key = xxxxxxxxxxxxxxxxx +region = ap-northeast-1 +``` + +Select profile if needed: export AWS_PROFILE=default + +## 2. Bootstrap: Create S3 Bucket + +``` +cd bootstrap-s3 +terraform init +terraform apply \ + -var="bucket_name=svc-plus-iac-state" \ + -var="region=ap-northeast-1" +``` + +This creates: +- S3 bucket for Terraform state +- Versioning enabled +- Server-side encryption (AES256) enabled + +## 3. Bootstrap: Create DynamoDB Lock Table + +``` +cd bootstrap-dynamo-db +terraform init +terraform plan \ + -var="region=ap-northeast-1" \ + -var="table_name=svc-plus-iac-state-dynamodb-lock" +terraform apply \ + -var="region=ap-northeast-1" \ + -var="table_name=svc-plus-iac-state-dynamodb-lock" +terraform output +``` + +This creates: + +- DynamoDB table: terraform-locks +- Primary key: LockID + +PAY_PER_REQUEST billing mode Compatible with Terraform backend locking + +## 4. Use in Terraform Backend + +After both bootstrap steps are completed: + +terraform { + backend "s3" { + bucket = "my-terraform-state" + key = "envs/dev/terraform.tfstate" + region = "ap-northeast-1" + encrypt = true + dynamodb_table = "terraform-locks" + } +} + + +Then run: + +terraform init -migrate-state + +5. Security Notes + +Never store AWS credentials in Terraform variables +Never commit credentials to Git + +Prefer: + +- environment variables +- AWS CLI profiles +- IAM Role / SSO / OIDC (recommended) +- S3 bucket has: Versioning ON + +Server-side encryption ON + +## 6. Cleanup + +To remove bootstrap resources: + +terraform destroy + + +# Access Key + STS 的执行流程(内部机制) + +你的 Terraform 执行流程变成: + +Terraform 读取你的 Access Key +→ 用 GET CALLER IDENTITY 验证身份 +调用 sts:AssumeRole +获得临时凭证(Session Token) +Terraform 使用临时凭证执行所有资源创建 + +AccessKey → STS → AssumeRole → 临时 Token → Terraform apply + diff --git a/iac-template/terraform-standard/backend.tf b/iac-template/terraform-standard/backend.tf new file mode 100644 index 00000000..c951a79a --- /dev/null +++ b/iac-template/terraform-standard/backend.tf @@ -0,0 +1,8 @@ +terraform { + backend "s3" { + bucket = "svc-plus-iac-state" + key = "sit/ec2/terraform.tfstate" + region = "svc-plus-iac-state-locks" + encrypt = true + } +} diff --git a/iac-template/terraform-standard/bootstrap-dynamodb/.gitignore b/iac-template/terraform-standard/bootstrap-dynamodb/.gitignore new file mode 100644 index 00000000..5e697082 --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-dynamodb/.gitignore @@ -0,0 +1,25 @@ +# Local terraform files +.terraform/ +.terraform.lock.hcl +terraform.tfstate +terraform.tfstate.backup + +# Auto tfvars generated by CI/CD or sensitive data +*.tfvars +*.auto.tfvars +*.tfvars.json + +# IDE / editor files +.idea/ +.vscode/ +*.swp + +# AWS credentials — never commit +.aws/ +credentials +config + +# OS-specific +.DS_Store +Thumbs.db + diff --git a/iac-template/terraform-standard/bootstrap-dynamodb/main.tf b/iac-template/terraform-standard/bootstrap-dynamodb/main.tf new file mode 100644 index 00000000..65f040ea --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-dynamodb/main.tf @@ -0,0 +1,16 @@ +resource "aws_dynamodb_table" "terraform_locks" { + name = var.table_name + billing_mode = "PAY_PER_REQUEST" + + hash_key = "LockID" + + attribute { + name = "LockID" + type = "S" + } + + tags = { + Name = var.table_name + Environment = "bootstrap" + } +} diff --git a/iac-template/terraform-standard/bootstrap-dynamodb/outputs.tf b/iac-template/terraform-standard/bootstrap-dynamodb/outputs.tf new file mode 100644 index 00000000..9a5ed80f --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-dynamodb/outputs.tf @@ -0,0 +1,5 @@ +output "dynamodb_table_name" { + description = "The name of the DynamoDB state lock table" + value = aws_dynamodb_table.terraform_locks.name +} + diff --git a/iac-template/terraform-standard/bootstrap-dynamodb/provider.tf b/iac-template/terraform-standard/bootstrap-dynamodb/provider.tf new file mode 100644 index 00000000..e546cc02 --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-dynamodb/provider.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.2" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.92" + } + } +} + +provider "aws" { + region = var.region +} diff --git a/iac-template/terraform-standard/bootstrap-dynamodb/variables.tf b/iac-template/terraform-standard/bootstrap-dynamodb/variables.tf new file mode 100644 index 00000000..5c755078 --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-dynamodb/variables.tf @@ -0,0 +1,9 @@ +variable "table_name" { + description = "DynamoDB table name for Terraform state lock" + type = string +} + +variable "region" { + description = "AWS region" + type = string +} diff --git a/iac-template/terraform-standard/bootstrap-s3/... b/iac-template/terraform-standard/bootstrap-s3/... new file mode 100644 index 00000000..b9f7f22e --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-s3/... @@ -0,0 +1,13 @@ +cd bootstrap-s3 + +export AWS_ACCESS_KEY_ID="AKIAxxxxxxxx" +export AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxx" +export AWS_DEFAULT_REGION="ap-northeast-1" + +terraform init +terraform apply \ + -var="bucket_name=my-terraform-state" \ + -var="region=ap-northeast-1" + + +~/.aws/credentials diff --git a/iac-template/terraform-standard/bootstrap-s3/.gitignore b/iac-template/terraform-standard/bootstrap-s3/.gitignore new file mode 100644 index 00000000..5e697082 --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-s3/.gitignore @@ -0,0 +1,25 @@ +# Local terraform files +.terraform/ +.terraform.lock.hcl +terraform.tfstate +terraform.tfstate.backup + +# Auto tfvars generated by CI/CD or sensitive data +*.tfvars +*.auto.tfvars +*.tfvars.json + +# IDE / editor files +.idea/ +.vscode/ +*.swp + +# AWS credentials — never commit +.aws/ +credentials +config + +# OS-specific +.DS_Store +Thumbs.db + diff --git a/iac-template/terraform-standard/bootstrap-s3/main.tf b/iac-template/terraform-standard/bootstrap-s3/main.tf new file mode 100644 index 00000000..0e8dbdc4 --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-s3/main.tf @@ -0,0 +1,21 @@ +resource "aws_s3_bucket" "state" { + bucket = var.bucket_name +} + +resource "aws_s3_bucket_versioning" "versioning" { + bucket = aws_s3_bucket.state.id + + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "sse" { + bucket = aws_s3_bucket.state.id + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} diff --git a/iac-template/terraform-standard/bootstrap-s3/outputs.tf b/iac-template/terraform-standard/bootstrap-s3/outputs.tf new file mode 100644 index 00000000..1c95c75b --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-s3/outputs.tf @@ -0,0 +1,3 @@ +output "bucket_name" { + value = aws_s3_bucket.state.bucket +} diff --git a/iac-template/terraform-standard/bootstrap-s3/provider.tf b/iac-template/terraform-standard/bootstrap-s3/provider.tf new file mode 100644 index 00000000..e546cc02 --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-s3/provider.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.2" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.92" + } + } +} + +provider "aws" { + region = var.region +} diff --git a/iac-template/terraform-standard/bootstrap-s3/variables.tf b/iac-template/terraform-standard/bootstrap-s3/variables.tf new file mode 100644 index 00000000..1d3e689b --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-s3/variables.tf @@ -0,0 +1,9 @@ +variable "bucket_name" { + description = "S3 bucket name for Terraform state" + type = string +} + +variable "region" { + description = "AWS region" + type = string +}