diff --git a/iac-template/terraform-standard/README.md b/iac-template/terraform-standard/README.md index dd8e9f8b..94bb7342 100644 --- a/iac-template/terraform-standard/README.md +++ b/iac-template/terraform-standard/README.md @@ -78,7 +78,17 @@ This creates: PAY_PER_REQUEST billing mode Compatible with Terraform backend locking -## 4. Use in Terraform Backend +## 4. Bootstrap IAM Role + +``` +cd bootstrap-iam +terraform init +terraform apply \ + -var="account_name=dev" \ + -var="role_name=TerraformDeployRole-Dev" +``` + +## 5. Use in Terraform Backend After both bootstrap steps are completed: @@ -92,7 +102,6 @@ terraform { } } - Then run: terraform init -migrate-state diff --git a/iac-template/terraform-standard/backend.tf b/iac-template/terraform-standard/backend.tf deleted file mode 100644 index c951a79a..00000000 --- a/iac-template/terraform-standard/backend.tf +++ /dev/null @@ -1,8 +0,0 @@ -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-iam/.gitignore b/iac-template/terraform-standard/bootstrap-iam/.gitignore new file mode 100644 index 00000000..5e697082 --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-iam/.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-iam/main.tf b/iac-template/terraform-standard/bootstrap-iam/main.tf new file mode 100644 index 00000000..f9c384da --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-iam/main.tf @@ -0,0 +1,28 @@ +resource "aws_iam_role" "terraform_deploy_role" { + name = var.role_name + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Principal = { + AWS = "arn:aws:iam::${local.account.account_id}:root" + } + Action = "sts:AssumeRole" + }] + }) + + tags = merge( + { + Name = var.role_name + Environment = local.account.environment + }, + local.account.tags + ) +} + +# 当前阶段给 Admin 权限(你熟悉后可以缩小) +resource "aws_iam_role_policy_attachment" "attach_admin" { + role = aws_iam_role.terraform_deploy_role.name + policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess" +} diff --git a/iac-template/terraform-standard/bootstrap-iam/outputs.tf b/iac-template/terraform-standard/bootstrap-iam/outputs.tf new file mode 100644 index 00000000..8ee7d701 --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-iam/outputs.tf @@ -0,0 +1,3 @@ +output "role_arn" { + value = aws_iam_role.terraform_deploy_role.arn +} diff --git a/iac-template/terraform-standard/bootstrap-iam/provider.tf b/iac-template/terraform-standard/bootstrap-iam/provider.tf new file mode 100644 index 00000000..e546cc02 --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-iam/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-iam/variables.tf b/iac-template/terraform-standard/bootstrap-iam/variables.tf new file mode 100644 index 00000000..2dfb863f --- /dev/null +++ b/iac-template/terraform-standard/bootstrap-iam/variables.tf @@ -0,0 +1,21 @@ +variable "region" { + description = "AWS region" + type = string +} + +variable "account_name" { + type = string + description = "Which account configuration to load (e.g., dev)" +} + +variable "role_name" { + type = string + description = "IAM role name to create (e.g., TerraformDeployRole-Dev)" +} + +locals { + account = yamldecode( + file("${path.root}/../config/accounts/${var.account_name}.yaml") + ) +} + diff --git a/iac-template/terraform-standard/config/accounts/dev.yaml b/iac-template/terraform-standard/config/accounts/dev.yaml new file mode 100644 index 00000000..3c488f6f --- /dev/null +++ b/iac-template/terraform-standard/config/accounts/dev.yaml @@ -0,0 +1,20 @@ +account_id: "730335654753" # 目前单账号 +name: dev +environment: dev + +region: ap-northeast-1 + +role_to_assume: arn:aws:iam::730335654753:role/TerraformDeployRole-Dev + +logging_bucket: org-dev-logs +shared_vpc_account: "730335654753" # 单账号,所以保持一致 + +tags: + Environment: dev + Owner: Platform + CostCenter: "DEV" + +backend: + bucket: svc-plus-iac-state + key_prefix: dev/ + dynamodb_table: svc-plus-iac-state-dynamodb-lock diff --git a/iac-template/terraform-standard/envs/dev/.gitignore b/iac-template/terraform-standard/envs/dev/.gitignore new file mode 100644 index 00000000..5e697082 --- /dev/null +++ b/iac-template/terraform-standard/envs/dev/.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/envs/dev/backend.tf b/iac-template/terraform-standard/envs/dev/backend.tf new file mode 100644 index 00000000..b3af6821 --- /dev/null +++ b/iac-template/terraform-standard/envs/dev/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "svc-plus-iac-state" + key = "account/iam/dev/terraform.tfstate" + region = "ap-northeast-1" + dynamodb_table = "svc-plus-iac-state-dynamodb-lock" + } +} + diff --git a/iac-template/terraform-standard/envs/dev/main.tf b/iac-template/terraform-standard/envs/dev/main.tf new file mode 100644 index 00000000..11371a9f --- /dev/null +++ b/iac-template/terraform-standard/envs/dev/main.tf @@ -0,0 +1,11 @@ +locals { + account = yamldecode( + file("${path.root}/../../config/accounts/dev.yaml") + ) +} + +# 第一个正式 module:iam +module "iam" { + source = "../../modules/iam" + account = local.account # << 唯一需要传入 module 的变量 +} diff --git a/iac-template/terraform-standard/envs/dev/outputs.tf b/iac-template/terraform-standard/envs/dev/outputs.tf new file mode 100644 index 00000000..567f1a7f --- /dev/null +++ b/iac-template/terraform-standard/envs/dev/outputs.tf @@ -0,0 +1,9 @@ +output "iam_role_arn" { + description = "IAM role ARN created for Terraform deployment" + value = module.iam.role_arn +} + +output "iam_role_name" { + description = "IAM role name" + value = module.iam.role_name +} diff --git a/iac-template/terraform-standard/envs/dev/provider.tf b/iac-template/terraform-standard/envs/dev/provider.tf new file mode 100644 index 00000000..212806de --- /dev/null +++ b/iac-template/terraform-standard/envs/dev/provider.tf @@ -0,0 +1,20 @@ +terraform { + required_version = ">= 1.2" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.92.0" + } + } +} + +provider "aws" { + region = "ap-northeast-1" + + assume_role { + role_arn = "arn:aws:iam::730335654753:role/TerraformDeployRole-Dev" + session_name = "TerraformDevSession" + } +} + diff --git a/iac-template/terraform-standard/modules/iam/.gitignore b/iac-template/terraform-standard/modules/iam/.gitignore new file mode 100644 index 00000000..5e697082 --- /dev/null +++ b/iac-template/terraform-standard/modules/iam/.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/modules/iam/main.tf b/iac-template/terraform-standard/modules/iam/main.tf new file mode 100644 index 00000000..3d80c910 --- /dev/null +++ b/iac-template/terraform-standard/modules/iam/main.tf @@ -0,0 +1,18 @@ +resource "aws_iam_role" "this" { + name = var.role_name + + assume_role_policy = data.aws_iam_policy_document.assume.json + + tags = var.tags +} + +data "aws_iam_policy_document" "assume" { + statement { + actions = ["sts:AssumeRole"] + + principals { + type = "AWS" + identifiers = ["*"] # 你可以未来改为 OIDC provider 等 + } + } +} diff --git a/iac-template/terraform-standard/modules/iam/outputs.tf b/iac-template/terraform-standard/modules/iam/outputs.tf new file mode 100644 index 00000000..e01d61bc --- /dev/null +++ b/iac-template/terraform-standard/modules/iam/outputs.tf @@ -0,0 +1,3 @@ +output "role_arn" { + value = aws_iam_role.this.arn +} diff --git a/iac-template/terraform-standard/modules/iam/provider.tf b/iac-template/terraform-standard/modules/iam/provider.tf new file mode 100644 index 00000000..300cbef7 --- /dev/null +++ b/iac-template/terraform-standard/modules/iam/provider.tf @@ -0,0 +1,25 @@ +locals { + account = yamldecode( + file("${path.root}/../../config/accounts/dev.yaml") + ) +} + +terraform { + required_version = ">= 1.2" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.92.0" + } + } +} + +provider "aws" { + region = var.region + + assume_role { + role_arn = "local.account.role_to_assume" + session_name = "TerraformDevSession" + } +} diff --git a/iac-template/terraform-standard/modules/iam/variables.tf b/iac-template/terraform-standard/modules/iam/variables.tf new file mode 100644 index 00000000..f90d91e4 --- /dev/null +++ b/iac-template/terraform-standard/modules/iam/variables.tf @@ -0,0 +1,18 @@ +variable "account" { + type = object({ + account_id = string + name = string + environment = string + region = string + role_to_assume = string + logging_bucket = string + shared_vpc_account = string + backend = object({ + bucket = string + key_prefix = string + dynamodb_table = string + }) + tags = map(string) + }) +} +