Allow explicit trusted control IPv4 sources in initialization firewall

This commit is contained in:
kaka
2026-11-04 23:26:07 +08:00
parent e76cb4c1b6
commit 9eb8110c90
2 changed files with 10 additions and 1 deletions

View File

@@ -101,3 +101,6 @@ Caddy 同时提供 /install.sh 稳定入口与 /releases/<40位小写Git提交>/
Debian 初始化时,固定 release 的 `host-init.sh --apply` 支持 `--firewall-policy /run/platform-secrets/firewall.json --firewall-script /已校验的固定release/firewall.sh`,直接调用同一个防火墙事务。脚本不再另写一套内网规则。策略仍需明确主机名、现有 SSH 端口/公网恢复来源和公网服务端口;内网全部放行由通用 firewall.sh 自动生成。新建 SSH 验证后,用 apply 返回的准确摘要执行 firewall.sh --confirm。未传防火墙输入的旧调用仅准备包和主机名,不能宣称已完成防火墙初始化。 Debian 初始化时,固定 release 的 `host-init.sh --apply` 支持 `--firewall-policy /run/platform-secrets/firewall.json --firewall-script /已校验的固定release/firewall.sh`,直接调用同一个防火墙事务。脚本不再另写一套内网规则。策略仍需明确主机名、现有 SSH 端口/公网恢复来源和公网服务端口;内网全部放行由通用 firewall.sh 自动生成。新建 SSH 验证后,用 apply 返回的准确摘要执行 firewall.sh --confirm。未传防火墙输入的旧调用仅准备包和主机名,不能宣称已完成防火墙初始化。
主机策略可增加 `trusted_sources: ["控制机实际公网IPv4"]`,对这些精确地址允许所有端口/协议。该字段由环境登记输入,禁止 CIDR,脚本不硬编码控制机 IP;host-init.sh 调用 firewall.sh 时自动使用同一字段。

View File

@@ -10,9 +10,10 @@ validate_policy() {
(split(".") | all(.[]; tonumber <= 255)); (split(".") | all(.[]; tonumber <= 255));
def tailip: ip and (split(".") | map(tonumber) | .[0] == 100 and .[1] >= 64 and .[1] <= 127); def tailip: ip and (split(".") | map(tonumber) | .[0] == 100 and .[1] >= 64 and .[1] <= 127);
def ports: type == "array" and all(.[]; type == "number" and . == floor and . >= 1 and . <= 65535); def ports: type == "array" and all(.[]; type == "number" and . == floor and . >= 1 and . <= 65535);
(keys == ["hostname","management","public_tcp","public_udp","tailnet","version"]) and .version == 1 and ((keys - ["trusted_sources"]) == ["hostname","management","public_tcp","public_udp","tailnet","version"]) and .version == 1 and
(.hostname | type == "string" and length <= 63 and test("^(dev|test|stage|prod)-[a-z][a-z0-9]{0,15}-[a-z][a-z0-9]{0,15}(-[a-z][a-z0-9]{0,15})?-(0[1-9]|[1-9][0-9])$")) and (.hostname | type == "string" and length <= 63 and test("^(dev|test|stage|prod)-[a-z][a-z0-9]{0,15}-[a-z][a-z0-9]{0,15}(-[a-z][a-z0-9]{0,15})?-(0[1-9]|[1-9][0-9])$")) and
(.public_tcp | ports) and (.public_udp | ports) and (.public_tcp | ports) and (.public_udp | ports) and
((.trusted_sources // []) | type == "array" and all(.[]; ip and (split(".")[0] | tonumber | . > 0 and . < 224))) and
(.management | keys == ["port","sources"]) and ([.management.port] | ports) and (.management | keys == ["port","sources"]) and ([.management.port] | ports) and
(.management.sources | type == "array" and all(.[]; ip and (tailip | not))) and (.management.sources | type == "array" and all(.[]; ip and (tailip | not))) and
(.tailnet | type == "array" and all(.[]; (.tailnet | type == "array" and all(.[];
@@ -43,6 +44,11 @@ table inet platform_host {
udp sport 67 udp dport 68 accept udp sport 67 udp dport 68 accept
ip6 saddr fe80::/10 udp sport 547 udp dport 546 accept ip6 saddr fe80::/10 udp sport 547 udp dport 546 accept
NFT NFT
# Public control hosts are explicit per-environment inputs, never compiled IPs.
sources=$(jq -r '(.trusted_sources // []) | unique | join(", ")' "$policy")
if [[ -n "$sources" ]]; then
printf ' ip saddr { %s } accept\n' "$sources"
fi
sources=$(jq -r '.management.sources | join(", ")' "$policy") sources=$(jq -r '.management.sources | join(", ")' "$policy")
if [[ -n "$sources" ]]; then if [[ -n "$sources" ]]; then
printf ' iifname != "tailscale0" ip saddr { %s } tcp dport %s accept\n' "$sources" "$(jq -r .management.port "$policy")" printf ' iifname != "tailscale0" ip saddr { %s } tcp dport %s accept\n' "$sources" "$(jq -r .management.port "$policy")"