#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.
