feat(terraform-standard): add S3 and DynamoDB bootstrap modules with backend setup

This commit is contained in:
Haitao Pan 2025-11-16 21:59:42 +08:00
parent 4b7789265c
commit f7960153fe
13 changed files with 294 additions and 0 deletions

View File

@ -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

View File

@ -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
}
}

View File

@ -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

View File

@ -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"
}
}

View File

@ -0,0 +1,5 @@
output "dynamodb_table_name" {
description = "The name of the DynamoDB state lock table"
value = aws_dynamodb_table.terraform_locks.name
}

View File

@ -0,0 +1,14 @@
terraform {
required_version = ">= 1.2"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.92"
}
}
}
provider "aws" {
region = var.region
}

View File

@ -0,0 +1,9 @@
variable "table_name" {
description = "DynamoDB table name for Terraform state lock"
type = string
}
variable "region" {
description = "AWS region"
type = string
}

View File

@ -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

View File

@ -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

View File

@ -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"
}
}
}

View File

@ -0,0 +1,3 @@
output "bucket_name" {
value = aws_s3_bucket.state.bucket
}

View File

@ -0,0 +1,14 @@
terraform {
required_version = ">= 1.2"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.92"
}
}
}
provider "aws" {
region = var.region
}

View File

@ -0,0 +1,9 @@
variable "bucket_name" {
description = "S3 bucket name for Terraform state"
type = string
}
variable "region" {
description = "AWS region"
type = string
}