fix(ops): contain 188 ollama gateway exposure
All checks were successful
Code Review / ai-code-review (push) Successful in 10s
All checks were successful
Code Review / ai-code-review (push) Successful in 10s
This commit is contained in:
@@ -1,3 +1,19 @@
|
||||
## 2026-05-06 | 188 Ollama gateway 暴露確認並臨時封口
|
||||
|
||||
**背景**:統帥確認沒有 `192.168.0.88` 這台主機;重新盤點後發現 `.88` 是 188 的 default gateway,Ollama 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`。
|
||||
|
||||
@@ -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` 均拒絕。
|
||||
|
||||
58
scripts/ops/ollama188-localhost-containment.sh
Executable file
58
scripts/ops/ollama188-localhost-containment.sh
Executable 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 連線"
|
||||
@@ -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 最近是否仍有推理 POST(POST_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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user