From 3765f0192c6d0cd1a667dbb8a466430a223d655f Mon Sep 17 00:00:00 2001 From: Haitao Pan Date: Fri, 21 Nov 2025 13:33:11 +0800 Subject: [PATCH] feat(iac): add full multi-cloud Terraform HCL frameworks (AliCloud/Azure/GCP/Vultr) - Introduce complete terraform-hcl-standard directory for 4 cloud providers - Add bootstrap (iam/oss/ots/s3), config, envs/dev templates - Add core modules: vpc, ecs/compute, nlb/alb, redis, rds, object-storage - Provide initial README for each provider --- .../ali-cloud/README.md | 31 ++++ .../ali-cloud/bootstrap-oss/main.tf | 29 ++++ .../ali-cloud/bootstrap-oss/variables.tf | 16 ++ .../ali-cloud/bootstrap-ots/main.tf | 35 +++++ .../ali-cloud/bootstrap-ots/variables.tf | 17 +++ .../ali-cloud/bootstrap-ram/main.tf | 104 +++++++++++++ .../ali-cloud/bootstrap-ram/variables.tf | 28 ++++ .../ali-cloud/config/backend.tf | 10 ++ .../ali-cloud/config/provider.tf | 23 +++ .../ali-cloud/config/variables.tf | 54 +++++++ .../ali-cloud/envs/dev/main.tf | 99 ++++++++++++ .../ali-cloud/envs/dev/variables.tf | 71 +++++++++ .../ali-cloud/modules/alb/main.tf | 49 ++++++ .../ali-cloud/modules/alb/variables.tf | 41 +++++ .../ali-cloud/modules/ecs/main.tf | 37 +++++ .../ali-cloud/modules/ecs/variables.tf | 62 ++++++++ .../ali-cloud/modules/nlb/main.tf | 34 +++++ .../ali-cloud/modules/nlb/variables.tf | 39 +++++ .../ali-cloud/modules/oss/main.tf | 16 ++ .../ali-cloud/modules/oss/variables.tf | 22 +++ .../ali-cloud/modules/ram/main.tf | 45 ++++++ .../ali-cloud/modules/ram/variables.tf | 31 ++++ .../ali-cloud/modules/rds/main.tf | 33 ++++ .../ali-cloud/modules/rds/variables.tf | 69 +++++++++ .../ali-cloud/modules/redis/main.tf | 17 +++ .../ali-cloud/modules/redis/variables.tf | 32 ++++ .../ali-cloud/modules/vpc/main.tf | 20 +++ .../ali-cloud/modules/vpc/variables.tf | 18 +++ .../azure-cloud/README.md | 33 ++++ .../azure-cloud/bootstrap-dynamodb/main.tf | 68 +++++++++ .../azure-cloud/bootstrap-iam/main.tf | 50 ++++++ .../azure-cloud/bootstrap-s3/main.tf | 63 ++++++++ .../azure-cloud/config/backend.tf | 9 ++ .../azure-cloud/config/provider.tf | 15 ++ .../azure-cloud/config/variables.tf | 15 ++ .../azure-cloud/envs/dev/main.tf | 142 +++++++++++++++++ .../azure-cloud/modules/alb/main.tf | 114 ++++++++++++++ .../azure-cloud/modules/ami_lookup/main.tf | 40 +++++ .../azure-cloud/modules/ec2/main.tf | 104 +++++++++++++ .../azure-cloud/modules/iam/main.tf | 31 ++++ .../azure-cloud/modules/keypair/main.tf | 27 ++++ .../azure-cloud/modules/landingzone/main.tf | 45 ++++++ .../azure-cloud/modules/msk/main.tf | 58 +++++++ .../azure-cloud/modules/nlb/main.tf | 101 ++++++++++++ .../azure-cloud/modules/rds/main.tf | 95 ++++++++++++ .../azure-cloud/modules/redis/main.tf | 48 ++++++ .../azure-cloud/modules/s3/main.tf | 46 ++++++ .../azure-cloud/modules/sg/main.tf | 69 +++++++++ .../azure-cloud/modules/vpc/main.tf | 62 ++++++++ .../gcp-cloud/README.md | 32 ++++ .../gcp-cloud/bootstrap-dynamodb/main.tf | 42 +++++ .../gcp-cloud/bootstrap-iam/main.tf | 47 ++++++ .../gcp-cloud/bootstrap-s3/main.tf | 47 ++++++ .../gcp-cloud/config/backend.tf | 9 ++ .../gcp-cloud/config/provider.tf | 24 +++ .../gcp-cloud/config/variables.tf | 27 ++++ .../gcp-cloud/envs/dev-alb/main.tf | 27 ++++ .../gcp-cloud/envs/dev-ec2/main.tf | 48 ++++++ .../gcp-cloud/envs/dev-kafka/main.tf | 24 +++ .../gcp-cloud/envs/dev-landingzone/main.tf | 28 ++++ .../gcp-cloud/envs/dev-nlb/main.tf | 43 ++++++ .../gcp-cloud/envs/dev-object/main.tf | 24 +++ .../gcp-cloud/envs/dev-rds/main.tf | 27 ++++ .../gcp-cloud/envs/dev-redis/main.tf | 26 ++++ .../gcp-cloud/envs/dev-role/main.tf | 25 +++ .../gcp-cloud/envs/dev-vpc/main.tf | 33 ++++ .../gcp-cloud/envs/dev/main.tf | 34 +++++ .../gcp-cloud/modules/alb/main.tf | 59 +++++++ .../gcp-cloud/modules/ami_lookup/main.tf | 21 +++ .../gcp-cloud/modules/ec2/main.tf | 70 +++++++++ .../gcp-cloud/modules/iam/main.tf | 25 +++ .../gcp-cloud/modules/keypair/main.tf | 36 +++++ .../gcp-cloud/modules/landingzone/main.tf | 26 ++++ .../gcp-cloud/modules/msk/main.tf | 36 +++++ .../gcp-cloud/modules/nlb/main.tf | 78 ++++++++++ .../gcp-cloud/modules/rds/main.tf | 44 ++++++ .../gcp-cloud/modules/redis/main.tf | 41 +++++ .../gcp-cloud/modules/s3/main.tf | 28 ++++ .../gcp-cloud/modules/sg/main.tf | 45 ++++++ .../gcp-cloud/modules/vpc/main.tf | 51 +++++++ .../vultr-vps/README.md | 36 +++++ .../vultr-vps/bootstrap-iam/main.tf | 70 +++++++++ .../bootstrap-object-storage/main.tf | 85 +++++++++++ .../vultr-vps/config/backend.tf | 46 ++++++ .../vultr-vps/config/provider.tf | 21 +++ .../vultr-vps/envs/dev/cloud-init.yaml | 6 + .../vultr-vps/envs/dev/main.tf | 80 ++++++++++ .../vultr-vps/envs/dev/variables.tf | 144 ++++++++++++++++++ .../vultr-vps/modules/compute/main.tf | 84 ++++++++++ .../vultr-vps/modules/data_store/main.tf | 72 +++++++++ .../vultr-vps/modules/iam/main.tf | 42 +++++ .../vultr-vps/modules/storage/main.tf | 80 ++++++++++ .../vultr-vps/modules/vpc/main.tf | 32 ++++ 93 files changed, 4242 insertions(+) create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/README.md create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/bootstrap-oss/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/bootstrap-oss/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ots/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ots/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ram/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ram/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/config/backend.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/config/provider.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/config/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/envs/dev/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/envs/dev/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/alb/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/alb/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/ecs/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/ecs/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/nlb/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/nlb/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/oss/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/oss/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/ram/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/ram/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/rds/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/rds/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/redis/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/redis/variables.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/vpc/main.tf create mode 100644 iac-template/terraform-hcl-standard/ali-cloud/modules/vpc/variables.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/README.md create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/bootstrap-dynamodb/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/bootstrap-iam/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/bootstrap-s3/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/config/backend.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/config/provider.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/config/variables.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/envs/dev/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/alb/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/ami_lookup/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/ec2/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/iam/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/keypair/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/landingzone/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/msk/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/nlb/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/rds/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/redis/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/s3/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/sg/main.tf create mode 100644 iac-template/terraform-hcl-standard/azure-cloud/modules/vpc/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/README.md create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-dynamodb/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-iam/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-s3/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/config/backend.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/config/provider.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/config/variables.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-alb/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-ec2/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-kafka/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-landingzone/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-nlb/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-object/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-rds/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-redis/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-role/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-vpc/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/envs/dev/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/alb/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/ami_lookup/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/ec2/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/iam/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/keypair/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/landingzone/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/msk/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/nlb/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/rds/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/redis/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/s3/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/sg/main.tf create mode 100644 iac-template/terraform-hcl-standard/gcp-cloud/modules/vpc/main.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/README.md create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/bootstrap-iam/main.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/bootstrap-object-storage/main.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/config/backend.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/config/provider.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/envs/dev/cloud-init.yaml create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/envs/dev/main.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/envs/dev/variables.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/modules/compute/main.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/modules/data_store/main.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/modules/iam/main.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/modules/storage/main.tf create mode 100644 iac-template/terraform-hcl-standard/vultr-vps/modules/vpc/main.tf diff --git a/iac-template/terraform-hcl-standard/ali-cloud/README.md b/iac-template/terraform-hcl-standard/ali-cloud/README.md new file mode 100644 index 00000000..3dea3f35 --- /dev/null +++ b/iac-template/terraform-hcl-standard/ali-cloud/README.md @@ -0,0 +1,31 @@ +# Alibaba Cloud Terraform Standard + +该目录提供与 AWS 目录对应的阿里云版本,用于在阿里云上快速引导基础设施。结构与 AWS 模板保持一致,包含引导阶段 (bootstrap)、环境示例 (envs) 与模块库 (modules)。 + +## AWS → Alibaba Cloud 映射 +- **S3 → OSS**:`bootstrap-oss` 创建远端状态桶,开启版本化与服务器端加密。 +- **DynamoDB → TableStore (OTS)**:`bootstrap-ots` 创建状态锁表,用于 Terraform 后端锁定。 +- **IAM → RAM**:`bootstrap-ram` 建立基础访问控制(RAM 角色、策略与用户)。 +- **VPC**:`modules/vpc` 使用专有网络与交换机,替代 AWS VPC/Subnet。 +- **ALB / NLB**:`modules/alb` 和 `modules/nlb` 分别映射到应用型负载均衡 (ALB) 与传统负载均衡 (SLB/NLB)。 +- **EC2 → ECS**:`modules/ecs` 提供计算实例与安全组。 +- **S3 → OSS**:`modules/oss` 作为通用对象存储模块。 +- **IAM → RAM**:`modules/ram` 封装 RAM 角色与策略创建。 +- **RDS / Redis / MSK**:`modules/rds`、`modules/redis` 提供 ApsaraDB 数据库与缓存,Kafka 类似需求可通过云消息队列/中间件扩展。 + +## 使用方式 +1. 在 `config/backend.tf` 中配置远端状态(OSS 桶与可选 OTS 锁表)。 +2. 在 `config/provider.tf` 中设置 `region`、`access_key`、`secret_key` 或 RAM 角色扮演信息,可通过环境变量传入。 +3. 运行引导阶段: + ```bash + terraform -chdir=bootstrap-oss init && terraform -chdir=bootstrap-oss apply + terraform -chdir=bootstrap-ots init && terraform -chdir=bootstrap-ots apply + terraform -chdir=bootstrap-ram init && terraform -chdir=bootstrap-ram apply + ``` +4. 按需修改 `envs/dev` 下的示例,执行: + ```bash + terraform -chdir=envs/dev init + terraform -chdir=envs/dev apply + ``` + +本目录仅新增阿里云模板,不改动现有 AWS/GCP 代码。 diff --git a/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-oss/main.tf b/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-oss/main.tf new file mode 100644 index 00000000..f7b43710 --- /dev/null +++ b/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-oss/main.tf @@ -0,0 +1,29 @@ +terraform { + required_providers { + alicloud = { + source = "aliyun/alicloud" + version = ">= 1.210.0" + } + } +} + +provider "alicloud" { + region = var.region +} + +resource "alicloud_oss_bucket" "state" { + bucket = var.state_bucket + acl = var.acl + + versioning { + status = "Enabled" + } + + server_side_encryption_rule { + sse_algorithm = "AES256" + } +} + +output "bucket" { + value = alicloud_oss_bucket.state.bucket +} diff --git a/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-oss/variables.tf b/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-oss/variables.tf new file mode 100644 index 00000000..4fe7aced --- /dev/null +++ b/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-oss/variables.tf @@ -0,0 +1,16 @@ +variable "region" { + description = "Alibaba Cloud region for OSS" + type = string + default = "cn-hangzhou" +} + +variable "state_bucket" { + description = "Name of the OSS bucket used for remote state" + type = string +} + +variable "acl" { + description = "ACL for the OSS bucket" + type = string + default = "private" +} diff --git a/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ots/main.tf b/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ots/main.tf new file mode 100644 index 00000000..2146acd3 --- /dev/null +++ b/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ots/main.tf @@ -0,0 +1,35 @@ +terraform { + required_providers { + alicloud = { + source = "aliyun/alicloud" + version = ">= 1.210.0" + } + } +} + +provider "alicloud" { + region = var.region +} + +resource "alicloud_ots_instance" "this" { + instance_name = var.instance_name + description = "Terraform state locking" + accessed_by = "Any" +} + +resource "alicloud_ots_table" "lock" { + instance_name = alicloud_ots_instance.this.name + table_name = var.table_name + + time_to_live = -1 + max_version = 1 + + primary_key { + name = "LockID" + type = "STRING" + } +} + +output "lock_table" { + value = alicloud_ots_table.lock.table_name +} diff --git a/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ots/variables.tf b/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ots/variables.tf new file mode 100644 index 00000000..883f405c --- /dev/null +++ b/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ots/variables.tf @@ -0,0 +1,17 @@ +variable "region" { + description = "Alibaba Cloud region for OTS" + type = string + default = "cn-hangzhou" +} + +variable "instance_name" { + description = "Name of the OTS instance" + type = string + default = "terraform-locks" +} + +variable "table_name" { + description = "Name of the lock table" + type = string + default = "terraform-locks" +} diff --git a/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ram/main.tf b/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ram/main.tf new file mode 100644 index 00000000..2cc785f8 --- /dev/null +++ b/iac-template/terraform-hcl-standard/ali-cloud/bootstrap-ram/main.tf @@ -0,0 +1,104 @@ +terraform { + required_providers { + alicloud = { + source = "aliyun/alicloud" + version = ">= 1.210.0" + } + } +} + +provider "alicloud" { + region = var.region +} + +locals { + assume_principal = "acs:ram::${var.account_id}:root" +} + +resource "alicloud_ram_role" "terraform" { + name = var.role_name + document = < v.id } +} diff --git a/iac-template/terraform-hcl-standard/ali-cloud/modules/vpc/variables.tf b/iac-template/terraform-hcl-standard/ali-cloud/modules/vpc/variables.tf new file mode 100644 index 00000000..0ca7ac0f --- /dev/null +++ b/iac-template/terraform-hcl-standard/ali-cloud/modules/vpc/variables.tf @@ -0,0 +1,18 @@ +variable "name" { + description = "Name of the VPC" + type = string +} + +variable "cidr_block" { + description = "CIDR block for the VPC" + type = string + default = "10.0.0.0/16" +} + +variable "vswitches" { + description = "Map of vswitches with cidr and az, e.g. { a = { cidr = \"10.0.1.0/24\", az = \"cn-hangzhou-b\" } }" + type = map(object({ + cidr = string + az = string + })) +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/README.md b/iac-template/terraform-hcl-standard/azure-cloud/README.md new file mode 100644 index 00000000..0ec9456c --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/README.md @@ -0,0 +1,33 @@ +# Azure Cloud Terraform Standard + +该目录提供与 `aws-cloud` 模板一一对应的 Azure 版本,延续相同的目录与模块命名(bootstrap、config、modules、envs),便于将 AWS 使用习惯映射到 Azure。 + +## 模板映射(AWS → Azure) +- **bootstrap-s3 → Storage Account**:创建存储账户与容器用于 Terraform 远端状态。 +- **bootstrap-dynamodb → Cosmos DB Table API**:提供无服务器键值表存储。 +- **bootstrap-iam → RBAC 角色分配**:为指定主体分配内置角色,替代 AWS IAM 角色/策略。 +- **modules**:保留 AWS 模块命名,内部实现替换为 Azure 服务: + - `vpc`:虚拟网络 + 子网(Virtual Network/Subnet)。 + - `alb`:应用程序网关(Application Gateway)。 + - `nlb`:标准负载均衡器(Standard Load Balancer)。 + - `ec2`:Linux 虚拟机(Virtual Machine)。 + - `s3`:存储账户与容器(Storage Account + Container)。 + - `rds`:PostgreSQL 灵活服务器(Flexible Server)。 + - `redis`:Azure Cache for Redis。 + - `sg`:网络安全组与规则(Network Security Group)。 + - `iam`:基于内置角色的角色分配(Role Assignment)。 + - `ami_lookup`:公共镜像查找(Ubuntu 平台镜像)。 + - `landingzone`:基础资源组与日志工作区。 + - `keypair`:生成 SSH 密钥对。 + - `msk`:事件中心命名空间与 Hub(Event Hubs)。 + +## 使用方式 +1. 在 `config/backend.tf` 中配置 Azure 存储作为 Terraform 远端状态(资源组、存储账户、容器)。 +2. 在 `config/provider.tf` 中设置 `subscription_id`、`tenant_id`、`location` 等参数。 +3. 参考 `envs/dev/main.tf`,按需修改变量后执行: + ```bash + terraform -chdir=envs/dev init + terraform -chdir=envs/dev apply + ``` + +本目录新增 Azure 代码,不改动现有 AWS 模板。 diff --git a/iac-template/terraform-hcl-standard/azure-cloud/bootstrap-dynamodb/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/bootstrap-dynamodb/main.tf new file mode 100644 index 00000000..df2a9be5 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/bootstrap-dynamodb/main.tf @@ -0,0 +1,68 @@ +variable "resource_group_name" { + description = "Resource group for the Cosmos DB account" + type = string +} + +variable "location" { + description = "Azure region" + type = string + default = "eastus" +} + +variable "account_name" { + description = "Cosmos DB account name" + type = string +} + +variable "table_name" { + description = "Table (Table API) name" + type = string + default = "tfstate-lock" +} + +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "cosmos" { + name = var.resource_group_name + location = var.location +} + +resource "azurerm_cosmosdb_account" "table" { + name = var.account_name + location = azurerm_resource_group.cosmos.location + resource_group_name = azurerm_resource_group.cosmos.name + offer_type = "Standard" + kind = "GlobalDocumentDB" + + consistency_policy { + consistency_level = "Session" + } + + capabilities { + name = "EnableTable" + } + + geo_location { + location = azurerm_resource_group.cosmos.location + failover_priority = 0 + } +} + +resource "azurerm_cosmosdb_table" "state_lock" { + name = var.table_name + resource_group_name = azurerm_resource_group.cosmos.name + account_name = azurerm_cosmosdb_account.table.name + throughput = 400 +} + +output "account" { + value = azurerm_cosmosdb_account.table.name + description = "Cosmos DB account for lock table" +} + +output "table" { + value = azurerm_cosmosdb_table.state_lock.name + description = "Table API collection used for state locking" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/bootstrap-iam/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/bootstrap-iam/main.tf new file mode 100644 index 00000000..f72e6810 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/bootstrap-iam/main.tf @@ -0,0 +1,50 @@ +variable "resource_group_name" { + description = "Resource group where role assignment is scoped" + type = string +} + +variable "location" { + description = "Azure region" + type = string + default = "eastus" +} + +variable "principal_id" { + description = "Object ID of the user/service principal/group to assign" + type = string +} + +variable "role_definition_name" { + description = "Built-in role to assign" + type = string + default = "Contributor" +} + +provider "azurerm" { + features {} +} + +data "azurerm_role_definition" "selected" { + name = var.role_definition_name +} + +resource "azurerm_resource_group" "iam" { + name = var.resource_group_name + location = var.location +} + +resource "azurerm_role_assignment" "scope_assignment" { + scope = azurerm_resource_group.iam.id + role_definition_id = data.azurerm_role_definition.selected.id + principal_id = var.principal_id +} + +output "role_definition" { + value = data.azurerm_role_definition.selected.name + description = "Role assigned to the principal" +} + +output "scope" { + value = azurerm_resource_group.iam.id + description = "Scope where the role assignment is created" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/bootstrap-s3/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/bootstrap-s3/main.tf new file mode 100644 index 00000000..0f8ef645 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/bootstrap-s3/main.tf @@ -0,0 +1,63 @@ +variable "resource_group_name" { + description = "Resource group for state storage" + type = string + default = "tfstate-rg" +} + +variable "location" { + description = "Azure region" + type = string + default = "eastus" +} + +variable "storage_account_name" { + description = "Storage account name for Terraform state" + type = string + default = "tfstateaccount" +} + +variable "container_name" { + description = "Blob container to store state" + type = string + default = "tfstate" +} + +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "state" { + name = var.resource_group_name + location = var.location +} + +resource "azurerm_storage_account" "state" { + name = var.storage_account_name + resource_group_name = azurerm_resource_group.state.name + location = azurerm_resource_group.state.location + account_tier = "Standard" + account_replication_type = "LRS" + min_tls_version = "TLS1_2" + allow_blob_public_access = false +} + +resource "azurerm_storage_container" "state" { + name = var.container_name + storage_account_name = azurerm_storage_account.state.name + container_access_type = "private" +} + +output "resource_group" { + value = azurerm_resource_group.state.name + description = "Resource group created for Terraform state" +} + +output "storage_account" { + value = azurerm_storage_account.state.name + description = "Storage account for Terraform state" +} + +output "container" { + value = azurerm_storage_container.state.name + description = "Blob container used for Terraform state" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/config/backend.tf b/iac-template/terraform-hcl-standard/azure-cloud/config/backend.tf new file mode 100644 index 00000000..4c106213 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/config/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "azurerm" { + # 请在使用前替换为实际资源组、存储账户、容器和状态文件名 + resource_group_name = "tfstate-rg" + storage_account_name = "tfstateaccount" + container_name = "tfstate" + key = "terraform.tfstate" + } +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/config/provider.tf b/iac-template/terraform-hcl-standard/azure-cloud/config/provider.tf new file mode 100644 index 00000000..190f6f0b --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/config/provider.tf @@ -0,0 +1,15 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 3.90.0" + } + } +} + +provider "azurerm" { + features {} + subscription_id = var.subscription_id + tenant_id = var.tenant_id +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/config/variables.tf b/iac-template/terraform-hcl-standard/azure-cloud/config/variables.tf new file mode 100644 index 00000000..f72a960b --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/config/variables.tf @@ -0,0 +1,15 @@ +variable "subscription_id" { + description = "Azure subscription id" + type = string +} + +variable "tenant_id" { + description = "Azure AD tenant id" + type = string +} + +variable "location" { + description = "Azure region" + type = string + default = "eastus" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/envs/dev/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/envs/dev/main.tf new file mode 100644 index 00000000..061cf049 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/envs/dev/main.tf @@ -0,0 +1,142 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 3.90.0" + } + tls = { + source = "hashicorp/tls" + version = ">= 4.0" + } + } +} + +variable "subscription_id" { + type = string + description = "Target subscription" +} + +variable "tenant_id" { + type = string + description = "AAD tenant id" +} + +variable "location" { + type = string + description = "Azure region" + default = "eastus" +} + +variable "principal_id" { + type = string + description = "Principal to grant Contributor on the landing zone" +} + +provider "azurerm" { + features {} + subscription_id = var.subscription_id + tenant_id = var.tenant_id +} + +locals { + resource_group_name = "demo-rg" + vnet_name = "demo-vnet" +} + +module "landingzone" { + source = "../../modules/landingzone" + resource_group_name = local.resource_group_name + location = var.location +} + +module "iam" { + source = "../../modules/iam" + scope = module.landingzone.resource_group_id + principal_id = var.principal_id + role_definition_name = "Contributor" +} + +module "vpc" { + source = "../../modules/vpc" + resource_group_name = module.landingzone.resource_group_name + location = var.location + vnet_name = local.vnet_name + address_space = ["10.20.0.0/16"] + subnets = [ + { + name = "app" + address_prefix = "10.20.1.0/24" + } + ] +} + +module "nsg" { + source = "../../modules/sg" + resource_group_name = module.landingzone.resource_group_name + location = var.location + name = "demo-nsg" +} + +resource "azurerm_subnet_network_security_group_association" "app" { + subnet_id = module.vpc.subnet_ids["app"] + network_security_group_id = module.nsg.nsg_id +} + +module "keypair" { + source = "../../modules/keypair" +} + +module "vm" { + source = "../../modules/ec2" + resource_group_name = module.landingzone.resource_group_name + location = var.location + vm_name = "demo-vm" + subnet_id = module.vpc.subnet_ids["app"] + admin_username = "azureuser" + ssh_public_key = module.keypair.public_key_openssh +} + +module "storage" { + source = "../../modules/s3" + resource_group_name = module.landingzone.resource_group_name + location = var.location + storage_account_name = "demostorageacct01" + container_name = "artifacts" +} + +module "database" { + source = "../../modules/rds" + resource_group_name = module.landingzone.resource_group_name + location = var.location + server_name = "demo-postgres" + admin_username = "pgadmin" + admin_password = "P@ssword12345!" + db_name = "appdb" + public_network_access_enabled = true +} + +module "cache" { + source = "../../modules/redis" + resource_group_name = module.landingzone.resource_group_name + location = var.location + name = "demorediscache" + sku_name = "Standard" + capacity = 1 +} + +output "resource_group" { + value = module.landingzone.resource_group_name + description = "Resource group provisioned for demo" +} + +output "vm_id" { + value = module.vm.vm_id + description = "Demo VM ID" +} + +output "ssh_private_key" { + value = module.keypair.private_key_pem + description = "Private key to access the VM" + sensitive = true +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/alb/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/alb/main.tf new file mode 100644 index 00000000..60b75714 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/alb/main.tf @@ -0,0 +1,114 @@ +variable "resource_group_name" { + description = "Resource group for the Application Gateway" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "name" { + description = "Application Gateway name" + type = string + default = "app-gateway" +} + +variable "subnet_id" { + description = "Subnet ID used by the Application Gateway" + type = string +} + +variable "backend_port" { + description = "Backend port for the default pool" + type = number + default = 80 +} + +variable "sku_name" { + description = "Application Gateway SKU" + type = string + default = "Standard_v2" +} + +variable "capacity" { + description = "Instance count" + type = number + default = 1 +} + +resource "azurerm_public_ip" "gateway" { + name = "${var.name}-pip" + resource_group_name = var.resource_group_name + location = var.location + allocation_method = "Static" + sku = "Standard" +} + +resource "azurerm_application_gateway" "this" { + name = var.name + resource_group_name = var.resource_group_name + location = var.location + + sku { + name = var.sku_name + tier = "Standard_v2" + } + + autoscale_configuration { + min_capacity = var.capacity + max_capacity = var.capacity + } + + gateway_ip_configuration { + name = "gateway-ipcfg" + subnet_id = var.subnet_id + } + + frontend_port { + name = "frontend-port" + port = 80 + } + + frontend_ip_configuration { + name = "frontend-ip" + public_ip_address_id = azurerm_public_ip.gateway.id + } + + backend_address_pool { + name = "default-backend" + } + + backend_http_settings { + name = "default-http" + cookie_based_affinity = "Disabled" + port = var.backend_port + protocol = "Http" + request_timeout = 30 + } + + http_listener { + name = "http-listener" + frontend_ip_configuration_name = "frontend-ip" + frontend_port_name = "frontend-port" + protocol = "Http" + } + + request_routing_rule { + name = "http-rule" + rule_type = "Basic" + http_listener_name = "http-listener" + backend_address_pool_name = "default-backend" + backend_http_settings_name = "default-http" + } +} + +output "application_gateway_id" { + value = azurerm_application_gateway.this.id + description = "Application Gateway resource ID" +} + +output "public_ip" { + value = azurerm_public_ip.gateway.ip_address + description = "Public IP assigned to the Application Gateway" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/ami_lookup/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/ami_lookup/main.tf new file mode 100644 index 00000000..205470ad --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/ami_lookup/main.tf @@ -0,0 +1,40 @@ +variable "location" { + description = "Azure region" + type = string + default = "eastus" +} + +variable "publisher" { + description = "Image publisher" + type = string + default = "Canonical" +} + +variable "offer" { + description = "Image offer" + type = string + default = "0001-com-ubuntu-server-focal" +} + +variable "sku" { + description = "Image SKU" + type = string + default = "20_04-lts" +} + +data "azurerm_platform_image" "ubuntu" { + location = var.location + publisher = var.publisher + offer = var.offer + sku = var.sku +} + +output "image" { + value = { + publisher = data.azurerm_platform_image.ubuntu.publisher + offer = data.azurerm_platform_image.ubuntu.offer + sku = data.azurerm_platform_image.ubuntu.sku + version = data.azurerm_platform_image.ubuntu.version + } + description = "Latest platform image metadata" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/ec2/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/ec2/main.tf new file mode 100644 index 00000000..1ebc5af7 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/ec2/main.tf @@ -0,0 +1,104 @@ +variable "resource_group_name" { + description = "Resource group for the VM" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "vm_name" { + description = "Virtual machine name" + type = string + default = "vm" +} + +variable "subnet_id" { + description = "Subnet ID to attach the VM" + type = string +} + +variable "admin_username" { + description = "Admin username for the VM" + type = string + default = "azureuser" +} + +variable "ssh_public_key" { + description = "Public SSH key for login" + type = string +} + +variable "vm_size" { + description = "Azure VM size" + type = string + default = "Standard_B2s" +} + +variable "source_image" { + description = "Platform image definition" + type = object({ + publisher = string + offer = string + sku = string + version = string + }) + default = { + publisher = "Canonical" + offer = "0001-com-ubuntu-server-focal" + sku = "20_04-lts" + version = "latest" + } +} + +resource "azurerm_network_interface" "vm" { + name = "${var.vm_name}-nic" + location = var.location + resource_group_name = var.resource_group_name + + ip_configuration { + name = "ipconfig1" + subnet_id = var.subnet_id + private_ip_address_allocation = "Dynamic" + } +} + +resource "azurerm_linux_virtual_machine" "vm" { + name = var.vm_name + resource_group_name = var.resource_group_name + location = var.location + size = var.vm_size + admin_username = var.admin_username + network_interface_ids = [ + azurerm_network_interface.vm.id + ] + + admin_ssh_key { + username = var.admin_username + public_key = var.ssh_public_key + } + + os_disk { + name = "${var.vm_name}-osdisk" + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = var.source_image.publisher + offer = var.source_image.offer + sku = var.source_image.sku + version = var.source_image.version + } +} + +output "vm_id" { + value = azurerm_linux_virtual_machine.vm.id + description = "Virtual machine resource ID" +} + +output "nic_id" { + value = azurerm_network_interface.vm.id + description = "Network interface ID" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/iam/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/iam/main.tf new file mode 100644 index 00000000..4d3b111c --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/iam/main.tf @@ -0,0 +1,31 @@ +variable "scope" { + description = "Scope for the role assignment" + type = string +} + +variable "principal_id" { + description = "Object ID of the principal to assign" + type = string +} + +variable "role_definition_name" { + description = "Built-in role name" + type = string + default = "Contributor" +} + +data "azurerm_role_definition" "selected" { + name = var.role_definition_name + scope = var.scope +} + +resource "azurerm_role_assignment" "assignment" { + scope = var.scope + role_definition_id = data.azurerm_role_definition.selected.id + principal_id = var.principal_id +} + +output "role_definition" { + value = data.azurerm_role_definition.selected.name + description = "Role assigned to the principal" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/keypair/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/keypair/main.tf new file mode 100644 index 00000000..83c6d4be --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/keypair/main.tf @@ -0,0 +1,27 @@ +variable "algorithm" { + description = "Algorithm for the SSH key" + type = string + default = "RSA" +} + +variable "rsa_bits" { + description = "RSA bits for the key when algorithm is RSA" + type = number + default = 4096 +} + +resource "tls_private_key" "ssh" { + algorithm = var.algorithm + rsa_bits = var.algorithm == "RSA" ? var.rsa_bits : null +} + +output "private_key_pem" { + value = tls_private_key.ssh.private_key_pem + sensitive = true + description = "Generated private key" +} + +output "public_key_openssh" { + value = tls_private_key.ssh.public_key_openssh + description = "Generated public key" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/landingzone/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/landingzone/main.tf new file mode 100644 index 00000000..424e8ef8 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/landingzone/main.tf @@ -0,0 +1,45 @@ +variable "resource_group_name" { + description = "Resource group to bootstrap" + type = string + default = "landingzone-rg" +} + +variable "location" { + description = "Azure region" + type = string + default = "eastus" +} + +variable "log_analytics_workspace_name" { + description = "Log Analytics workspace name" + type = string + default = "landingzone-law" +} + +resource "azurerm_resource_group" "this" { + name = var.resource_group_name + location = var.location +} + +resource "azurerm_log_analytics_workspace" "logs" { + name = var.log_analytics_workspace_name + location = var.location + resource_group_name = azurerm_resource_group.this.name + sku = "PerGB2018" + retention_in_days = 30 +} + +output "resource_group_id" { + value = azurerm_resource_group.this.id + description = "Landing zone resource group ID" +} + +output "log_analytics_workspace_id" { + value = azurerm_log_analytics_workspace.logs.id + description = "Log Analytics workspace ID" +} + +output "resource_group_name" { + value = azurerm_resource_group.this.name + description = "Landing zone resource group name" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/msk/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/msk/main.tf new file mode 100644 index 00000000..8496dadf --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/msk/main.tf @@ -0,0 +1,58 @@ +variable "resource_group_name" { + description = "Resource group for Event Hubs" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "namespace_name" { + description = "Event Hubs namespace name" + type = string +} + +variable "eventhub_name" { + description = "Event Hub name" + type = string + default = "events" +} + +variable "partition_count" { + description = "Number of partitions" + type = number + default = 2 +} + +variable "message_retention" { + description = "Message retention in days" + type = number + default = 1 +} + +resource "azurerm_eventhub_namespace" "ns" { + name = var.namespace_name + location = var.location + resource_group_name = var.resource_group_name + sku = "Standard" + capacity = 1 +} + +resource "azurerm_eventhub" "hub" { + name = var.eventhub_name + namespace_name = azurerm_eventhub_namespace.ns.name + resource_group_name = var.resource_group_name + partition_count = var.partition_count + message_retention = var.message_retention +} + +output "namespace_id" { + value = azurerm_eventhub_namespace.ns.id + description = "Event Hubs namespace ID" +} + +output "eventhub_id" { + value = azurerm_eventhub.hub.id + description = "Event Hub ID" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/nlb/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/nlb/main.tf new file mode 100644 index 00000000..37dcb23c --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/nlb/main.tf @@ -0,0 +1,101 @@ +variable "resource_group_name" { + description = "Resource group for the load balancer" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "name" { + description = "Load balancer name" + type = string + default = "nlb" +} + +variable "protocol" { + description = "Frontend protocol" + type = string + default = "Tcp" +} + +variable "frontend_port" { + description = "Frontend port" + type = number + default = 80 +} + +variable "backend_port" { + description = "Backend port" + type = number + default = 80 +} + +variable "backend_pool_backend_ids" { + description = "List of backend NIC IDs or IP configurations" + type = list(string) + default = [] +} + +resource "azurerm_public_ip" "lb" { + name = "${var.name}-pip" + location = var.location + resource_group_name = var.resource_group_name + allocation_method = "Static" + sku = "Standard" +} + +resource "azurerm_lb" "this" { + name = var.name + location = var.location + resource_group_name = var.resource_group_name + sku = "Standard" + + frontend_ip_configuration { + name = "public" + public_ip_address_id = azurerm_public_ip.lb.id + } +} + +resource "azurerm_lb_backend_address_pool" "pool" { + name = "backendpool" + loadbalancer_id = azurerm_lb.this.id +} + +resource "azurerm_lb_probe" "tcp" { + name = "tcp-probe" + resource_group_name = var.resource_group_name + loadbalancer_id = azurerm_lb.this.id + protocol = var.protocol + port = var.backend_port +} + +resource "azurerm_lb_rule" "lb_rule" { + name = "lb-rule" + resource_group_name = var.resource_group_name + loadbalancer_id = azurerm_lb.this.id + protocol = var.protocol + frontend_port = var.frontend_port + backend_port = var.backend_port + frontend_ip_configuration_name = "public" + backend_address_pool_id = azurerm_lb_backend_address_pool.pool.id + probe_id = azurerm_lb_probe.tcp.id +} + +resource "azurerm_network_interface_backend_address_pool_association" "attach" { + for_each = toset(var.backend_pool_backend_ids) + network_interface_id = each.value + ip_configuration_name = "ipconfig1" + backend_address_pool_id = azurerm_lb_backend_address_pool.pool.id +} + +output "lb_public_ip" { + value = azurerm_public_ip.lb.ip_address + description = "Public IP assigned to the load balancer" +} + +output "backend_pool_id" { + value = azurerm_lb_backend_address_pool.pool.id + description = "Backend address pool ID" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/rds/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/rds/main.tf new file mode 100644 index 00000000..ca9420d3 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/rds/main.tf @@ -0,0 +1,95 @@ +variable "resource_group_name" { + description = "Resource group for the database" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "server_name" { + description = "PostgreSQL flexible server name" + type = string +} + +variable "admin_username" { + description = "Admin username" + type = string + default = "pgadmin" +} + +variable "admin_password" { + description = "Admin password" + type = string + sensitive = true +} + +variable "version" { + description = "PostgreSQL version" + type = string + default = "14" +} + +variable "sku_name" { + description = "SKU name for flexible server" + type = string + default = "GP_Standard_D2ds_v4" +} + +variable "storage_mb" { + description = "Storage in MB" + type = number + default = 32768 +} + +variable "db_name" { + description = "Default database name" + type = string + default = "app" +} + +variable "public_network_access_enabled" { + description = "Allow public network access" + type = bool + default = true +} + +resource "azurerm_postgresql_flexible_server" "this" { + name = var.server_name + resource_group_name = var.resource_group_name + location = var.location + version = var.version + administrator_login = var.admin_username + administrator_password = var.admin_password + sku_name = var.sku_name + storage_mb = var.storage_mb + zone = 1 + backup_retention_days = 7 + public_network_access_enabled = var.public_network_access_enabled +} + +resource "azurerm_postgresql_flexible_database" "db" { + name = var.db_name + server_id = azurerm_postgresql_flexible_server.this.id + charset = "UTF8" + collation = "en_US.utf8" +} + +resource "azurerm_postgresql_flexible_server_firewall_rule" "allow_all" { + count = var.public_network_access_enabled ? 1 : 0 + name = "allow-all" + server_id = azurerm_postgresql_flexible_server.this.id + start_ip_address = "0.0.0.0" + end_ip_address = "255.255.255.255" +} + +output "server_fqdn" { + value = azurerm_postgresql_flexible_server.this.fqdn + description = "Database server FQDN" +} + +output "database_name" { + value = azurerm_postgresql_flexible_database.db.name + description = "Database name created" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/redis/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/redis/main.tf new file mode 100644 index 00000000..e241dd6e --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/redis/main.tf @@ -0,0 +1,48 @@ +variable "resource_group_name" { + description = "Resource group for Redis" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "name" { + description = "Redis cache name" + type = string +} + +variable "sku_name" { + description = "Redis SKU name" + type = string + default = "Standard" +} + +variable "capacity" { + description = "Redis capacity (size family dependent)" + type = number + default = 1 +} + +resource "azurerm_redis_cache" "this" { + name = var.name + location = var.location + resource_group_name = var.resource_group_name + capacity = var.capacity + family = "C" + sku_name = var.sku_name + enable_non_ssl_port = false + minimum_tls_version = "1.2" +} + +output "hostname" { + value = azurerm_redis_cache.this.hostname + description = "Redis hostname" +} + +output "primary_key" { + value = azurerm_redis_cache.this.primary_access_key + sensitive = true + description = "Redis primary key" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/s3/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/s3/main.tf new file mode 100644 index 00000000..0d32e4d1 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/s3/main.tf @@ -0,0 +1,46 @@ +variable "resource_group_name" { + description = "Resource group for storage" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "storage_account_name" { + description = "Storage account name" + type = string +} + +variable "container_name" { + description = "Blob container name" + type = string + default = "app" +} + +resource "azurerm_storage_account" "this" { + name = var.storage_account_name + resource_group_name = var.resource_group_name + location = var.location + account_tier = "Standard" + account_replication_type = "LRS" + min_tls_version = "TLS1_2" + allow_blob_public_access = false +} + +resource "azurerm_storage_container" "this" { + name = var.container_name + storage_account_name = azurerm_storage_account.this.name + container_access_type = "private" +} + +output "storage_account_id" { + value = azurerm_storage_account.this.id + description = "Storage account ID" +} + +output "container_name" { + value = azurerm_storage_container.this.name + description = "Blob container name" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/sg/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/sg/main.tf new file mode 100644 index 00000000..f547f6c4 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/sg/main.tf @@ -0,0 +1,69 @@ +variable "resource_group_name" { + description = "Resource group for NSG" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "name" { + description = "Network security group name" + type = string + default = "nsg" +} + +variable "rules" { + description = "List of security rules" + type = list(object({ + name = string + priority = number + direction = string + access = string + protocol = string + source_port_range = string + destination_port_range = string + source_address_prefix = string + destination_address_prefix = string + })) + default = [ + { + name = "ssh" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "22" + source_address_prefix = "*" + destination_address_prefix = "*" + } + ] +} + +resource "azurerm_network_security_group" "this" { + name = var.name + location = var.location + resource_group_name = var.resource_group_name +} + +resource "azurerm_network_security_rule" "rules" { + for_each = { for rule in var.rules : rule.name => rule } + name = each.value.name + priority = each.value.priority + direction = each.value.direction + access = each.value.access + protocol = each.value.protocol + source_port_range = each.value.source_port_range + destination_port_range = each.value.destination_port_range + source_address_prefix = each.value.source_address_prefix + destination_address_prefix = each.value.destination_address_prefix + resource_group_name = var.resource_group_name + network_security_group_name = azurerm_network_security_group.this.name +} + +output "nsg_id" { + value = azurerm_network_security_group.this.id + description = "Network security group ID" +} diff --git a/iac-template/terraform-hcl-standard/azure-cloud/modules/vpc/main.tf b/iac-template/terraform-hcl-standard/azure-cloud/modules/vpc/main.tf new file mode 100644 index 00000000..e5c6def7 --- /dev/null +++ b/iac-template/terraform-hcl-standard/azure-cloud/modules/vpc/main.tf @@ -0,0 +1,62 @@ +variable "resource_group_name" { + description = "Resource group for the virtual network" + type = string +} + +variable "location" { + description = "Azure region" + type = string +} + +variable "vnet_name" { + description = "Virtual network name" + type = string + default = "main-vnet" +} + +variable "address_space" { + description = "Address space for the virtual network" + type = list(string) + default = ["10.10.0.0/16"] +} + +variable "subnets" { + description = "Subnets to create inside the VNet" + type = list(object({ + name = string + address_prefix = string + service_endpoints = optional(list(string), []) + })) + default = [ + { + name = "default" + address_prefix = "10.10.1.0/24" + } + ] +} + +resource "azurerm_virtual_network" "this" { + name = var.vnet_name + address_space = var.address_space + location = var.location + resource_group_name = var.resource_group_name +} + +resource "azurerm_subnet" "this" { + for_each = { for subnet in var.subnets : subnet.name => subnet } + name = each.value.name + resource_group_name = var.resource_group_name + virtual_network_name = azurerm_virtual_network.this.name + address_prefixes = [each.value.address_prefix] + service_endpoints = lookup(each.value, "service_endpoints", []) +} + +output "vnet_id" { + value = azurerm_virtual_network.this.id + description = "Virtual network resource ID" +} + +output "subnet_ids" { + value = { for name, subnet in azurerm_subnet.this : name => subnet.id } + description = "Map of subnet IDs keyed by name" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/README.md b/iac-template/terraform-hcl-standard/gcp-cloud/README.md new file mode 100644 index 00000000..d8315374 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/README.md @@ -0,0 +1,32 @@ +# GCP Cloud Terraform Standard + +该目录提供与 `aws-cloud` 模板一一对应的 GCP 版本,用于在 GCP 上快速引导基础设施。结构与 AWS 目录保持一致,包括引导阶段 (bootstrap)、环境示例 (envs) 与模块库 (modules)。 + +## 模板映射 +- **bootstrap-dynamodb → Firestore**:使用 Firestore(Datastore 模式)作为无服务器键值存储。 +- **bootstrap-iam → IAM**:创建基础服务账号与自定义角色,替代 AWS IAM 角色与策略。 +- **bootstrap-s3 → Cloud Storage**:创建 GCS 存储桶并启用版本化,对应 AWS S3。 +- **modules**:保留原始模块命名(alb、nlb、vpc 等),内部实现改为 GCP 资源: + - `alb`/`nlb`:使用 Google HTTP(S) / TCP 负载均衡。 + - `ec2`:映射到 Compute Engine 实例或 MIG。 + - `keypair`:生成 SSH 密钥并写入元数据。 + - `msk`:映射到 Pub/Sub(发布/订阅)。 + - `rds`:映射到 Cloud SQL。 + - `s3`:映射到 Cloud Storage。 + - `vpc`:使用 VPC 网络与子网。 + - `ami_lookup`:映射到最新公共镜像查找(debian/ubuntu)。 + - `iam`:分配 IAM 角色与绑定。 + - `landingzone`:创建基础网络、日志与审计配置。 + - `redis`:映射到 Memorystore。 + - `sg`:映射到 VPC 防火墙规则。 + +## 使用方式 +1. 在 `config/backend.tf` 中配置远端状态(GCS 存储桶)。 +2. 在 `config/provider.tf` 中设置 `project`、`region`、`credentials` 等参数。 +3. 按需修改 `envs` 下的环境示例,执行: + ```bash + terraform -chdir=envs/dev init + terraform -chdir=envs/dev apply + ``` + +本目录仅新增 GCP 代码,不改动现有 AWS 模板。 diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-dynamodb/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-dynamodb/main.tf new file mode 100644 index 00000000..2bdd975d --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-dynamodb/main.tf @@ -0,0 +1,42 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.0" + } + } +} + +variable "project_id" { + description = "GCP project id where Firestore will be enabled" + type = string +} + +variable "location" { + description = "Firestore location" + type = string + default = "us-central" +} + +resource "google_project_service" "firestore" { + service = "firestore.googleapis.com" + project = var.project_id +} + +resource "google_project_service" "cloudresourcemanager" { + service = "cloudresourcemanager.googleapis.com" + project = var.project_id +} + +resource "google_firestore_database" "default" { + name = "(default)" + location_id = var.location + project = var.project_id + type = "DATASTORE_MODE" + depends_on = [google_project_service.firestore, google_project_service.cloudresourcemanager] +} + +output "firestore_database" { + description = "Firestore database ID" + value = google_firestore_database.default.name +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-iam/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-iam/main.tf new file mode 100644 index 00000000..1ca2c18f --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-iam/main.tf @@ -0,0 +1,47 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.0" + } + } +} + +variable "project_id" { + description = "Target project for IAM bootstrap" + type = string +} + +variable "service_account_id" { + description = "ID of the bootstrap service account" + type = string + default = "terraform-bootstrap" +} + +variable "service_account_roles" { + description = "List of roles to attach to the bootstrap service account" + type = list(string) + default = [ + "roles/resourcemanager.projectIamAdmin", + "roles/storage.admin", + "roles/compute.admin" + ] +} + +resource "google_service_account" "bootstrap" { + account_id = var.service_account_id + display_name = "Terraform Bootstrap" + project = var.project_id +} + +resource "google_project_iam_member" "bootstrap" { + for_each = toset(var.service_account_roles) + project = var.project_id + role = each.value + member = "serviceAccount:${google_service_account.bootstrap.email}" +} + +output "service_account_email" { + value = google_service_account.bootstrap.email + description = "Bootstrap service account email" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-s3/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-s3/main.tf new file mode 100644 index 00000000..bca892d4 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/bootstrap-s3/main.tf @@ -0,0 +1,47 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.0" + } + } +} + +variable "project_id" { + description = "Project id where the state bucket will be created" + type = string +} + +variable "bucket_name" { + description = "Name of the GCS bucket" + type = string +} + +variable "location" { + description = "Bucket location" + type = string + default = "US" +} + +resource "google_storage_bucket" "state" { + name = var.bucket_name + location = var.location + project = var.project_id + uniform_bucket_level_access = true + versioning { + enabled = true + } + lifecycle_rule { + action { + type = "Delete" + } + condition { + age = 365 + } + } +} + +output "bucket" { + value = google_storage_bucket.state.name + description = "Created state bucket" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/config/backend.tf b/iac-template/terraform-hcl-standard/gcp-cloud/config/backend.tf new file mode 100644 index 00000000..981f5ec1 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/config/backend.tf @@ -0,0 +1,9 @@ +terraform { + required_version = ">= 1.5.0" + + backend "gcs" { + bucket = var.state_bucket + prefix = var.state_prefix + project = var.project_id + } +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/config/provider.tf b/iac-template/terraform-hcl-standard/gcp-cloud/config/provider.tf new file mode 100644 index 00000000..3b856dfd --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/config/provider.tf @@ -0,0 +1,24 @@ +terraform { + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.0" + } + google-beta = { + source = "hashicorp/google-beta" + version = ">= 5.0" + } + } +} + +provider "google" { + project = var.project_id + region = var.region + zone = var.zone +} + +provider "google-beta" { + project = var.project_id + region = var.region + zone = var.zone +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/config/variables.tf b/iac-template/terraform-hcl-standard/gcp-cloud/config/variables.tf new file mode 100644 index 00000000..f4cdcd15 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/config/variables.tf @@ -0,0 +1,27 @@ +variable "project_id" { + description = "GCP project id" + type = string +} + +variable "region" { + description = "Default region" + type = string + default = "us-central1" +} + +variable "zone" { + description = "Default zone" + type = string + default = "us-central1-a" +} + +variable "state_bucket" { + description = "GCS bucket used for Terraform remote state" + type = string +} + +variable "state_prefix" { + description = "Prefix within the state bucket" + type = string + default = "terraform/state" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-alb/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-alb/main.tf new file mode 100644 index 00000000..253e73fd --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-alb/main.tf @@ -0,0 +1,27 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.0" + } + } +} + +variable "project_id" { type = string } + +provider "google" { + project = var.project_id + region = "us-central1" +} + +module "alb" { + source = "../../modules/alb" + project_id = var.project_id + bucket_name = "dev-alb-static-${var.project_id}" + name = "dev-alb" +} + +output "forwarding_rule" { + value = module.alb.forwarding_rule +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-ec2/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-ec2/main.tf new file mode 100644 index 00000000..3e1d68b2 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-ec2/main.tf @@ -0,0 +1,48 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { source = "hashicorp/google" version = ">= 5.0" } + } +} + +variable "project_id" { type = string } +variable "region" { type = string default = "us-central1" } +variable "zone" { type = string default = "us-central1-a" } + +provider "google" { + project = var.project_id + region = var.region + zone = var.zone +} + +module "vpc" { + source = "../../modules/vpc" + project_id = var.project_id + subnets = [{ + name = "ec2-subnet" + ip_cidr_range = "10.40.0.0/24" + region = var.region + }] +} + +data "google_client_config" "current" {} + +module "ami" { + source = "../../modules/ami_lookup" +} + +module "vm" { + source = "../../modules/ec2" + project_id = var.project_id + name = "dev-compute" + zone = var.zone + machine_type = "e2-medium" + network = module.vpc.network_self_link + subnet = module.vpc.subnet_self_links[0] + image = module.ami.image + ssh_keys = ["terraform:${data.google_client_config.current.access_token}"] +} + +output "instance" { + value = module.vm.instance_self_link +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-kafka/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-kafka/main.tf new file mode 100644 index 00000000..2a142220 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-kafka/main.tf @@ -0,0 +1,24 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { source = "hashicorp/google" version = ">= 5.0" } + } +} + +variable "project_id" { type = string } + +provider "google" { + project = var.project_id + region = "us-central1" +} + +module "pubsub" { + source = "../../modules/msk" + project_id = var.project_id + topic = "dev-topic" + subscription = "dev-subscription" +} + +output "topic" { + value = module.pubsub.topic +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-landingzone/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-landingzone/main.tf new file mode 100644 index 00000000..72f7db9b --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-landingzone/main.tf @@ -0,0 +1,28 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { source = "hashicorp/google" version = ">= 5.0" } + } +} + +variable "project_id" { type = string } + +provider "google" { + project = var.project_id + region = "us-central1" +} + +module "landingzone" { + source = "../../modules/landingzone" + project_id = var.project_id + services = [ + "compute.googleapis.com", + "pubsub.googleapis.com", + "sqladmin.googleapis.com", + "redis.googleapis.com" + ] +} + +output "services" { + value = module.landingzone.enabled_services +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-nlb/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-nlb/main.tf new file mode 100644 index 00000000..2ffe088e --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-nlb/main.tf @@ -0,0 +1,43 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.0" + } + } +} + +variable "project_id" { type = string } +variable "region" { type = string default = "us-central1" } +variable "zone" { type = string default = "us-central1-a" } + +provider "google" { + project = var.project_id + region = var.region + zone = var.zone +} + +module "vpc" { + source = "../../modules/vpc" + project_id = var.project_id + subnets = [{ + name = "nlb-subnet" + ip_cidr_range = "10.30.0.0/24" + region = var.region + }] +} + +module "nlb" { + source = "../../modules/nlb" + project_id = var.project_id + network = module.vpc.network_self_link + subnet = module.vpc.subnet_self_links[0] + port = 8080 + zone = var.zone + name = "dev-nlb" +} + +output "forwarding_rule" { + value = module.nlb.forwarding_rule +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-object/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-object/main.tf new file mode 100644 index 00000000..bb28e7a1 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-object/main.tf @@ -0,0 +1,24 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { source = "hashicorp/google" version = ">= 5.0" } + } +} + +variable "project_id" { type = string } + +provider "google" { + project = var.project_id + region = "us-central1" +} + +module "bucket" { + source = "../../modules/s3" + project_id = var.project_id + name = "dev-object-${var.project_id}" + location = "US" +} + +output "bucket" { + value = module.bucket.bucket +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-rds/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-rds/main.tf new file mode 100644 index 00000000..b64253dc --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-rds/main.tf @@ -0,0 +1,27 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { source = "hashicorp/google" version = ">= 5.0" } + } +} + +variable "project_id" { type = string } +variable "region" { type = string default = "us-central1" } + +provider "google" { + project = var.project_id + region = var.region +} + +module "sql" { + source = "../../modules/rds" + project_id = var.project_id + name = "dev-postgres" + database_version = "POSTGRES_15" + region = var.region + tier = "db-custom-1-3840" +} + +output "connection_name" { + value = module.sql.connection_name +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-redis/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-redis/main.tf new file mode 100644 index 00000000..6e24d428 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-redis/main.tf @@ -0,0 +1,26 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { source = "hashicorp/google" version = ">= 5.0" } + } +} + +variable "project_id" { type = string } +variable "region" { type = string default = "us-central1" } + +provider "google" { + project = var.project_id + region = var.region +} + +module "redis" { + source = "../../modules/redis" + project_id = var.project_id + name = "dev-redis" + region = var.region + memory_size_gb = 2 +} + +output "redis_host" { + value = module.redis.host +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-role/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-role/main.tf new file mode 100644 index 00000000..c6700796 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-role/main.tf @@ -0,0 +1,25 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { source = "hashicorp/google" version = ">= 5.0" } + } +} + +variable "project_id" { type = string } + +provider "google" { + project = var.project_id + region = "us-central1" +} + +module "iam" { + source = "../../modules/iam" + project_id = var.project_id + bindings = [ + { role = "roles/storage.objectViewer", member = "allAuthenticatedUsers" } + ] +} + +output "roles" { + value = module.iam.applied_bindings +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-vpc/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-vpc/main.tf new file mode 100644 index 00000000..1296fd9e --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev-vpc/main.tf @@ -0,0 +1,33 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.0" + } + } +} + +variable "project_id" { type = string } +variable "region" { type = string default = "us-central1" } + +provider "google" { + project = var.project_id + region = var.region +} + +module "vpc" { + source = "../../modules/vpc" + project_id = var.project_id + subnets = [ + { + name = "dev-subnet" + ip_cidr_range = "10.20.0.0/24" + region = var.region + } + ] +} + +output "network" { + value = module.vpc.network_self_link +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev/main.tf new file mode 100644 index 00000000..893937a8 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/envs/dev/main.tf @@ -0,0 +1,34 @@ +terraform { + required_version = ">= 1.5.0" + required_providers { + google = { + source = "hashicorp/google" + version = ">= 5.0" + } + } +} + +variable "project_id" { + type = string + description = "Target project" +} + +variable "region" { + type = string + default = "us-central1" +} + +provider "google" { + project = var.project_id + region = var.region +} + +module "landingzone" { + source = "../../modules/landingzone" + project_id = var.project_id +} + +output "enabled_services" { + value = module.landingzone.enabled_services + description = "APIs enabled for the project" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/alb/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/alb/main.tf new file mode 100644 index 00000000..61bd817d --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/alb/main.tf @@ -0,0 +1,59 @@ +variable "project_id" { + description = "Project id" + type = string +} + +variable "name" { + description = "Load balancer name" + type = string + default = "http-lb" +} + +variable "bucket_name" { + description = "Name for the backend bucket" + type = string +} + +resource "google_storage_bucket" "static" { + name = var.bucket_name + location = "US" + project = var.project_id + uniform_bucket_level_access = true + website { + main_page_suffix = "index.html" + not_found_page = "404.html" + } +} + +resource "google_compute_backend_bucket" "static" { + name = "${var.name}-backend" + bucket_name = google_storage_bucket.static.name + enable_cdn = true +} + +resource "google_compute_url_map" "static" { + name = "${var.name}-url-map" + default_service = google_compute_backend_bucket.static.self_link +} + +resource "google_compute_target_http_proxy" "static" { + name = "${var.name}-http-proxy" + url_map = google_compute_url_map.static.self_link +} + +resource "google_compute_global_forwarding_rule" "static" { + name = "${var.name}-fwd" + port_range = "80" + target = google_compute_target_http_proxy.static.self_link + load_balancing_scheme = "EXTERNAL" +} + +output "bucket" { + value = google_storage_bucket.static.name + description = "Static site bucket" +} + +output "forwarding_rule" { + value = google_compute_global_forwarding_rule.static.name + description = "HTTP forwarding rule" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/ami_lookup/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/ami_lookup/main.tf new file mode 100644 index 00000000..49798de8 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/ami_lookup/main.tf @@ -0,0 +1,21 @@ +variable "family" { + description = "Image family to lookup" + type = string + default = "debian-12" +} + +variable "project" { + description = "Project hosting the image" + type = string + default = "debian-cloud" +} + +data "google_compute_image" "family" { + family = var.family + project = var.project +} + +output "image" { + value = data.google_compute_image.family.self_link + description = "Self link of the resolved image" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/ec2/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/ec2/main.tf new file mode 100644 index 00000000..6a9a3329 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/ec2/main.tf @@ -0,0 +1,70 @@ +variable "project_id" { + description = "Project id" + type = string +} + +variable "name" { + description = "Instance name" + type = string +} + +variable "zone" { + description = "Instance zone" + type = string + default = "us-central1-a" +} + +variable "machine_type" { + description = "Machine type" + type = string + default = "e2-medium" +} + +variable "network" { + description = "Network self link" + type = string +} + +variable "subnet" { + description = "Subnetwork self link" + type = string +} + +variable "image" { + description = "Source image" + type = string +} + +variable "ssh_keys" { + description = "SSH key metadata entries" + type = list(string) + default = [] +} + +resource "google_compute_instance" "vm" { + name = var.name + project = var.project_id + zone = var.zone + machine_type = var.machine_type + + boot_disk { + initialize_params { + image = var.image + } + } + + network_interface { + network = var.network + subnetwork = var.subnet + access_config {} + } + + metadata = length(var.ssh_keys) > 0 ? { + ssh-keys = join("\n", var.ssh_keys) + } : {} +} + +output "instance_self_link" { + value = google_compute_instance.vm.self_link + description = "Instance self link" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/iam/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/iam/main.tf new file mode 100644 index 00000000..e2b52af1 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/iam/main.tf @@ -0,0 +1,25 @@ +variable "project_id" { + type = string + description = "Project id" +} + +variable "bindings" { + type = list(object({ + role = string + member = string + })) + description = "List of role/member bindings" + default = [] +} + +resource "google_project_iam_member" "bindings" { + for_each = { for idx, binding in var.bindings : idx => binding } + project = var.project_id + role = each.value.role + member = each.value.member +} + +output "applied_bindings" { + value = [for binding in google_project_iam_member.bindings : binding.role] + description = "Roles applied to members" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/keypair/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/keypair/main.tf new file mode 100644 index 00000000..4c1907dd --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/keypair/main.tf @@ -0,0 +1,36 @@ +terraform { + required_providers { + tls = { + source = "hashicorp/tls" + version = ">= 4.0" + } + } +} + +variable "algorithm" { + type = string + description = "Algorithm for the SSH key" + default = "RSA" +} + +variable "rsa_bits" { + type = number + description = "RSA key length when algorithm is RSA" + default = 4096 +} + +resource "tls_private_key" "ssh" { + algorithm = var.algorithm + rsa_bits = var.rsa_bits +} + +output "public_key_openssh" { + value = tls_private_key.ssh.public_key_openssh + description = "Generated public key" +} + +output "private_key_pem" { + value = tls_private_key.ssh.private_key_pem + sensitive = true + description = "Generated private key" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/landingzone/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/landingzone/main.tf new file mode 100644 index 00000000..856e18eb --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/landingzone/main.tf @@ -0,0 +1,26 @@ +variable "project_id" { + description = "Project id" + type = string +} + +variable "services" { + description = "APIs to enable" + type = list(string) + default = [ + "compute.googleapis.com", + "iam.googleapis.com", + "cloudresourcemanager.googleapis.com", + "logging.googleapis.com" + ] +} + +resource "google_project_service" "enabled" { + for_each = toset(var.services) + project = var.project_id + service = each.key +} + +output "enabled_services" { + value = [for s in google_project_service.enabled : s.service] + description = "List of enabled services" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/msk/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/msk/main.tf new file mode 100644 index 00000000..513f6526 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/msk/main.tf @@ -0,0 +1,36 @@ +variable "project_id" { + description = "Project id" + type = string +} + +variable "topic" { + description = "Pub/Sub topic name" + type = string + default = "default-topic" +} + +variable "subscription" { + description = "Subscription name" + type = string + default = "default-subscription" +} + +resource "google_pubsub_topic" "this" { + name = var.topic + project = var.project_id +} + +resource "google_pubsub_subscription" "this" { + name = var.subscription + topic = google_pubsub_topic.this.name +} + +output "topic" { + value = google_pubsub_topic.this.name + description = "Pub/Sub topic name" +} + +output "subscription" { + value = google_pubsub_subscription.this.name + description = "Pub/Sub subscription name" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/nlb/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/nlb/main.tf new file mode 100644 index 00000000..6e853a13 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/nlb/main.tf @@ -0,0 +1,78 @@ +variable "project_id" { + description = "Project id" + type = string +} + +variable "name" { + description = "Load balancer name" + type = string + default = "tcp-lb" +} + +variable "network" { + description = "Network self link" + type = string +} + +variable "subnet" { + description = "Subnetwork self link" + type = string +} + +variable "port" { + description = "Service port" + type = number + default = 80 +} + +variable "zone" { + description = "Zone for unmanaged instance group" + type = string + default = "us-central1-a" +} + +resource "google_compute_instance_group" "placeholder" { + name = "${var.name}-ig" + project = var.project_id + zone = var.zone + network = var.network + named_port { + name = "service" + port = var.port + } +} + +resource "google_compute_health_check" "tcp" { + name = "${var.name}-hc" + project = var.project_id + tcp_health_check { + port = var.port + } +} + +resource "google_compute_backend_service" "tcp" { + name = "${var.name}-backend" + project = var.project_id + load_balancing_scheme = "EXTERNAL" + protocol = "TCP" + health_checks = [google_compute_health_check.tcp.self_link] + backend { + group = google_compute_instance_group.placeholder.self_link + } +} + +resource "google_compute_forwarding_rule" "tcp" { + name = "${var.name}-fwd" + project = var.project_id + load_balancing_scheme = "EXTERNAL" + ip_protocol = "TCP" + port_range = tostring(var.port) + backend_service = google_compute_backend_service.tcp.self_link + network = var.network + subnetwork = var.subnet +} + +output "forwarding_rule" { + value = google_compute_forwarding_rule.tcp.name + description = "TCP forwarding rule" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/rds/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/rds/main.tf new file mode 100644 index 00000000..826f4f9c --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/rds/main.tf @@ -0,0 +1,44 @@ +variable "project_id" { + description = "Project id" + type = string +} + +variable "name" { + description = "Instance name" + type = string + default = "default-sql" +} + +variable "database_version" { + description = "Cloud SQL engine" + type = string + default = "POSTGRES_15" +} + +variable "tier" { + description = "Machine tier" + type = string + default = "db-f1-micro" +} + +variable "region" { + description = "Instance region" + type = string + default = "us-central1" +} + +resource "google_sql_database_instance" "this" { + name = var.name + project = var.project_id + region = var.region + database_version = var.database_version + + settings { + tier = var.tier + } +} + +output "connection_name" { + value = google_sql_database_instance.this.connection_name + description = "Instance connection string" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/redis/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/redis/main.tf new file mode 100644 index 00000000..1ec2b2cb --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/redis/main.tf @@ -0,0 +1,41 @@ +variable "project_id" { + description = "Project id" + type = string +} + +variable "name" { + description = "Redis instance name" + type = string + default = "default-redis" +} + +variable "region" { + description = "Region for the instance" + type = string + default = "us-central1" +} + +variable "tier" { + description = "Service tier" + type = string + default = "STANDARD_HA" +} + +variable "memory_size_gb" { + description = "Memory size" + type = number + default = 1 +} + +resource "google_redis_instance" "this" { + name = var.name + project = var.project_id + region = var.region + tier = var.tier + memory_size_gb = var.memory_size_gb +} + +output "host" { + value = google_redis_instance.this.host + description = "Redis host" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/s3/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/s3/main.tf new file mode 100644 index 00000000..ea7bcdd4 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/s3/main.tf @@ -0,0 +1,28 @@ +variable "project_id" { + description = "Project id" + type = string +} + +variable "name" { + description = "Bucket name" + type = string +} + +variable "location" { + description = "Bucket location" + type = string + default = "US" +} + +resource "google_storage_bucket" "this" { + name = var.name + project = var.project_id + location = var.location + uniform_bucket_level_access = true + versioning { enabled = true } +} + +output "bucket" { + value = google_storage_bucket.this.name + description = "Storage bucket" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/sg/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/sg/main.tf new file mode 100644 index 00000000..37f00479 --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/sg/main.tf @@ -0,0 +1,45 @@ +variable "project_id" { + description = "Project id" + type = string +} + +variable "network" { + description = "Network self link" + type = string +} + +variable "rules" { + description = "Firewall rules" + type = list(object({ + name = string + direction = string + ranges = list(string) + protocols = map(list(number)) + target_tags = list(string) + })) + default = [] +} + +resource "google_compute_firewall" "rules" { + for_each = { for rule in var.rules : rule.name => rule } + + name = each.value.name + project = var.project_id + network = var.network + direction = upper(each.value.direction) + priority = 1000 + + allow = [for proto, ports in each.value.protocols : { + protocol = proto + ports = [for port in ports : tostring(port)] + }] + + source_ranges = each.value.direction == "ingress" ? each.value.ranges : null + destination_ranges = each.value.direction == "egress" ? each.value.ranges : null + target_tags = each.value.target_tags +} + +output "firewall_rules" { + value = [for rule in google_compute_firewall.rules : rule.name] + description = "Created firewall rules" +} diff --git a/iac-template/terraform-hcl-standard/gcp-cloud/modules/vpc/main.tf b/iac-template/terraform-hcl-standard/gcp-cloud/modules/vpc/main.tf new file mode 100644 index 00000000..5a186c9d --- /dev/null +++ b/iac-template/terraform-hcl-standard/gcp-cloud/modules/vpc/main.tf @@ -0,0 +1,51 @@ +variable "project_id" { + description = "Project id" + type = string +} + +variable "network_name" { + description = "Name of the VPC network" + type = string + default = "main-vpc" +} + +variable "subnets" { + description = "List of subnet definitions" + type = list(object({ + name = string + ip_cidr_range = string + region = string + })) + default = [ + { + name = "default-subnet" + ip_cidr_range = "10.10.0.0/24" + region = "us-central1" + } + ] +} + +resource "google_compute_network" "this" { + name = var.network_name + project = var.project_id + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "this" { + for_each = { for subnet in var.subnets : subnet.name => subnet } + name = each.value.name + ip_cidr_range = each.value.ip_cidr_range + region = each.value.region + network = google_compute_network.this.id + private_ip_google_access = true +} + +output "network_self_link" { + value = google_compute_network.this.self_link + description = "VPC network self link" +} + +output "subnet_self_links" { + value = [for subnet in google_compute_subnetwork.this : subnet.self_link] + description = "Subnetwork self links" +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/README.md b/iac-template/terraform-hcl-standard/vultr-vps/README.md new file mode 100644 index 00000000..80e44ea9 --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/README.md @@ -0,0 +1,36 @@ +# Vultr VPS Terraform Standard + +此目录在保持 AWS 模板目录结构的同时,提供 Vultr VPS 的等效实现,方便在 Vultr 上快速落地基础设施。模板包含引导阶段(bootstrap)、环境示例(envs)与模块库(modules),与 `aws-cloud`/`gcp-cloud` 目录一一对应。 + +## AWS → Vultr 资源映射 +- **VPC (aws_vpc)** → `vultr_vpc`:创建私网并自定义 IPv4 段。 +- **EC2 (aws_instance)** → `vultr_instance`:创建 VPS/计算实例,支持自定义镜像与云初始化脚本。 +- **S3 (aws_s3_bucket)** → `vultr_object_storage`:提供 S3 兼容对象存储,可用于远端状态与应用资产。 +- **IAM (aws_iam_user/role + aws_key_pair)** → `vultr_user` + `vultr_ssh_key`:管理子账号权限与 SSH 公钥分发。 +- **RDS (aws_db_instance)** → `vultr_database`:托管数据库(MySQL/PostgreSQL/Redis),支持自动备份与高可用套餐。 + +## 目录结构 +- `bootstrap-object-storage/`:初始化 Vultr 对象存储集群与访问密钥,可作为 Terraform 远端状态桶。 +- `bootstrap-iam/`:创建子账号与 SSH Key,实现最小权限访问与实例登录。 +- `config/`:包含通用的 `backend.tf` 与 `provider.tf`,用于配置 S3 兼容后端与 Vultr Provider。 +- `modules/`:核心模块实现(vpc、compute、storage、iam、data_store),接口与 AWS 模块命名保持一致。 +- `envs/`:示例环境(`dev`)展示如何组合模块。 + +## 使用方式 +1. 在 `config/backend.tf` 中填写 Vultr 对象存储的 endpoint、bucket、访问密钥;在 `config/provider.tf` 设置 `vultr_api_key` 与默认 region。 +2. 使用引导模板创建状态桶与基础身份: + ```bash + terraform -chdir=bootstrap-object-storage init + terraform -chdir=bootstrap-object-storage apply + + terraform -chdir=bootstrap-iam init + terraform -chdir=bootstrap-iam apply + ``` +3. 根据需要复制 `envs/dev`,调整变量后运行: + ```bash + terraform -chdir=envs/dev init + terraform -chdir=envs/dev apply + ``` +4. 模块可单独在 `envs` 下拆分(如 `dev-vpc`, `dev-compute`),以匹配 AWS 目录的分环境实践。 + +> 本目录只新增 Vultr 代码,不改动既有 AWS/GCP 模板。 diff --git a/iac-template/terraform-hcl-standard/vultr-vps/bootstrap-iam/main.tf b/iac-template/terraform-hcl-standard/vultr-vps/bootstrap-iam/main.tf new file mode 100644 index 00000000..abf5d216 --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/bootstrap-iam/main.tf @@ -0,0 +1,70 @@ +terraform { + required_version = ">= 1.5" + + required_providers { + vultr = { + source = "vultr/vultr" + version = "~> 2.19" + } + } +} + +provider "vultr" { + api_key = var.vultr_api_key +} + +resource "vultr_user" "readonly" { + email = var.user_email + api_enabled = true + acls = var.acls + password = var.user_password +} + +resource "vultr_ssh_key" "bootstrap" { + name = var.ssh_key_name + ssh_key = var.public_key +} + +output "user_id" { + value = vultr_user.readonly.id + description = "最小权限 API 子账号 ID" +} + +output "ssh_key_id" { + value = vultr_ssh_key.bootstrap.id + description = "上传到 Vultr 的 SSH 公钥 ID" +} + +variable "vultr_api_key" { + description = "管理账号 API Key" + type = string + sensitive = true +} + +variable "user_email" { + description = "子账号邮箱" + type = string +} + +variable "user_password" { + description = "子账号初始密码" + type = string + sensitive = true +} + +variable "acls" { + description = "授予子账号的权限集合,例如 [\"subscriptions\", \"support\"]" + type = list(string) + default = ["subscriptions", "support", "billing"] +} + +variable "ssh_key_name" { + description = "SSH Key 的名称标签" + type = string + default = "bootstrap-key" +} + +variable "public_key" { + description = "SSH 公钥内容" + type = string +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/bootstrap-object-storage/main.tf b/iac-template/terraform-hcl-standard/vultr-vps/bootstrap-object-storage/main.tf new file mode 100644 index 00000000..0b150cc2 --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/bootstrap-object-storage/main.tf @@ -0,0 +1,85 @@ +terraform { + required_version = ">= 1.5" + + required_providers { + vultr = { + source = "vultr/vultr" + version = "~> 2.19" + } + } +} + +provider "vultr" { + api_key = var.vultr_api_key +} + +resource "vultr_object_storage" "state" { + region = var.region + cluster_id = var.cluster_id + label = var.name + smtp_enabled = false + minio_access = true + minio_secret = var.seed_secret + bucket_name = var.bucket +} + +resource "vultr_object_storage_key" "state" { + object_storage_id = vultr_object_storage.state.id + description = "terraform-state" +} + +output "bucket" { + description = "对象存储桶名称" + value = vultr_object_storage.state.bucket_name +} + +output "endpoint" { + description = "S3 兼容 Endpoint" + value = vultr_object_storage.state.s3_hostname +} + +output "access_key" { + description = "访问密钥 Access Key" + value = vultr_object_storage_key.state.access_key + sensitive = true +} + +output "secret_key" { + description = "访问密钥 Secret Key" + value = vultr_object_storage_key.state.secret_key + sensitive = true +} + +variable "vultr_api_key" { + description = "Vultr API Key" + type = string + sensitive = true +} + +variable "region" { + description = "Vultr 区域代码" + type = string +} + +variable "cluster_id" { + description = "对象存储集群 ID(例如 ewr1)" + type = string +} + +variable "bucket" { + description = "对象存储桶名称" + type = string +} + +variable "name" { + description = "资源标签" + type = string + default = "terraform-state" +} + +variable "seed_secret" { + description = "可选的初始密钥种子,确保生成的 secret 可追踪" + type = string + default = "" + sensitive = true +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/config/backend.tf b/iac-template/terraform-hcl-standard/vultr-vps/config/backend.tf new file mode 100644 index 00000000..a3ffc7da --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/config/backend.tf @@ -0,0 +1,46 @@ +terraform { + backend "s3" { + endpoint = var.object_storage_endpoint + bucket = var.state_bucket + key = var.state_key + region = var.region + access_key = var.access_key + secret_key = var.secret_key + skip_credentials_validation = true + skip_region_validation = true + skip_requesting_account_id = true + force_path_style = true + } +} + +variable "object_storage_endpoint" { + description = "Vultr 对象存储的 S3 兼容 Endpoint (例如 https://ewr1.vultrobjects.com)" + type = string +} + +variable "state_bucket" { + description = "用于存储 Terraform state 的对象存储桶" + type = string +} + +variable "state_key" { + description = "state 文件路径,例如 vpc/dev/terraform.tfstate" + type = string +} + +variable "region" { + description = "Vultr 区域代码,例如 ewr、sgp、fra" + type = string +} + +variable "access_key" { + description = "对象存储访问密钥 Access Key" + type = string + sensitive = true +} + +variable "secret_key" { + description = "对象存储访问密钥 Secret Key" + type = string + sensitive = true +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/config/provider.tf b/iac-template/terraform-hcl-standard/vultr-vps/config/provider.tf new file mode 100644 index 00000000..d195873a --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/config/provider.tf @@ -0,0 +1,21 @@ +terraform { + required_version = ">= 1.5" + + required_providers { + vultr = { + source = "vultr/vultr" + version = "~> 2.19" + } + } +} + +provider "vultr" { + api_key = var.vultr_api_key + rate_limit = 700 +} + +variable "vultr_api_key" { + description = "Vultr API Key,建议通过环境变量 VULTR_API_KEY 提供" + type = string + sensitive = true +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/envs/dev/cloud-init.yaml b/iac-template/terraform-hcl-standard/vultr-vps/envs/dev/cloud-init.yaml new file mode 100644 index 00000000..2a68a607 --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/envs/dev/cloud-init.yaml @@ -0,0 +1,6 @@ +#cloud-config +package_update: true +package_upgrade: true +runcmd: + - echo "Hello from Vultr dev environment" > /etc/motd + - systemctl enable ssh diff --git a/iac-template/terraform-hcl-standard/vultr-vps/envs/dev/main.tf b/iac-template/terraform-hcl-standard/vultr-vps/envs/dev/main.tf new file mode 100644 index 00000000..03014d51 --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/envs/dev/main.tf @@ -0,0 +1,80 @@ +terraform { + required_version = ">= 1.5" + + required_providers { + vultr = { + source = "vultr/vultr" + version = "~> 2.19" + } + } +} + +provider "vultr" { + api_key = var.vultr_api_key +} + +module "vpc" { + source = "../modules/vpc" + region = var.region + description = var.vpc_description + v4_subnet = var.v4_subnet + v4_subnet_size = var.v4_subnet_size +} + +module "iam" { + source = "../modules/iam" + users = var.users + ssh_keys = var.ssh_keys +} + +module "storage" { + source = "../modules/storage" + region = var.region + cluster_id = var.cluster_id + object_bucket = var.object_bucket + enable_block = var.enable_block + block_size_gb = var.block_size_gb + label = "${var.name_prefix}-storage" +} + +module "compute" { + source = "../modules/compute" + label = "${var.name_prefix}-vm" + region = var.region + plan = var.plan + os_id = var.os_id + enable_ipv6 = true + backups = true + tags = [var.name_prefix, "dev"] + vpc_id = module.vpc.vpc_id + ssh_key_ids = values(module.iam.ssh_key_ids) + user_data = file(var.user_data_file) +} + +module "data_store" { + source = "../modules/data_store" + label = "${var.name_prefix}-db" + region = var.region + engine = var.db_engine + plan = var.db_plan + dbname = var.dbname + username = var.db_username + password = var.db_password + ha = var.db_ha +} + +output "vpc_id" { + value = module.vpc.vpc_id +} + +output "instance_ip" { + value = module.compute.main_ip +} + +output "bucket" { + value = module.storage.bucket_name +} + +output "database_dsn" { + value = module.data_store.dsn +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/envs/dev/variables.tf b/iac-template/terraform-hcl-standard/vultr-vps/envs/dev/variables.tf new file mode 100644 index 00000000..7646c499 --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/envs/dev/variables.tf @@ -0,0 +1,144 @@ +variable "vultr_api_key" { + description = "Vultr API Key" + type = string + sensitive = true +} + +variable "region" { + description = "部署区域" + type = string + default = "ewr" +} + +variable "vpc_description" { + description = "VPC 描述" + type = string + default = "dev-vpc" +} + +variable "v4_subnet" { + description = "VPC IPv4 段" + type = string + default = "10.20.0.0" +} + +variable "v4_subnet_size" { + description = "掩码位数" + type = number + default = 22 +} + +variable "cluster_id" { + description = "对象存储集群 ID" + type = string + default = "ewr1" +} + +variable "object_bucket" { + description = "对象存储桶名称" + type = string + default = "dev-app-bucket" +} + +variable "enable_block" { + description = "是否创建块存储" + type = bool + default = true +} + +variable "block_size_gb" { + description = "块存储大小" + type = number + default = 100 +} + +variable "name_prefix" { + description = "资源名前缀" + type = string + default = "demo" +} + +variable "plan" { + description = "实例套餐" + type = string + default = "vc2-1c-1gb" +} + +variable "os_id" { + description = "操作系统 ID" + type = number + default = 215 +} + +variable "users" { + description = "子账号配置" + type = list(object({ + email = string + password = string + acls = list(string) + })) + default = [ + { + email = "devops@example.com" + password = "ChangeMe123!" + acls = ["subscriptions", "support"] + } + ] +} + +variable "ssh_keys" { + description = "SSH 公钥列表" + type = list(object({ + name = string + public = string + })) + default = [ + { + name = "dev-key" + public = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKexamplegenerated dev@example" + } + ] +} + +variable "user_data_file" { + description = "cloud-init 脚本路径" + type = string + default = "cloud-init.yaml" +} + +variable "db_engine" { + description = "数据库引擎" + type = string + default = "pg" +} + +variable "db_plan" { + description = "数据库套餐" + type = string + default = "vultr-dbaas-startup-cc-1-7-5" +} + +variable "dbname" { + description = "数据库名称" + type = string + default = "app" +} + +variable "db_username" { + description = "数据库用户名" + type = string + default = "app" +} + +variable "db_password" { + description = "数据库密码" + type = string + sensitive = true + default = "ChangeMeP@ssw0rd" +} + +variable "db_ha" { + description = "启用数据库高可用" + type = bool + default = false +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/modules/compute/main.tf b/iac-template/terraform-hcl-standard/vultr-vps/modules/compute/main.tf new file mode 100644 index 00000000..0d453dac --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/modules/compute/main.tf @@ -0,0 +1,84 @@ +variable "label" { + description = "实例名称" + type = string +} + +variable "region" { + description = "Vultr 区域代码" + type = string +} + +variable "plan" { + description = "Vultr 计费套餐 (例如 vc2-1c-1gb)" + type = string +} + +variable "os_id" { + description = "操作系统 ID,参考 Vultr 文档 (例:215 为 Ubuntu 22.04)" + type = number +} + +variable "enable_ipv6" { + description = "是否启用 IPv6" + type = bool + default = true +} + +variable "backups" { + description = "启用自动备份" + type = bool + default = false +} + +variable "tags" { + description = "实例标签列表" + type = list(string) + default = [] +} + +variable "vpc_id" { + description = "可选的 VPC ID,将实例加入私网" + type = string + default = null +} + +variable "ssh_key_ids" { + description = "已上传的 SSH Key ID 列表" + type = list(string) + default = [] +} + +variable "user_data" { + description = "cloud-init 用户数据" + type = string + default = "" +} + +resource "vultr_instance" "this" { + label = var.label + region = var.region + plan = var.plan + os_id = var.os_id + enable_ipv6 = var.enable_ipv6 + backups = var.backups + tags = var.tags + vpc_ids = var.vpc_id == null ? [] : [var.vpc_id] + ssh_key_ids = var.ssh_key_ids + user_data = var.user_data +} + +output "instance_id" { + value = vultr_instance.this.id + description = "实例 ID" +} + +output "main_ip" { + value = vultr_instance.this.main_ip + description = "主公网 IP" +} + +output "default_password" { + value = vultr_instance.this.default_password + description = "系统生成密码(如未使用 SSH Key 时)" + sensitive = true +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/modules/data_store/main.tf b/iac-template/terraform-hcl-standard/vultr-vps/modules/data_store/main.tf new file mode 100644 index 00000000..7756e17a --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/modules/data_store/main.tf @@ -0,0 +1,72 @@ +variable "label" { + description = "数据库实例标签" + type = string + default = "app-db" +} + +variable "region" { + description = "Vultr 区域代码" + type = string +} + +variable "engine" { + description = "数据库引擎 (mysql, pg, redis)" + type = string +} + +variable "plan" { + description = "数据库套餐代号(如 vultr-dbaas-startup-cc-1-7-5)" + type = string +} + +variable "dbname" { + description = "数据库名称" + type = string + default = "app" +} + +variable "username" { + description = "数据库用户名" + type = string + default = "app" +} + +variable "password" { + description = "数据库密码" + type = string + sensitive = true +} + +variable "ha" { + description = "启用高可用" + type = bool + default = false +} + +resource "vultr_database" "this" { + label = var.label + region = var.region + plan = var.plan + engine = var.engine + replicas = var.ha ? 1 : 0 + + database = var.dbname + username = var.username + password = var.password +} + +output "dsn" { + description = "标准连接串(host:port/database)" + value = "${vultr_database.this.hostname}:${vultr_database.this.port}/${vultr_database.this.database}" +} + +output "username" { + value = vultr_database.this.username + description = "数据库用户名" +} + +output "password" { + value = vultr_database.this.password + sensitive = true + description = "数据库密码" +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/modules/iam/main.tf b/iac-template/terraform-hcl-standard/vultr-vps/modules/iam/main.tf new file mode 100644 index 00000000..8ab8c19a --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/modules/iam/main.tf @@ -0,0 +1,42 @@ +variable "users" { + description = "需要创建的子账号列表" + type = list(object({ + email = string + password = string + acls = list(string) + })) + default = [] +} + +variable "ssh_keys" { + description = "需要上传的 SSH 公钥列表" + type = list(object({ + name = string + public = string + })) + default = [] +} + +resource "vultr_user" "this" { + for_each = { for u in var.users : u.email => u } + email = each.value.email + password = each.value.password + api_enabled = true + acls = each.value.acls +} + +resource "vultr_ssh_key" "this" { + for_each = { for k in var.ssh_keys : k.name => k } + name = each.value.name + ssh_key = each.value.public +} + +output "user_ids" { + value = { for k, v in vultr_user.this : k => v.id } + description = "创建的子账号 ID 映射" +} + +output "ssh_key_ids" { + value = { for k, v in vultr_ssh_key.this : k => v.id } + description = "上传的 SSH Key ID 映射" +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/modules/storage/main.tf b/iac-template/terraform-hcl-standard/vultr-vps/modules/storage/main.tf new file mode 100644 index 00000000..c4de9585 --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/modules/storage/main.tf @@ -0,0 +1,80 @@ +variable "region" { + description = "Vultr 区域代码" + type = string +} + +variable "object_bucket" { + description = "对象存储桶名称" + type = string +} + +variable "cluster_id" { + description = "对象存储集群 ID (如 ewr1)" + type = string +} + +variable "enable_block" { + description = "是否同时创建块存储卷" + type = bool + default = false +} + +variable "block_size_gb" { + description = "块存储大小 (GB)" + type = number + default = 100 +} + +variable "label" { + description = "资源标签" + type = string + default = "app-storage" +} + +resource "vultr_object_storage" "bucket" { + region = var.region + cluster_id = var.cluster_id + label = var.label + bucket_name = var.object_bucket + minio_access = true +} + +resource "vultr_object_storage_key" "bucket" { + object_storage_id = vultr_object_storage.bucket.id + description = "app-storage" +} + +resource "vultr_block_storage" "volume" { + count = var.enable_block ? 1 : 0 + region = var.region + label = "${var.label}-block" + size_gb = var.block_size_gb + block_type = "storage_opt" +} + +output "bucket_name" { + value = vultr_object_storage.bucket.bucket_name + description = "创建的对象存储桶" +} + +output "bucket_endpoint" { + value = vultr_object_storage.bucket.s3_hostname + description = "S3 兼容 Endpoint" +} + +output "access_key" { + value = vultr_object_storage_key.bucket.access_key + sensitive = true + description = "对象存储 Access Key" +} + +output "secret_key" { + value = vultr_object_storage_key.bucket.secret_key + sensitive = true + description = "对象存储 Secret Key" +} + +output "block_volume_id" { + value = try(vultr_block_storage.volume[0].id, null) + description = "可选块存储卷 ID" +} diff --git a/iac-template/terraform-hcl-standard/vultr-vps/modules/vpc/main.tf b/iac-template/terraform-hcl-standard/vultr-vps/modules/vpc/main.tf new file mode 100644 index 00000000..3f020587 --- /dev/null +++ b/iac-template/terraform-hcl-standard/vultr-vps/modules/vpc/main.tf @@ -0,0 +1,32 @@ +variable "region" { + description = "Vultr 区域代码" + type = string +} + +variable "description" { + description = "VPC 描述标签" + type = string + default = "app-vpc" +} + +variable "v4_subnet" { + description = "VPC 的 IPv4 子网,例如 10.10.0.0/22" + type = string +} + +variable "v4_subnet_size" { + description = "子网掩码位数,Vultr 需要单独传递" + type = number +} + +resource "vultr_vpc" "this" { + region = var.region + description = var.description + v4_subnet = var.v4_subnet + v4_subnet_size = var.v4_subnet_size +} + +output "vpc_id" { + value = vultr_vpc.this.id + description = "创建的 VPC ID" +}