Files
dsh_shenxian/scripts/install-egress-guard.sh
admin 452924d89c feat(config): 涉密内容外置到配置目录(档案 140)
把散落在代码里的真实部署值统一收进 config/,代码改为引用配置,
使仓库副本/开源导出不再带出生产域名、IP、内网路径与凭据。

新增 config/:platform.env.example(模板)· load.sh(shell 加载器)·
index.cjs(node 加载器)· README.md(键一览与优先级)。
真实值放 config/platform.env —— 已 .gitignore 排除,不入库、不进导出。

TS 侧新增 src/platform-paths.ts 作部署路径的唯一解析处(零副作用):
platformDir/stateDir/backupDir/artifactDir/installDir/scriptPath。
config.ts 接入这些字段;内置中继种子由生产 URL 改为空(改由
DSHS_OVERLAY_BOOTSTRAP_SEEDS 提供)。修掉 5 处硬编码绝对路径,
src/** 注释中性化 116 行/53 文件。

scripts/** 36 个内部运维脚本:真令牌/PG 口令/隧道目标/主机号/路径
一律改从配置取;web/wake.html 的注册域白名单改为运行时从
location.hostname 推导;test/** 夹具 119 行/13 文件改 RFC 2606/5737
保留值,并把「内置种子必须为空」固化为回归断言。

取证:tsc 0 错;npm test 373/375(唯一失败 lease 属既有);
全仓扫描(大小写不敏感)代码面涉密标识 = 0;已部署 47 并零回归
(/opt/dsh/* 未搬家,/var/lib/dshs/platform 未被误建)。
2026-09-19 15:12:19 +08:00

120 lines
5.6 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# 一键复现 dsh 实例出网护栏(/etc/nftables-dsh-egress.nft + dsh-egress.service)
#
# 档案 14 · H1 阻断云元数据端点(100.100.100.200)
# 档案 14 · H4 观测实例新建外联(只记录不拦截)
# 档案 39 · H5 封锁实例**主动**访问宿主自身(loopback / eth0 / docker0 / 公网 EIP)
#
# 用法(需 root):bash scripts/install-egress-guard.sh
# 回滚:systemctl disable --now dsh-egress
#
# ⚠️ 改 H5 前必读档案 39「事故/踩坑记录」:**不能只按目的地址匹配** ——
# 实例是「先收后回」的服务端,回包目的地址同样是 127.0.0.1,
# 按 daddr 一刀切会把回包一起拒掉 → nginx 无法回源、实例整体不可用
# (判定特征:root 连实例端口 **timeout 而非 refused**)。
# 必须只匹配主动发起:TCP 用纯 SYN,UDP 用 ct state new。
set -euo pipefail
if [ "$(id -u)" != "0" ]; then
echo "需要 root" >&2
exit 1
fi
. "$(cd "$(dirname "$0")/.." && pwd)/config/load.sh"
# ⛔ 本机地址不写死在 nft 规则里:规则体里用占位符,写完文件再注入实际值。
HOST_ADDRS=""
for a in "$DSH_HOST_LAN_IP" "$DSH_HOST_PUBLIC_IP"; do
[ -n "$a" ] && HOST_ADDRS="${HOST_ADDRS:+$HOST_ADDRS, }$a"
done
echo "==> 写入 /etc/nftables-dsh-egress.nft"
cat > /etc/nftables-dsh-egress.nft <<'NFTEOF'
#!/usr/sbin/nft -f
# dsh 实例出网护栏
# 档案 14 · H1(云元数据端点)+ H4(外联观测)
# 档案 39 · H5(实例不得「主动」访问宿主自身 —— 切断宿主服务面与跨租户互通)
# 只作用于 dsh 实例 uid 段 100000-199999;root / 云监控 / Docker 不受影响。
#
# 坑 1:阿里云 DNS 是 100.100.2.136 / 100.100.2.138 —— 绝不能封 100.100.0.0/16 整段,
# 本文件只精确封元数据端点 100.100.100.200(/32)。
# 坑 2:Docker 用 iptables-nft,本表独立,不与 docker 链混用。
# 坑 3:观测要排除 53 端口 —— nft 日志不记录查询域名,DNS 行是纯噪音且量最大。
# 坑 4(档案 39,实测踩到):H5 **绝不能只按目的地址匹配**。实例是「先收后回」的服务端:
# nginx(root) → 实例端口的 SYN 合法,但实例回的 SYN-ACK 与后续数据包
# **目的地址同样是 127.0.0.1**(客户端就是本机)。若按 daddr 一刀切 reject,
# 回包会被一起拒掉 → root 连实例端口 **超时**、nginx 无法回源、实例整体不可用。
# → 必须只匹配**实例主动发起**的连接:TCP 用纯 SYN(`tcp flags & (fin|syn|rst|ack) == syn`,
# SYN-ACK 带 ack 位故不匹配),UDP 用 `ct state new`。
table ip dsh_egress {
chain output {
type filter hook output priority filter; policy accept;
# H1 · 阻断云元数据端点(先记录再拒绝)
meta skuid 100000-199999 ip daddr 100.100.100.200 log prefix "dsh-egress-BLOCK " level warn
meta skuid 100000-199999 ip daddr 100.100.100.200 counter reject
# H5 · 实例不得主动访问宿主自身(档案 39)
# 封 4 类目的地址(仅实例主动发起的连接):
# 127.0.0.0/8 → 宿主全部 loopback 服务(sshd 22/32022、nginx 80/443/888、
# 门户 3080、BT-Panel 58888/8765)+ 其他实例的 127.0.0.1 监听
# <host-lan-ip> → 宿主内网卡(eth0,同样到达 nginx/面板)
# 172.17.0.1 → docker0 网桥网关
# <server-public-ip> → 公网 EIP(回环到本机 nginx/sshd)
# 不影响:公网访问、阿里云内网 DNS(100.100.2.136/138)、pip/npm 下载、
# 实例自身监听端口、nginx 回源(root 发包 + 实例回包带 ack)
meta skuid 100000-199999 ip daddr { 127.0.0.0/8, 172.17.0.1, __HOST_ADDRS__ } \
meta l4proto tcp tcp flags & (fin|syn|rst|ack) == syn \
counter log prefix "dsh-egress-HOST " level warn limit rate 20/minute
meta skuid 100000-199999 ip daddr { 127.0.0.0/8, 172.17.0.1, __HOST_ADDRS__ } \
meta l4proto tcp tcp flags & (fin|syn|rst|ack) == syn \
counter reject with tcp reset
meta skuid 100000-199999 ip daddr { 127.0.0.0/8, 172.17.0.1, __HOST_ADDRS__ } \
meta l4proto udp ct state new counter reject
# H4 · 观测实例新建外联(先记录不拦截;排除 loopback 与 DNS 降噪)
meta skuid 100000-199999 ip daddr != 127.0.0.0/8 tcp dport != 53 ct state new counter log prefix "dsh-egress " level info
meta skuid 100000-199999 ip daddr != 127.0.0.0/8 udp dport != 53 ct state new counter log prefix "dsh-egress " level info
}
}
NFTEOF
# 注入本机地址(来自 config/platform.env);未配 ⇒ 摘掉该占位符,规则只剩回环与 docker 网桥。
if [ -n "$HOST_ADDRS" ]; then
sed -i "s|__HOST_ADDRS__|$HOST_ADDRS|g" /etc/nftables-dsh-egress.nft
else
sed -i "s|, __HOST_ADDRS__||g" /etc/nftables-dsh-egress.nft
fi
echo "==> 写入 /etc/systemd/system/dsh-egress.service"
cat > /etc/systemd/system/dsh-egress.service <<'SVCEOF'
[Unit]
Description=DSH instance egress guard (nftables)
Documentation=file:/etc/nftables-dsh-egress.nft
After=network-pre.target
Before=network.service
Wants=network-pre.target
[Service]
Type=oneshot
RemainAfterExit=yes
# 幂等:nft -f 遇到已存在的表会报 File exists,故先删(忽略不存在时的报错)
ExecStartPre=-/usr/sbin/nft delete table ip dsh_egress
ExecStart=/usr/sbin/nft -f /etc/nftables-dsh-egress.nft
ExecStop=-/usr/sbin/nft delete table ip dsh_egress
[Install]
WantedBy=multi-user.target
SVCEOF
echo "==> 语法预检"
nft -c -f /etc/nftables-dsh-egress.nft
echo "==> 启用并重载"
systemctl daemon-reload
systemctl enable dsh-egress
systemctl restart dsh-egress
echo "==> 当前规则"
nft list table ip dsh_egress
echo "OK"