redc Template Management
This skill guides you through creating and maintaining templates for the redc multi-cloud deployment engine. redc templates are Terraform-based infrastructure-as-code definitions organized by cloud provider, with a metadata layer (case.json) that the redc engine and GUI consume.
Template Types
redc has four template types, each in its own directory:
| Type | template value |
Directory | When to use |
|---|---|---|---|
| Preset | preset or omit |
aliyun/, aws/, tencent/, etc. |
Full cloud scenarios (ECS+VPC+SG) shown in Scene Management |
| Base | base |
base-templates/ |
Minimal cloud primitives for Custom Deployment |
| Userdata | userdata |
userdata-templates/ |
Init scripts (bash/powershell) composable with any base |
| Compose | compose |
compose-templates/ |
Docker Compose definitions for Compose Management |
Pick preset for self-contained "one-click deploy" scenarios. Pick base when providing a minimal building block that users combine with userdata scripts. Pick userdata for software installation scripts. Pick compose for Docker service stacks.
Creating a New Template
Step 1: Determine the template type and location
Preset template → <provider>/<scene-name>/ (e.g., aliyun/nat-probe/, aws/proxy/)
Base template → base-templates/<provider>-<resource>/ (e.g., base-templates/aws-ec2/)
Userdata template → userdata-templates/<name>/ (e.g., userdata-templates/redis-bash/)
Compose template → compose-templates/<name>/ (e.g., compose-templates/elk-stack/)
Directory and file names: lowercase, hyphens for word separation, no spaces.
Step 2: Create the required files
Every template directory needs at minimum:
scene-name/
├── case.json ← Metadata (REQUIRED)
├── README.md ← Documentation in Chinese (REQUIRED)
├── README_EN.md ← Documentation in English (REQUIRED)
├── versions.tf ← Provider version locks (preset/base only)
├── main.tf ← Core resources (preset/base only)
├── variables.tf ← Input variables (preset/base only)
└── outputs.tf ← Output values (preset/base only)
For userdata templates, the structure is simpler:
script-name/
├── case.json
├── README.md
├── README_EN.md
└── userdata ← The script file (no extension)
For compose templates:
stack-name/
├── case.json
├── README.md
├── README_EN.md
└── redc-compose.yaml
Step 3: Write case.json
This is the most important file — the redc engine and CI both validate it strictly.
Common required fields (all template types, CI will fail without these):
| Field | Type | Description |
|---|---|---|
name |
string | 模板名称,非空 |
user |
string | 作者名,非空 |
version |
string | 语义化版本号,如 "1.0.0" |
description |
string | 中文描述,非空 |
description_en |
string | 英文描述,非空 |
tags |
list | 标签列表,非空 |
Type-specific required fields (CI also enforces these):
| Template Type | Extra Required Fields | Description |
|---|---|---|
preset |
arch |
架构,如 "x86_64" 或 "arm64" |
base |
arch, provider |
架构 + 云厂商标识(如 "alicloud", "aws") |
userdata |
nameZh, type, category |
中文名 + 脚本类型 (bash/powershell) + 分类 (basic/tool/service/security) |
compose |
(无额外字段) | — |
Preset template example:
{
"name": "ecs",
"user": "redc",
"version": "1.0.0",
"description": "阿里云 ECS 实例",
"description_en": "Alibaba Cloud ECS instance",
"tags": ["ecs", "basic"],
"arch": "x86_64",
"template": "preset"
}
Base template example:
{
"name": "alicloud-ecs",
"user": "redc",
"version": "1.0.5",
"description": "阿里云 ECS 基础模板",
"description_en": "Alibaba Cloud ECS base template",
"tags": ["ecs"],
"arch": "x86_64",
"provider": "alicloud",
"template": "base"
}
Userdata template example:
{
"name": "f8x-bash",
"nameZh": "f8x 渗透测试工具集",
"user": "r0fus0d",
"version": "1.0.1",
"description": "f8x 渗透测试工具集",
"description_en": "f8x penetration testing toolkit",
"tags": ["tool"],
"type": "bash",
"category": "tool",
"template": "userdata"
}
Optional fields (not enforced by CI, but useful):
| Field | Used by | Description |
|---|---|---|
redc_plugins |
preset | 逗号分隔的插件列表 |
provider |
preset | 云厂商标识(preset 可选,base 必填) |
vulType |
userdata | 漏洞类型(安全类 userdata) |
cveId |
userdata | CVE 编号 |
Version numbering: Use semantic versioning (major.minor.patch). Bump patch for fixes, minor for new features, major for breaking changes. Every template change must bump the version — redc uses this field to detect updates; unchanged versions will not trigger redc pull updates on user machines.
Step 4: Write Terraform files (preset/base templates)
versions.tf
Lock the provider version to avoid compatibility surprises:
terraform {
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = "1.241.0"
}
}
}
provider "alicloud" {
profile = "cloud-tool"
region = var.region
}
Current provider versions in use across the repo:
aliyun/alicloud:1.241.0hashicorp/aws:5.25.0tencentcloudstack/tencentcloud:1.81.8hashicorp/azurerm:4.61.0volcengine/volcengine:0.0.184
When adding a template for an existing provider, match the version already used unless there's a specific reason to differ.
variables.tf
Declare all configurable inputs. Common patterns:
variable "region" {
type = string
description = "Cloud region"
default = "cn-beijing"
}
variable "instance_name" {
type = string
description = "Instance name"
default = "my-scene"
}
variable "instance_password" {
type = string
description = "Login password (leave empty to auto-generate)"
sensitive = true
default = ""
}
Hardcoded AMIs/image IDs and regions are a common template smell — extract them to variables with sensible defaults so users can override them.
main.tf
The core resource definitions. Follow these patterns:
Password auto-generation (standard pattern used across all templates):
locals {
password_seed = replace(uuid(), "-", "")
generated_password = format("%s_+%s", substr(local.password_seed, 0, 12), substr(local.password_seed, 12, 10))
instance_password = var.instance_password != "" ? var.instance_password : local.generated_password
}
User data script: Inline with <<-EOF heredoc. Always include:
- Basic packages:
curl,wget,tmux,unzip - BBR network optimization
- Cloud agent removal (for Chinese clouds)
- trzsz for terminal file transfer
Security groups: Open all TCP/UDP for lab/pentest use. Add a comment noting this is intentional.
Naming: Use var.instance_name prefix for all resource names to avoid collisions.
outputs.tf
The redc engine and GUI read these outputs. Use these standardized names:
| Output | Description | Use when |
|---|---|---|
public_ip |
Instance public IP | Always (if instance has public IP) |
ssh_user |
SSH username | Always |
ssh_command |
Full SSH command | Always |
ssh_password |
Instance password (nonsensitive) | Password-based auth |
ssh_private_key_path |
Path to SSH key file | Key-based auth (AWS, GCP) |
Legacy names (ecs_ip, ecs_password) still work but prefer the standardized names for new templates.
output "public_ip" {
description = "Public IP address"
value = alicloud_instance.ecs.public_ip
}
output "ssh_user" {
description = "SSH login username"
value = "root"
}
output "ssh_command" {
description = "SSH connection command"
value = "ssh root@${alicloud_instance.ecs.public_ip}"
}
output "ssh_password" {
description = "SSH password"
value = nonsensitive(local.instance_password)
}
Step 5: Write README.md and README_EN.md
Every template must have both a Chinese README (README.md) and an English README (README_EN.md). The redc website uses README_EN.md when users browse in English mode, so both files are required by CI.
Both READMEs should include:
- Title and description — What this template deploys
- Architecture diagram (for complex setups) — ASCII art showing resource relationships
- Usage section — Both
redccommands and standaloneterraformcommands - Variables table — All configurable parameters with defaults
- Outputs table — What information is returned after deployment
- Notes/caveats — Cost warnings, region restrictions, security implications
Template:
# Scene Name
Brief description of what gets deployed.
## Usage
### Via redc
\```bash
redc pull <provider>/<scene>
redc run <provider>/<scene>
redc status
redc stop
\```
### Standalone
\```bash
terraform init
terraform apply -auto-approve
terraform destroy -auto-approve
\```
## Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `region` | `cn-beijing` | Cloud region |
## Outputs
| Output | Description |
|--------|-------------|
| `public_ip` | Instance public IP |
Step 6: Validate
Before committing, run these checks:
# Format check
terraform fmt -check .
# Syntax validation
terraform init -backend=false
terraform validate
# Auto-fix formatting
terraform fmt .
Also verify case.json has all required fields — both the 6 common fields (name, user, version, description, description_en, tags) and the type-specific fields:
- preset:
arch - base:
arch,provider - userdata:
nameZh,type,category
Clean up before committing: remove .terraform/, .terraform.lock.hcl, and any *.tfstate* files.
Maintaining Existing Templates
Updating a template
⚠️ 重要: 任何场景模板的更新(包括 .tf 文件、README、case.json 字段修改等),都必须同时更新
case.json中的version字段。redc 工具通过版本号判断模板是否有更新,如果版本号不变,用户端的redc pull不会拉取到最新模板。
- Bump the version in
case.json— patch for fixes (1.0.1→1.0.2), minor for features (1.0.x→1.1.0) - Make the changes to
.tffiles - Update
README.mdif the interface changed - Run
terraform fmt .andterraform validate
Common maintenance tasks
Updating provider version: Change version in versions.tf, run terraform init -upgrade to verify compatibility, update the lock file.
Adding a variable: Add to variables.tf with a default value (backward-compatible), reference in main.tf, document in README.md.
Fixing output names: When standardizing from ecs_ip → public_ip, keep both outputs during transition (old one with a deprecation comment).
CI Validation Rules
The GitHub Actions CI (validate.yml) checks:
- Every template directory must have
README.md,README_EN.mdandcase.json - Common required fields:
name,user,version,description,description_en,tags - Type-specific required fields:
preset:archbase:arch,provideruserdata:nameZh,type,categorycompose: (no extra fields)
- Field constraints:
name/user/description/description_enmust be non-empty strings,versionmust be a string,tagsmust be a non-empty list - Terraform syntax:
terraform fmtmust pass (syntax only, not formatting style) - Directories in
plugins/,.git/,.github/are excluded from checks
Adding a new cloud provider
- Create the provider directory at repo root (e.g.,
oracle/) - Add at least one template (e.g.,
oracle/compute/) - Follow existing patterns — look at
aliyun/ecs/oraws/ec2/as reference - Update
README.mdat repo root to list the new provider - Optionally add a base template in
base-templates/<provider>-<resource>/
Reference: Cloud Provider Patterns
Alibaba Cloud (aliyun/)
- Provider:
aliyun/alicloud - Auth:
profile = "cloud-tool"(redc manages credentials) - Network: VPC + VSwitch + Security Group
- Instance:
alicloud_instancewithinternet_max_bandwidth_outfor public IP - Agent removal: wget aegis uninstall scripts
- Spot instances:
spot_strategy = "SpotWithPriceLimit"for cost savings
AWS (aws/)
- Provider:
hashicorp/aws - Auth: environment variables (redc injects)
- SSH: auto-generate via
tls_private_key+aws_key_pair+local_file - Instance:
aws_instancewith auto-assigned public IP via subnet - Random suffix:
random_id.suffix.hexfor unique resource names - Spot:
aws_spot_instance_requestfor cost savings
Tencent Cloud (tencent/)
- Provider:
tencentcloudstack/tencentcloud - Auth: environment variables
- Network: VPC + Subnet + Security Group
- Instance:
tencentcloud_instance - Output file:
output.tf(note: singular, notoutputs.tf)
Azure (azure/)
- Provider:
hashicorp/azurerm - Auth:
features {}block required - Resource group required for all resources
- Network: VNet + Subnet + NSG + Public IP + NIC
Reference: Userdata Script Patterns
Userdata scripts go in userdata-templates/<name>/userdata (no file extension).
Bash template:
#!/bin/bash
# Install <tool>
<installation commands>
echo "<tool> installed successfully!"
PowerShell template:
# Install <tool>
<installation commands>
Write-Host "<tool> installed successfully!"
Keep scripts minimal and idempotent. The redc engine injects these into the user_data field of cloud instances.