merge: 弹性节点基建:Terraform + 一键更换 [tsk_6u0FxmbC7Yeq]

# Conflicts:
#	.gitignore
#	infra/cloud-init/node.yaml.tmpl
This commit is contained in:
wangjia
2026-06-13 17:30:37 +08:00
39 changed files with 3883 additions and 0 deletions
+64
View File
@@ -43,3 +43,67 @@ runcmd:
# 整机 35 分钟内可服务:cloud-init 完成 → agent 首启 Enroll → Register 取全量配置 →
# 渲染 sing-box config 并 restart sing-box → REALITY/Hy2 入站上线。
## template: jinja-free Go text/template — rendered by
## server/internal/provision (CloudInitRenderer). Fields:
## {{.NodeUUID}} {{.BootstrapToken}} {{.Region}} {{.Role}} {{.Tier}} {{.ControlPlaneURL}}
##
## "Nodes are cattle, not pets" (doc/04 §2): this is the ENTIRE persistent
## footprint of a data-plane node — sing-box + agent binaries + a one-time
## bootstrap token. Zero user DB, zero logs, zero persistent state.
##
## SECURITY: the rendered output carries a one-time bootstrap token. It MUST NOT
## be logged. The token is consumed exactly once during mTLS enrollment (task #5)
## and is useless afterwards.
#cloud-config
write_files:
# Node identity + enrollment parameters consumed by the agent on first boot.
- path: /etc/pangolin/bootstrap.env
permissions: "0600"
owner: root:root
content: |
PANGOLIN_NODE_UUID={{.NodeUUID}}
PANGOLIN_BOOTSTRAP_TOKEN={{.BootstrapToken}}
PANGOLIN_CONTROL_PLANE_URL={{.ControlPlaneURL}}
PANGOLIN_REGION={{.Region}}
PANGOLIN_ROLE={{.Role}}
PANGOLIN_TIER={{.Tier}}
# systemd unit: agent enrolls (mTLS) then pulls runtime config from control plane.
- path: /etc/systemd/system/pangolin-agent.service
permissions: "0644"
owner: root:root
content: |
[Unit]
Description=Pangolin node agent (self-register + config pull)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
EnvironmentFile=/etc/pangolin/bootstrap.env
ExecStart=/usr/local/bin/pangolin-agent run
# No-log node: agent does not persist connection logs.
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
runcmd:
# 1. Harden: key-only SSH, no root password (doc/06 §3).
- sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
- sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
- systemctl restart sshd || true
# 2. Install the agent binary (pinned, checksum-verified by the install script,
# delivered out-of-band by task #6). Placeholder URL resolved at build time.
- install -d -m 0755 /etc/pangolin
- /usr/local/bin/pangolin-agent-install || true
# 3. Enroll + start. The agent reads bootstrap.env, performs mTLS enrollment,
# and the control plane flips the node provisioning → probing → up.
- systemctl daemon-reload
- systemctl enable --now pangolin-agent.service
# 4. Shred the one-time token from disk after enrollment (defence in depth).
- bash -c 'sleep 60; shred -u /etc/pangolin/bootstrap.env 2>/dev/null || rm -f /etc/pangolin/bootstrap.env'
# No swap file written to disk, no persistent data dirs — a destroyed node leaks nothing.