8de32eb611
# Conflicts: # .gitignore # infra/cloud-init/node.yaml.tmpl
110 lines
4.9 KiB
Cheetah
110 lines
4.9 KiB
Cheetah
#cloud-config
|
||
# Pangolin 加速节点一段式安装模板(与 #14 弹性开机共用)。
|
||
#
|
||
# 渲染:控制面 provisioner 用 sed 替换所有 __PLACEHOLDER__(沿用 deploy/ 约定)。
|
||
# __CONTROL_PLANE__ 控制面 gRPC 地址 host:port
|
||
# __SERVER_NAME__ 校验控制面证书的 TLS SNI(留空则取 host 部分)
|
||
# __BOOTSTRAP_TOKEN__ 一次性引导 token(由 mtls.BootstrapTokenManager.IssueToken 预签发,15min TTL)
|
||
# __DERIVE_KEY__ Hy2 口令派生密钥(与控制面同源,见 agentd.DeriveHy2Password)
|
||
# __AGENT_VERSION__ pangolin-agent 版本(与产物命名/SHA 锁定一致)
|
||
# __ARTIFACT_BASE__ 二进制与安装脚本下载根 URL
|
||
# __INSTALL_SHA256__ install-node.sh 的 SHA-256(整链可复现校验)
|
||
#
|
||
# 安全:agent.env 内含 bootstrap token,权限 0600;token 一次性消费后即失效。
|
||
# 节点无状态:除 /etc/pangolin-agent/{node.key,node.crt,ca.crt,state.json} 与
|
||
# /etc/sing-box 外不落任何持久数据,且 state.json 仅含 dp_uuid + expires_at。
|
||
|
||
write_files:
|
||
- path: /etc/pangolin-agent/agent.env
|
||
permissions: '0600'
|
||
owner: root:root
|
||
content: |
|
||
PANGOLIN_AGENT_CONTROL_PLANE=__CONTROL_PLANE__
|
||
PANGOLIN_AGENT_SERVER_NAME=__SERVER_NAME__
|
||
PANGOLIN_AGENT_BOOTSTRAP_TOKEN=__BOOTSTRAP_TOKEN__
|
||
PANGOLIN_AGENT_DERIVE_KEY=__DERIVE_KEY__
|
||
PANGOLIN_AGENT_STATE_DIR=/etc/pangolin-agent
|
||
PANGOLIN_AGENT_SINGBOX_CONFIG=/etc/sing-box/config.json
|
||
PANGOLIN_AGENT_SINGBOX_UNIT=sing-box
|
||
PANGOLIN_AGENT_VERSION=__AGENT_VERSION__
|
||
|
||
runcmd:
|
||
- |
|
||
set -euo pipefail
|
||
mkdir -p /opt/pangolin
|
||
tmp="$(mktemp)"
|
||
# 下载安装脚本并按锁定 SHA-256 校验后再执行(拒绝被篡改的脚本)。
|
||
curl -fsSL --retry 3 "__ARTIFACT_BASE__/install-node.sh" -o "$tmp"
|
||
echo "__INSTALL_SHA256__ $tmp" | sha256sum -c -
|
||
install -m 0755 "$tmp" /opt/pangolin/install-node.sh
|
||
rm -f "$tmp"
|
||
ARTIFACT_BASE="__ARTIFACT_BASE__" AGENT_VERSION="__AGENT_VERSION__" \
|
||
bash /opt/pangolin/install-node.sh
|
||
|
||
# 整机 3–5 分钟内可服务: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.
|