fix(ops): contain 188 ollama gateway exposure
All checks were successful
Code Review / ai-code-review (push) Successful in 10s

This commit is contained in:
Your Name
2026-05-06 15:18:28 +08:00
parent 2adbf1e6cd
commit f88a3a846b
4 changed files with 151 additions and 2 deletions

View File

@@ -1,3 +1,19 @@
## 2026-05-06 | 188 Ollama gateway 暴露確認並臨時封口
**背景**:統帥確認沒有 `192.168.0.88` 這台主機;重新盤點後發現 `.88` 是 188 的 default gatewayOllama journal 裡的 `.88` 來源不是正常依賴,而是 gateway / NAT / port-forward / hairpin 入口。
**本次處置**
- 確認 188 `ollama.service` systemd override 設為 `OLLAMA_HOST=0.0.0.0`,因此原本對 LAN / gateway 開放 `*:11434`
- `ollama@188` 無 sudo無法永久改 systemd 或 iptables先執行臨時封口將 Ollama 換成只綁 `127.0.0.1:11434` 的同使用者進程。
- 新增 `scripts/ops/ollama188-localhost-containment.sh`,並強化 `ollama188-retirement-gate.sh` 檢查 `*:11434` 暴露。
- `OLLAMA-188-RETIREMENT-GATE.md` 補上 `.88` 正確判讀、臨時封口與需要 root 的永久修法。
**驗證**
- 188 listen`127.0.0.1:11434`
- 從本機、110、K8s Pod 連 `192.168.0.188:11434` 均被拒絕。
- 188 本機 `curl http://127.0.0.1:11434/api/tags` OK。
- 注意systemd 原服務會因仍設定 `0.0.0.0` 而 restart 失敗;永久收斂需要 root 修改 override。
## 2026-05-06 | Gitea CD 188 ops sync 加上 timeout 防卡死
**背景**`d441f706` 的主 CD 已完成 tests 與 deploy marker但 runner 卡在 `Sync Ops Scripts to 188` 的裸 `scp`188 剛經歷重開後,沒有 timeout 的 sftp 子程序會阻塞 `post-deploy-checks`

View File

@@ -18,6 +18,7 @@
- Prometheus live config 不得再探測 `192.168.0.188:11434`
- 188 的 Ollama journal 在觀察窗口內不得有 `/api/generate``/api/chat``/v1/chat/completions` 推理 POST。
- `192.168.0.121` 不得再固定對 188 `/api/tags` 做 dev health check。
- 188 不得以 `0.0.0.0:11434` / `*:11434` 監聽;允許的臨時狀態只有 `127.0.0.1:11434`
## 檢查方式
@@ -40,11 +41,61 @@ POST_SINCE="24 hours ago" HEALTH_SINCE="10 minutes ago" scripts/ops/ollama188-re
| Disable | Stop 後 48 小時無回歸 | 可 `systemctl disable ollama` |
| Uninstall | Disable 後 7 天無回歸,且確認無其他專案依賴 | 才評估移除套件與模型資料 |
## 192.168.0.88 的正確判讀
`192.168.0.88` 不是 AWOOOI 的下游專案主機。188 上的路由顯示:
```text
default via 192.168.0.88 dev ens160
```
因此 Ollama journal 中的 `192.168.0.88` 應視為 gateway / NAT / port-forward / hairpin 來源。若看到它打 `/api/generate``/api/chat``/v1/chat/completions`,代表 188 的 `:11434` 曾經暴露給 gateway 入口,不是正常 tenant 依賴。
## 緊急封口
目前 `ollama@192.168.0.188` 沒有 sudo無法直接修改 systemd override 或 iptables。若發現 188 Ollama 又變成 `*:11434`,可先執行臨時封口:
```bash
scripts/ops/ollama188-localhost-containment.sh
```
臨時封口會:
- kill 目前 `ollama` 使用者的 `/usr/local/bin/ollama serve`
- 以同一個 `ollama` 使用者重啟一個只綁 `127.0.0.1:11434` 的進程。
-`192.168.0.188:11434` 從 LAN / gateway 視角拒絕連線。
限制:
- systemd 原服務仍會因 root-owned override 裡的 `OLLAMA_HOST=0.0.0.0` 而反覆 restart 失敗。
- 這是安全封口,不是乾淨的永久狀態。
## 永久修法(需要 188 root 權限)
在 188 上以 root 執行:
```bash
sudo install -d /etc/systemd/system/ollama.service.d
sudo cp /etc/systemd/system/ollama.service.d/override.conf \
/etc/systemd/system/ollama.service.d/override.conf.bak.$(date +%Y%m%d_%H%M%S)
sudo sed -i 's/Environment="OLLAMA_HOST=0.0.0.0"/Environment="OLLAMA_HOST=127.0.0.1:11434"/' \
/etc/systemd/system/ollama.service.d/override.conf
sudo systemctl daemon-reload
sudo pkill -u ollama -f "/usr/local/bin/ollama serve" || true
sudo systemctl restart ollama
ss -lntp | grep 11434
curl -sS --max-time 3 http://127.0.0.1:11434/api/tags >/dev/null && echo LOCAL_OK
curl -sS --max-time 3 http://192.168.0.188:11434/api/tags || echo LAN_CLOSED
```
## 今日發現
- `awoooi-prod` provider registry 已沒有 `ollama_188`
- `awoooi-dev` 原本仍使用 `OLLAMA_URL=http://192.168.0.188:11434`,已 live patch 到 GCP-A/GCP-B/111 proxy。
- Prometheus 舊 blackbox target 已移除並 reload避免退役後誤報。
- 188 journal 中近期少量推理 POST 來源為 `192.168.0.88`,不是 K8s Pod此來源未釐清前不建議解除安裝
- 188 journal 中近期少量推理 POST 來源為 `192.168.0.88`;後續確認 `.88` 是 188 的 default gateway不是下游主機
- 2026-05-06 14:53 短窗口 Gate 綠燈repo、K8s env、Prometheus target、dev health check 均已避開 188。
- 24 小時 Gate 尚未綠燈:仍看得到 `192.168.0.88` 在 24 小時內送過推理 POST。
- 2026-05-06 15:14 已執行臨時封口188 只聽 `127.0.0.1:11434`從本機、110、K8s Pod 直連 `192.168.0.188:11434` 均拒絕。

View File

@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# 188 Ollama 緊急封口。
# 不需要 root把目前對外開放的 ollama serve 換成只綁 127.0.0.1:11434 的同使用者進程。
# 這是臨時手段;永久修法仍必須用 root 修改 systemd override。
set -euo pipefail
LEGACY_SSH="${LEGACY_SSH:-ollama@192.168.0.188}"
ssh -o BatchMode=yes -o ConnectTimeout=5 "$LEGACY_SSH" 'cat > ~/awoooi-ops/ollama-localhost-containment.sh <<'"'"'REMOTE_SH'"'"'
#!/usr/bin/env bash
set -euo pipefail
LOG="$HOME/awoooi-ops/ollama-localhost-containment.log"
SERVE_LOG="$HOME/awoooi-ops/ollama-localhost-serve.log"
{
echo "=== containment start $(date) ==="
echo "before:"
ss -lntp | grep 11434 || true
for i in $(seq 1 20); do
pkill -u ollama -f "/usr/local/bin/ollama serve" 2>/dev/null || true
sleep 0.2
nohup env \
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" \
OLLAMA_HOST="127.0.0.1:11434" \
OLLAMA_KEEP_ALIVE="30m" \
OLLAMA_MAX_LOADED_MODELS="2" \
OLLAMA_NUM_THREAD="14" \
OLLAMA_NUM_PARALLEL="4" \
OLLAMA_FLASH_ATTENTION="1" \
OLLAMA_RUNNERS_DIR="/tmp/ollama_runners" \
/usr/local/bin/ollama serve >> "$SERVE_LOG" 2>&1 &
sleep 1
if ss -lntp | grep -q "127.0.0.1:11434"; then
echo "contained on attempt $i"
break
fi
done
echo "after:"
ss -lntp | grep 11434 || true
echo "local test:"
curl -sS --max-time 3 http://127.0.0.1:11434/api/tags >/dev/null && echo LOCAL_OK || echo LOCAL_FAIL
echo "=== containment end $(date) ==="
} | tee -a "$LOG"
REMOTE_SH
chmod +x ~/awoooi-ops/ollama-localhost-containment.sh
~/awoooi-ops/ollama-localhost-containment.sh'
echo "=== 驗證 LAN 入口 ==="
if curl -sS --max-time 3 http://192.168.0.188:11434/api/tags >/dev/null 2>&1; then
echo "FAIL: 192.168.0.188:11434 仍可從 LAN 連線"
exit 1
fi
echo "PASS: 192.168.0.188:11434 已拒絕 LAN 連線"

View File

@@ -34,7 +34,8 @@ check_repo_runtime_refs() {
output="$(
cd "$ROOT_DIR" && rg -n "$pattern" \
apps/api/src apps/api/scripts scripts k8s ops \
-g '!scripts/ops/ollama188-retirement-gate.sh' 2>/dev/null || true
-g '!scripts/ops/ollama188-retirement-gate.sh' \
-g '!scripts/ops/ollama188-localhost-containment.sh' 2>/dev/null || true
)"
if [[ -n "$output" ]]; then
@@ -80,6 +81,28 @@ check_prometheus_config() {
fi
}
check_legacy_port_exposure() {
info "檢查 188 Ollama 是否仍對 LAN/gateway 開放"
local listen_output
if ! listen_output="$(ssh -o BatchMode=yes -o ConnectTimeout=5 "$LEGACY_SSH" \
"ss -lntp | grep ':11434' || true" 2>/dev/null)"; then
warn "無法讀取 188 listen 狀態"
return
fi
printf '%s\n' "$listen_output"
if printf '%s\n' "$listen_output" | grep -Eq '(\*:11434|0\.0\.0\.0:11434|\[::\]:11434)'; then
fail "188 Ollama 仍綁定 all interfaces可能被 gateway/NAT 打入"
return
fi
if curl -sS --max-time 3 http://192.168.0.188:11434/api/tags >/dev/null 2>&1; then
fail "本機仍可從 LAN 直連 192.168.0.188:11434"
else
pass "LAN 入口已關閉;若需本機使用,應只留 127.0.0.1:11434"
fi
}
check_legacy_inference_posts() {
info "檢查 188 Ollama 最近是否仍有推理 POSTPOST_SINCE=${POST_SINCE}"
local output
@@ -117,6 +140,7 @@ check_dev_health_noise() {
check_repo_runtime_refs
check_k8s_env
check_prometheus_config
check_legacy_port_exposure
check_legacy_inference_posts
check_dev_health_noise