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
This commit is contained in:
parent
338090a8f3
commit
3765f0192c
31
iac-template/terraform-hcl-standard/ali-cloud/README.md
Normal file
31
iac-template/terraform-hcl-standard/ali-cloud/README.md
Normal file
@ -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 代码。
|
||||
@ -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
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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 = <<POLICY
|
||||
{
|
||||
"Version": "1",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": "sts:AssumeRole",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"RAM": ["${local.assume_principal}"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
description = "Role assumed by CI/CD or operators for Terraform"
|
||||
force = true
|
||||
}
|
||||
|
||||
resource "alicloud_ram_policy" "terraform_admin" {
|
||||
name = var.policy_name
|
||||
description = "Terraform administrative access"
|
||||
document = <<POLICY
|
||||
{
|
||||
"Version": "1",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"ecs:*",
|
||||
"vpc:*",
|
||||
"oss:*",
|
||||
"ram:*",
|
||||
"slb:*",
|
||||
"alb:*",
|
||||
"rds:*",
|
||||
"kvstore:*"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
force = true
|
||||
}
|
||||
|
||||
resource "alicloud_ram_role_policy_attachment" "role_attach" {
|
||||
policy_name = alicloud_ram_policy.terraform_admin.name
|
||||
policy_type = alicloud_ram_policy.terraform_admin.type
|
||||
role_name = alicloud_ram_role.terraform.name
|
||||
}
|
||||
|
||||
resource "alicloud_ram_user" "terraform" {
|
||||
name = var.user_name
|
||||
display_name = "terraform-automation"
|
||||
force = true
|
||||
}
|
||||
|
||||
resource "alicloud_ram_user_policy_attachment" "user_attach" {
|
||||
policy_name = alicloud_ram_policy.terraform_admin.name
|
||||
policy_type = alicloud_ram_policy.terraform_admin.type
|
||||
user_name = alicloud_ram_user.terraform.name
|
||||
}
|
||||
|
||||
resource "alicloud_ram_access_key" "terraform" {
|
||||
user_name = alicloud_ram_user.terraform.name
|
||||
}
|
||||
|
||||
output "ram_role_name" {
|
||||
value = alicloud_ram_role.terraform.name
|
||||
}
|
||||
|
||||
output "ram_user_name" {
|
||||
value = alicloud_ram_user.terraform.name
|
||||
}
|
||||
|
||||
output "access_key_id" {
|
||||
value = alicloud_ram_access_key.terraform.id
|
||||
description = "Access key ID for terraform user"
|
||||
}
|
||||
|
||||
output "access_key_secret" {
|
||||
value = alicloud_ram_access_key.terraform.secret
|
||||
description = "Access key secret for terraform user"
|
||||
sensitive = true
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
variable "region" {
|
||||
description = "Alibaba Cloud region"
|
||||
type = string
|
||||
default = "cn-hangzhou"
|
||||
}
|
||||
|
||||
variable "account_id" {
|
||||
description = "Alibaba Cloud account ID used for trust policy"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "role_name" {
|
||||
description = "Name of RAM role used by Terraform"
|
||||
type = string
|
||||
default = "TerraformExecutionRole"
|
||||
}
|
||||
|
||||
variable "policy_name" {
|
||||
description = "Custom policy name granting Terraform permissions"
|
||||
type = string
|
||||
default = "TerraformAdministrator"
|
||||
}
|
||||
|
||||
variable "user_name" {
|
||||
description = "Name of RAM user for Terraform automation"
|
||||
type = string
|
||||
default = "terraform"
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5.0"
|
||||
|
||||
backend "oss" {
|
||||
bucket = var.state_bucket
|
||||
prefix = var.state_prefix
|
||||
region = var.region
|
||||
tablestore_table = var.lock_table
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
alicloud = {
|
||||
source = "aliyun/alicloud"
|
||||
version = ">= 1.210.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "alicloud" {
|
||||
region = var.region
|
||||
access_key = var.access_key
|
||||
secret_key = var.secret_key
|
||||
security_token = var.security_token
|
||||
|
||||
dynamic "assume_role" {
|
||||
for_each = var.ram_role_arn == null ? [] : [var.ram_role_arn]
|
||||
content {
|
||||
role_arn = assume_role.value
|
||||
session_name = var.session_name
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
variable "region" {
|
||||
description = "Default Alibaba Cloud region"
|
||||
type = string
|
||||
default = "cn-hangzhou"
|
||||
}
|
||||
|
||||
variable "access_key" {
|
||||
description = "Alibaba Cloud Access Key ID"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "secret_key" {
|
||||
description = "Alibaba Cloud Access Key Secret"
|
||||
type = string
|
||||
default = null
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "security_token" {
|
||||
description = "Optional security token when using STS credentials"
|
||||
type = string
|
||||
default = null
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "ram_role_arn" {
|
||||
description = "Optional RAM role ARN to assume for operations"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "session_name" {
|
||||
description = "Session name when assuming a RAM role"
|
||||
type = string
|
||||
default = "terraform"
|
||||
}
|
||||
|
||||
variable "state_bucket" {
|
||||
description = "OSS bucket used for Terraform remote state"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "state_prefix" {
|
||||
description = "Prefix within the remote state bucket"
|
||||
type = string
|
||||
default = "terraform/state"
|
||||
}
|
||||
|
||||
variable "lock_table" {
|
||||
description = "OTS table used for state locking"
|
||||
type = string
|
||||
default = "terraform-locks"
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5.0"
|
||||
required_providers {
|
||||
alicloud = {
|
||||
source = "aliyun/alicloud"
|
||||
version = ">= 1.210.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "alicloud" {
|
||||
region = var.region
|
||||
}
|
||||
|
||||
module "network" {
|
||||
source = "../modules/vpc"
|
||||
name = var.vpc_name
|
||||
cidr_block = var.vpc_cidr
|
||||
vswitches = var.vswitches
|
||||
}
|
||||
|
||||
locals {
|
||||
zone_mappings = [for key, cfg in var.vswitches : {
|
||||
vswitch_id = module.network.vswitch_ids[key]
|
||||
zone_id = cfg.az
|
||||
}]
|
||||
primary_vswitch = module.network.vswitch_ids[local.primary_vswitch_key]
|
||||
primary_vswitch_key = keys(module.network.vswitch_ids)[0]
|
||||
}
|
||||
|
||||
module "alb" {
|
||||
source = "../modules/alb"
|
||||
name = "dev-alb"
|
||||
vpc_id = module.network.vpc_id
|
||||
zone_mappings = local.zone_mappings
|
||||
address_type = "Internet"
|
||||
edition = "Standard"
|
||||
protocol = "HTTP"
|
||||
listener_port = 80
|
||||
}
|
||||
|
||||
module "nlb" {
|
||||
source = "../modules/nlb"
|
||||
name = "dev-nlb"
|
||||
vswitch_id = local.primary_vswitch
|
||||
address_type = "Internet"
|
||||
spec = "slb.s2.small"
|
||||
protocol = "tcp"
|
||||
frontend_port = 443
|
||||
backend_port = 443
|
||||
}
|
||||
|
||||
module "bucket" {
|
||||
source = "../modules/oss"
|
||||
name = var.bucket_name
|
||||
enable_versioning = true
|
||||
}
|
||||
|
||||
module "compute" {
|
||||
source = "../modules/ecs"
|
||||
name = "dev-ecs"
|
||||
vpc_id = module.network.vpc_id
|
||||
vswitch_id = local.primary_vswitch
|
||||
instance_type = var.instance_type
|
||||
image_id = var.image_id
|
||||
key_name = var.key_name
|
||||
internet_max_bandwidth_out = 50
|
||||
}
|
||||
|
||||
module "database" {
|
||||
source = "../modules/rds"
|
||||
vpc_id = module.network.vpc_id
|
||||
vswitch_id = local.primary_vswitch
|
||||
engine = "MySQL"
|
||||
engine_version = "8.0"
|
||||
instance_type = var.rds_instance_type
|
||||
account_password = var.rds_password
|
||||
}
|
||||
|
||||
module "cache" {
|
||||
source = "../modules/redis"
|
||||
name = "dev-redis"
|
||||
vpc_id = module.network.vpc_id
|
||||
vswitch_id = local.primary_vswitch
|
||||
password = var.redis_password
|
||||
engine_version = "6.0"
|
||||
}
|
||||
|
||||
output "vpc_id" {
|
||||
value = module.network.vpc_id
|
||||
}
|
||||
|
||||
output "alb_endpoint" {
|
||||
value = module.alb.alb_id
|
||||
}
|
||||
|
||||
output "ecs_instance" {
|
||||
value = module.compute.instance_id
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
variable "region" {
|
||||
description = "Deployment region"
|
||||
type = string
|
||||
default = "cn-hangzhou"
|
||||
}
|
||||
|
||||
variable "vpc_name" {
|
||||
description = "VPC name"
|
||||
type = string
|
||||
default = "dev-vpc"
|
||||
}
|
||||
|
||||
variable "vpc_cidr" {
|
||||
description = "VPC CIDR"
|
||||
type = string
|
||||
default = "10.10.0.0/16"
|
||||
}
|
||||
|
||||
variable "vswitches" {
|
||||
description = "Map of vswitch definitions"
|
||||
type = map(object({
|
||||
cidr = string
|
||||
az = string
|
||||
}))
|
||||
default = {
|
||||
a = { cidr = "10.10.1.0/24", az = "cn-hangzhou-b" }
|
||||
b = { cidr = "10.10.2.0/24", az = "cn-hangzhou-c" }
|
||||
}
|
||||
}
|
||||
|
||||
variable "instance_type" {
|
||||
description = "ECS instance type"
|
||||
type = string
|
||||
default = "ecs.g6.large"
|
||||
}
|
||||
|
||||
variable "image_id" {
|
||||
description = "ECS image ID"
|
||||
type = string
|
||||
default = "aliyun_2_1903_x64_20G_alibase_20240223.vhd"
|
||||
}
|
||||
|
||||
variable "key_name" {
|
||||
description = "SSH key pair name"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "bucket_name" {
|
||||
description = "OSS bucket name"
|
||||
type = string
|
||||
default = "dev-terraform-oss"
|
||||
}
|
||||
|
||||
variable "rds_instance_type" {
|
||||
description = "RDS instance type"
|
||||
type = string
|
||||
default = "rds.mysql.c1.large"
|
||||
}
|
||||
|
||||
variable "rds_password" {
|
||||
description = "RDS account password"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "redis_password" {
|
||||
description = "Redis password"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
resource "alicloud_alb_load_balancer" "this" {
|
||||
load_balancer_name = var.name
|
||||
address_type = var.address_type
|
||||
load_balancer_edition = var.edition
|
||||
vpc_id = var.vpc_id
|
||||
address_allocated_mode = "Dynamic"
|
||||
|
||||
dynamic "zone_mappings" {
|
||||
for_each = var.zone_mappings
|
||||
content {
|
||||
vswitch_id = zone_mappings.value.vswitch_id
|
||||
zone_id = zone_mappings.value.zone_id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "alicloud_alb_server_group" "this" {
|
||||
server_group_name = "${var.name}-sg"
|
||||
vpc_id = var.vpc_id
|
||||
protocol = var.protocol
|
||||
}
|
||||
|
||||
resource "alicloud_alb_listener" "http" {
|
||||
load_balancer_id = alicloud_alb_load_balancer.this.id
|
||||
listener_port = var.listener_port
|
||||
listener_protocol = var.protocol
|
||||
|
||||
default_actions {
|
||||
type = "ForwardGroup"
|
||||
|
||||
forward_group_config {
|
||||
server_group_tuples {
|
||||
server_group_id = alicloud_alb_server_group.this.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "alb_id" {
|
||||
value = alicloud_alb_load_balancer.this.id
|
||||
}
|
||||
|
||||
output "listener_id" {
|
||||
value = alicloud_alb_listener.http.id
|
||||
}
|
||||
|
||||
output "server_group_id" {
|
||||
value = alicloud_alb_server_group.this.id
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
variable "name" {
|
||||
description = "ALB name"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "vpc_id" {
|
||||
description = "VPC ID for the ALB"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "address_type" {
|
||||
description = "Address type: Internet or Intranet"
|
||||
type = string
|
||||
default = "Internet"
|
||||
}
|
||||
|
||||
variable "edition" {
|
||||
description = "Load balancer edition"
|
||||
type = string
|
||||
default = "Standard"
|
||||
}
|
||||
|
||||
variable "protocol" {
|
||||
description = "Listener protocol"
|
||||
type = string
|
||||
default = "HTTP"
|
||||
}
|
||||
|
||||
variable "listener_port" {
|
||||
description = "Listener port"
|
||||
type = number
|
||||
default = 80
|
||||
}
|
||||
|
||||
variable "zone_mappings" {
|
||||
description = "List of zone mappings with vswitch_id and zone_id"
|
||||
type = list(object({
|
||||
vswitch_id = string
|
||||
zone_id = string
|
||||
}))
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
resource "alicloud_security_group" "this" {
|
||||
name = "${var.name}-sg"
|
||||
vpc_id = var.vpc_id
|
||||
}
|
||||
|
||||
resource "alicloud_security_group_rule" "ssh" {
|
||||
type = "ingress"
|
||||
ip_protocol = "tcp"
|
||||
nic_type = "intranet"
|
||||
policy = "accept"
|
||||
port_range = "22/22"
|
||||
priority = 1
|
||||
security_group_id = alicloud_security_group.this.id
|
||||
cidr_ip = var.ssh_cidr
|
||||
}
|
||||
|
||||
resource "alicloud_instance" "this" {
|
||||
instance_name = var.name
|
||||
host_name = var.name
|
||||
image_id = var.image_id
|
||||
instance_type = var.instance_type
|
||||
vswitch_id = var.vswitch_id
|
||||
security_groups = [alicloud_security_group.this.id]
|
||||
system_disk_category = var.system_disk_category
|
||||
system_disk_size = var.system_disk_size
|
||||
internet_max_bandwidth_out = var.internet_max_bandwidth_out
|
||||
key_name = var.key_name
|
||||
user_data = var.user_data
|
||||
}
|
||||
|
||||
output "instance_id" {
|
||||
value = alicloud_instance.this.id
|
||||
}
|
||||
|
||||
output "private_ip" {
|
||||
value = alicloud_instance.this.private_ip
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
variable "name" {
|
||||
description = "ECS instance name"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "vpc_id" {
|
||||
description = "VPC ID for the ECS instance"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "vswitch_id" {
|
||||
description = "VSwitch ID to place the instance"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "image_id" {
|
||||
description = "Image ID"
|
||||
type = string
|
||||
default = "aliyun_2_1903_x64_20G_alibase_20240223.vhd"
|
||||
}
|
||||
|
||||
variable "instance_type" {
|
||||
description = "Instance type"
|
||||
type = string
|
||||
default = "ecs.g6.large"
|
||||
}
|
||||
|
||||
variable "system_disk_category" {
|
||||
description = "System disk category"
|
||||
type = string
|
||||
default = "cloud_essd"
|
||||
}
|
||||
|
||||
variable "system_disk_size" {
|
||||
description = "System disk size in GB"
|
||||
type = number
|
||||
default = 40
|
||||
}
|
||||
|
||||
variable "internet_max_bandwidth_out" {
|
||||
description = "Max outbound bandwidth"
|
||||
type = number
|
||||
default = 10
|
||||
}
|
||||
|
||||
variable "key_name" {
|
||||
description = "SSH key pair name"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "ssh_cidr" {
|
||||
description = "CIDR allowed for SSH"
|
||||
type = string
|
||||
default = "0.0.0.0/0"
|
||||
}
|
||||
|
||||
variable "user_data" {
|
||||
description = "Optional user data"
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
resource "alicloud_slb_load_balancer" "this" {
|
||||
name = var.name
|
||||
address_type = var.address_type
|
||||
load_balancer_spec = var.spec
|
||||
vswitch_id = var.vswitch_id
|
||||
internet_charge_type = "paybytraffic"
|
||||
}
|
||||
|
||||
resource "alicloud_slb_server_group" "this" {
|
||||
load_balancer_id = alicloud_slb_load_balancer.this.id
|
||||
name = "${var.name}-sg"
|
||||
}
|
||||
|
||||
resource "alicloud_slb_listener" "tcp" {
|
||||
load_balancer_id = alicloud_slb_load_balancer.this.id
|
||||
backend_port = var.backend_port
|
||||
frontend_port = var.frontend_port
|
||||
bandwidth = -1
|
||||
protocol = var.protocol
|
||||
|
||||
health_check {
|
||||
health_check_interval = 5
|
||||
healthy_threshold = 3
|
||||
unhealthy_threshold = 3
|
||||
}
|
||||
}
|
||||
|
||||
output "nlb_id" {
|
||||
value = alicloud_slb_load_balancer.this.id
|
||||
}
|
||||
|
||||
output "listener_id" {
|
||||
value = alicloud_slb_listener.tcp.id
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
variable "name" {
|
||||
description = "SLB/NLB name"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "vswitch_id" {
|
||||
description = "VSwitch ID for the load balancer"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "address_type" {
|
||||
description = "Address type"
|
||||
type = string
|
||||
default = "Internet"
|
||||
}
|
||||
|
||||
variable "spec" {
|
||||
description = "Load balancer specification"
|
||||
type = string
|
||||
default = "slb.s2.small"
|
||||
}
|
||||
|
||||
variable "protocol" {
|
||||
description = "Listener protocol"
|
||||
type = string
|
||||
default = "tcp"
|
||||
}
|
||||
|
||||
variable "frontend_port" {
|
||||
description = "Frontend listener port"
|
||||
type = number
|
||||
default = 80
|
||||
}
|
||||
|
||||
variable "backend_port" {
|
||||
description = "Backend server port"
|
||||
type = number
|
||||
default = 80
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
resource "alicloud_oss_bucket" "this" {
|
||||
bucket = var.name
|
||||
acl = var.acl
|
||||
|
||||
versioning {
|
||||
status = var.enable_versioning ? "Enabled" : "Suspended"
|
||||
}
|
||||
|
||||
server_side_encryption_rule {
|
||||
sse_algorithm = var.sse_algorithm
|
||||
}
|
||||
}
|
||||
|
||||
output "bucket" {
|
||||
value = alicloud_oss_bucket.this.bucket
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
variable "name" {
|
||||
description = "OSS bucket name"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "acl" {
|
||||
description = "Bucket ACL"
|
||||
type = string
|
||||
default = "private"
|
||||
}
|
||||
|
||||
variable "enable_versioning" {
|
||||
description = "Enable bucket versioning"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "sse_algorithm" {
|
||||
description = "Server-side encryption algorithm"
|
||||
type = string
|
||||
default = "AES256"
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
locals {
|
||||
principals = [for principal in var.assume_principals : "acs:ram::${principal}:root"]
|
||||
}
|
||||
|
||||
resource "alicloud_ram_role" "this" {
|
||||
name = var.role_name
|
||||
document = jsonencode({
|
||||
Version = "1"
|
||||
Statement = [{
|
||||
Action = "sts:AssumeRole"
|
||||
Effect = "Allow"
|
||||
Principal = { RAM = local.principals }
|
||||
}]
|
||||
})
|
||||
description = var.description
|
||||
force = true
|
||||
}
|
||||
|
||||
resource "alicloud_ram_policy" "this" {
|
||||
name = var.policy_name
|
||||
description = "Custom RAM policy"
|
||||
document = jsonencode({
|
||||
Version = "1"
|
||||
Statement = [{
|
||||
Action = var.actions
|
||||
Effect = "Allow"
|
||||
Resource = var.resource
|
||||
}]
|
||||
})
|
||||
force = true
|
||||
}
|
||||
|
||||
resource "alicloud_ram_role_policy_attachment" "attachment" {
|
||||
policy_name = alicloud_ram_policy.this.name
|
||||
policy_type = alicloud_ram_policy.this.type
|
||||
role_name = alicloud_ram_role.this.name
|
||||
}
|
||||
|
||||
output "role_name" {
|
||||
value = alicloud_ram_role.this.name
|
||||
}
|
||||
|
||||
output "policy_name" {
|
||||
value = alicloud_ram_policy.this.name
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
variable "role_name" {
|
||||
description = "RAM role name"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "policy_name" {
|
||||
description = "Policy name"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "assume_principals" {
|
||||
description = "List of account IDs allowed to assume the role"
|
||||
type = list(string)
|
||||
}
|
||||
|
||||
variable "actions" {
|
||||
description = "Actions allowed by the policy"
|
||||
type = list(string)
|
||||
}
|
||||
|
||||
variable "resource" {
|
||||
description = "Resource ARN(s)"
|
||||
type = string
|
||||
default = "*"
|
||||
}
|
||||
|
||||
variable "description" {
|
||||
description = "Role description"
|
||||
type = string
|
||||
default = "Custom RAM role"
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
resource "alicloud_db_instance" "this" {
|
||||
engine = var.engine
|
||||
engine_version = var.engine_version
|
||||
instance_type = var.instance_type
|
||||
db_instance_storage_type = var.storage_type
|
||||
db_instance_storage = var.storage
|
||||
instance_charge_type = "PostPaid"
|
||||
vswitch_id = var.vswitch_id
|
||||
vpc_id = var.vpc_id
|
||||
security_ip_list = join(",", var.security_ips)
|
||||
}
|
||||
|
||||
resource "alicloud_db_account" "this" {
|
||||
db_instance_id = alicloud_db_instance.this.id
|
||||
account_name = var.account_name
|
||||
account_password = var.account_password
|
||||
}
|
||||
|
||||
resource "alicloud_db_database" "this" {
|
||||
count = var.create_database ? 1 : 0
|
||||
db_instance_id = alicloud_db_instance.this.id
|
||||
name = var.database_name
|
||||
character_set = "utf8mb4"
|
||||
description = "managed by terraform"
|
||||
}
|
||||
|
||||
output "instance_id" {
|
||||
value = alicloud_db_instance.this.id
|
||||
}
|
||||
|
||||
output "connection_string" {
|
||||
value = alicloud_db_instance.this.connection_string
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
variable "engine" {
|
||||
description = "Database engine"
|
||||
type = string
|
||||
default = "MySQL"
|
||||
}
|
||||
|
||||
variable "engine_version" {
|
||||
description = "Engine version"
|
||||
type = string
|
||||
default = "8.0"
|
||||
}
|
||||
|
||||
variable "instance_type" {
|
||||
description = "RDS instance type"
|
||||
type = string
|
||||
default = "rds.mysql.c1.large"
|
||||
}
|
||||
|
||||
variable "storage_type" {
|
||||
description = "Storage type"
|
||||
type = string
|
||||
default = "cloud_essd"
|
||||
}
|
||||
|
||||
variable "storage" {
|
||||
description = "Storage size in GB"
|
||||
type = number
|
||||
default = 50
|
||||
}
|
||||
|
||||
variable "vpc_id" {
|
||||
description = "VPC ID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "vswitch_id" {
|
||||
description = "VSwitch ID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "security_ips" {
|
||||
description = "List of IPs allowed to access RDS"
|
||||
type = list(string)
|
||||
default = ["0.0.0.0/0"]
|
||||
}
|
||||
|
||||
variable "account_name" {
|
||||
description = "Database account name"
|
||||
type = string
|
||||
default = "terraform"
|
||||
}
|
||||
|
||||
variable "account_password" {
|
||||
description = "Database account password"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "create_database" {
|
||||
description = "Whether to create a database"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "database_name" {
|
||||
description = "Database name"
|
||||
type = string
|
||||
default = "appdb"
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
resource "alicloud_kvstore_instance" "this" {
|
||||
instance_name = var.name
|
||||
instance_class = var.instance_class
|
||||
engine_version = var.engine_version
|
||||
vswitch_id = var.vswitch_id
|
||||
vpc_id = var.vpc_id
|
||||
password = var.password
|
||||
payment_type = "PostPaid"
|
||||
}
|
||||
|
||||
output "instance_id" {
|
||||
value = alicloud_kvstore_instance.this.id
|
||||
}
|
||||
|
||||
output "connection_string" {
|
||||
value = alicloud_kvstore_instance.this.connection_domain
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
variable "name" {
|
||||
description = "Redis instance name"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "instance_class" {
|
||||
description = "Instance class"
|
||||
type = string
|
||||
default = "redis.master.small.default"
|
||||
}
|
||||
|
||||
variable "engine_version" {
|
||||
description = "Redis engine version"
|
||||
type = string
|
||||
default = "6.0"
|
||||
}
|
||||
|
||||
variable "vpc_id" {
|
||||
description = "VPC ID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "vswitch_id" {
|
||||
description = "VSwitch ID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "password" {
|
||||
description = "Instance password"
|
||||
type = string
|
||||
sensitive = true
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
resource "alicloud_vpc" "this" {
|
||||
name = var.name
|
||||
cidr_block = var.cidr_block
|
||||
}
|
||||
|
||||
resource "alicloud_vswitch" "this" {
|
||||
for_each = var.vswitches
|
||||
vpc_id = alicloud_vpc.this.id
|
||||
cidr_block = each.value.cidr
|
||||
zone_id = each.value.az
|
||||
vswitch_name = "${var.name}-${each.key}"
|
||||
}
|
||||
|
||||
output "vpc_id" {
|
||||
value = alicloud_vpc.this.id
|
||||
}
|
||||
|
||||
output "vswitch_ids" {
|
||||
value = { for k, v in alicloud_vswitch.this : k => v.id }
|
||||
}
|
||||
@ -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
|
||||
}))
|
||||
}
|
||||
33
iac-template/terraform-hcl-standard/azure-cloud/README.md
Normal file
33
iac-template/terraform-hcl-standard/azure-cloud/README.md
Normal file
@ -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 模板。
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
backend "azurerm" {
|
||||
# 请在使用前替换为实际资源组、存储账户、容器和状态文件名
|
||||
resource_group_name = "tfstate-rg"
|
||||
storage_account_name = "tfstateaccount"
|
||||
container_name = "tfstate"
|
||||
key = "terraform.tfstate"
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
142
iac-template/terraform-hcl-standard/azure-cloud/envs/dev/main.tf
Normal file
142
iac-template/terraform-hcl-standard/azure-cloud/envs/dev/main.tf
Normal file
@ -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
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
32
iac-template/terraform-hcl-standard/gcp-cloud/README.md
Normal file
32
iac-template/terraform-hcl-standard/gcp-cloud/README.md
Normal file
@ -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 模板。
|
||||
@ -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
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = ">= 1.5.0"
|
||||
|
||||
backend "gcs" {
|
||||
bucket = var.state_bucket
|
||||
prefix = var.state_prefix
|
||||
project = var.project_id
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
36
iac-template/terraform-hcl-standard/vultr-vps/README.md
Normal file
36
iac-template/terraform-hcl-standard/vultr-vps/README.md
Normal file
@ -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 模板。
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
#cloud-config
|
||||
package_update: true
|
||||
package_upgrade: true
|
||||
runcmd:
|
||||
- echo "Hello from Vultr dev environment" > /etc/motd
|
||||
- systemctl enable ssh
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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 = "数据库密码"
|
||||
}
|
||||
@ -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 映射"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
@ -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"
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user