操作说明
本方案基于天翼云 ROS(资源编排服务)控制台,采用 Terraform Module 模块化设计,实现赛事用云主机全流程自动化批量部署。用户仅需导入模板、配置核心参数,即可一键完成 VPC、子网、安全组规则、云主机、弹性 IP 等全套网络与计算资源的自动化创建,全程无需手动操作。
通过模块化封装,方案支持灵活自定义可用区、网络网段、实例规格及部署数量,同时内置安全密码自动生成能力,可满足网络安全赛事、攻防演练、CTF 竞赛等场景下的多组别隔离、环境统一与快速交付需求,实现资源部署高效化、运行环境标准化、运维管理轻量化,为各类赛事靶机环境提供稳定、便捷的规模化交付能力。
适用场景
网络安全赛事靶机批量快速开通与统一部署
多组别、多题型竞赛环境的标准化网络搭建
攻防演练、CTF 赛事多镜像靶场环境一致性交付
临时赛事训练、演示环境快速创建与赛后一键回收
需自定义网段、靶机规格与资源隔离的规模化赛事场景
核心能力
在 ROS 控制台中:
导入模板(基于 Terraform 语法适配)
核心参数配置:配置实例数量(instance_count)、可用区选择、镜像、云主机规格等等
一键创建资源栈
即可自动完成:
多VPC和子网自动创建与分配
N 台云主机批量创建
弹性公网 IP 自动绑定
符合安全规范的随机密码自动生成
同时支持一键删除资源栈,实现全量资源自动回收
操作步骤
登录控制中心。
在控制台首页搜索“资源编排ROS”,或在左侧产品导航栏选择“管理工具 > 资源编排ROS”,进入资源编排控制台。
在左侧导航栏选择 模板管理。
在模板管理页面,单击创建模板。
本方案模板示例如下(该模板默认基于华东1资源池, 可以根据需要可以进行调整),请参考文档创建模板完成模板配置。
模板目录结构:
│ main.tf
│
├───ecs
│ main.tf
│ variables.tf
│
└───vpc
main.tf
variables.tf
注意:provider版本至少使用2.1.0
main.tf
terraform {
required_providers {
ctyun = {
source = "ctyun-it/ctyun"
version = "2.1.0"
}
}
}
provider "ctyun" {
az_name = var.az_name
}
variable "az_name" {
type = string
default = "cn-huadong1-jsnj1A-public-ctcloud"
description = "可用区名称"
}
variable "vpc_name" {
type = string
default = "test-vpc"
description = "VPC名称"
}
variable "subnet_name" {
type = string
default = "test-subnet"
description = "子网名称"
}
variable "cidr" {
type = list(string)
default = ["172.18.1.0/24", "172.18.2.0/24"]
description = "CIDR"
}
variable "instance_name" {
type = string
default = "test-ecs"
description = "云主机名称"
}
variable "instance_count" {
type = number
default = 4
description = "云主机数量"
}
variable "image_id" {
type = string
default = "f9415853-b07d-4dd8-afb7-f48e10de151e"
description = "镜像ID"
}
variable "flavor_name" {
type = string
default = "c7.xlarge.2"
description = "规格名称"
}
variable "system_disk_type" {
type = string
default = "sas"
description = "系统盘类型"
}
variable "system_disk_size" {
type = number
default = 40
description = "系统盘大小"
}
variable "bandwidth" {
type = number
default = 10
description = "公网带宽"
}
variable "password_seed" {
type = string
default = "random_password_seed"
description = "随机密码种子"
}
# 配置VPC、子网和安全组规则
locals {
sg_rules = [
{
range = "8000-9000",
dest_cidr_ip = "222.71.48.90/32"
protocol = "tcp"
direction = "ingress"
},
]
}
module "vpc" {
source = "./vpc"
vpc_name_prefix = var.vpc_name
subnet_name_prefix = var.subnet_name
cidr = var.cidr
sg_rules = local.sg_rules
}
# 创建云主机和弹性IP并绑定
module "ecs" {
source = "./ecs"
ecs_count = var.instance_count
instance_name_prefix = var.instance_name
display_name_prefix = var.instance_name
flavor_name = var.flavor_name
system_disk_type = var.system_disk_type
system_disk_size = var.system_disk_size
image_id = var.image_id
bandwidth = var.bandwidth
vpc_ids = module.vpc.vpc_id
subnet_ids = module.vpc.subnet_id
passwords = local.passwords
}
# 输出主机信息
output "ecs_eip" {
value = [
for idx, e in module.ecs.ecs_list : {
ecs_id = module.ecs.ecs_list[idx].id
ecs_name = module.ecs.ecs_list[idx].display_name
fixed_ip = module.ecs.ecs_list[idx].fixed_ip
eip_address = module.ecs.ecs_list[idx].eip_address
password = local.passwords[idx]
}
]
}
locals {
seed_list = [for i in range(var.instance_count) : "${var.password_seed}-${i}"]
passwords = [
for seed in local.seed_list :
format(
"%s%s%s",
substr(replace(upper(sha256(seed)), "/[^A-Za-z0-9]/", ""), 0, 5),
"A@a",
substr(replace(lower(sha256(seed)), "/[^A-Za-z0-9]/", ""), 5, 5),
)
]
}ecs\main.tf
terraform {
required_providers {
ctyun = {
source = "ctyun-it/ctyun"
version = "2.1.0"
}
}
}
locals {
vpc_count = length(var.vpc_ids)
}
# 创建绑定EIP的云主机
resource "ctyun_ecs" "ecs" {
count = var.ecs_count
instance_name = "${var.instance_name_prefix}-${count.index + 1}"
display_name = "${var.display_name_prefix}-${count.index + 1}"
flavor_name = var.flavor_name
image_id = var.image_id
system_disk_type = var.system_disk_type
system_disk_size = var.system_disk_size
vpc_id = var.vpc_ids[count.index % local.vpc_count]
subnet_id = var.subnet_ids[count.index % local.vpc_count]
status = var.status
cycle_type = "on_demand"
bandwidth = var.bandwidth
password = var.passwords[count.index]
}
output "ecs_list" {
value = ctyun_ecs.ecs
}ecs\variables.tf
variable "ecs_count" {
type = number
}
variable "instance_name_prefix" {
type = string
}
variable "display_name_prefix" {
type = string
}
variable "flavor_name" {
type = string
}
variable "image_id" {
type = string
}
variable "system_disk_type" {
type = string
}
variable "system_disk_size" {
type = number
}
variable "vpc_ids" {
type = list(string)
}
variable "subnet_ids" {
type = list(string)
}
variable "status" {
type = string
default = "running"
}
variable "passwords" {
type = list(string)
}
variable "bandwidth" {
type = number
}vpc\main.tf
terraform {
required_providers {
ctyun = {
source = "ctyun-it/ctyun"
version = "2.1.0"
}
}
}
locals {
vpc_count = length(var.cidr)
}
# 创建vpc
resource "ctyun_vpc" "vpc" {
count = local.vpc_count
name = "${var.vpc_name_prefix}-${count.index + 1}"
cidr = var.cidr[count.index]
}
# 在vpc下创建子网
resource "ctyun_subnet" "subnet" {
count = local.vpc_count
vpc_id = ctyun_vpc.vpc[count.index].id
name = "${var.subnet_name_prefix}-${count.index + 1}"
cidr = var.cidr[count.index]
dns = [
"114.114.114.114",
"8.8.8.8",
]
}
# 查询安全组
data "ctyun_security_groups" "security_group" {
count = local.vpc_count
vpc_id = ctyun_vpc.vpc[count.index].id
}
locals {
security_group_ids = [for idx in range(local.vpc_count) : data.ctyun_security_groups.security_group[idx].security_groups[0].security_group_id]
}
resource "ctyun_security_group_rule" "security_group_rule" {
# 双重循环:每个安全组 × 每个规则
for_each = {
for index, pair in setproduct(local.security_group_ids, var.sg_rules) :
"rule_${index}" => {
security_group_id = pair[0]
rule = pair[1]
}
}
security_group_id = each.value.security_group_id
direction = each.value.rule.direction
protocol = each.value.rule.protocol
dest_cidr_ip = each.value.rule.dest_cidr_ip
range = each.value.rule.range
action = "accept"
priority = 1
ether_type = "ipv4"
}
output "vpc_id" {
value = ctyun_vpc.vpc[*].id
}
output "subnet_id" {
value = ctyun_subnet.subnet[*].id
}vpc\variables.tf
variable "cidr" {
type = list(string)
}
variable "vpc_name_prefix" {
type = string
}
variable "subnet_name_prefix" {
type = string
}
variable "sg_rules" {
type = list(object({
range = string # 端口/端口段
dest_cidr_ip = string # 目标网段
direction = string # 出方向还是入方向
protocol = string # 协议
}))
default = []
}