feat(security): 新增 SSH network access 只讀清冊
This commit is contained in:
@@ -28,6 +28,46 @@
|
||||
- IwoooS 整體仍維持 `64%`;active runtime gate 仍 `0`。
|
||||
|
||||
**邊界**:本段只做只讀批准包、snapshot、schema、API、測試、前端可視化與文件;未寫 Gateway queue、未呼叫 Telegram Bot API、未改 receiver route、未寫 delivery receipt、未啟動 retry worker、未發 Telegram、未 SSH、未 active scan、未收 secret value、未開 runtime gate、未建立任何 P2-403E 內容區執行按鈕。
|
||||
## 2026-06-11|IwoooS P1-2 SSH / network access repo-only 清冊
|
||||
|
||||
**背景**:統帥要求所有重要配置都要被資安控管,尤其 Nginx 以外的 SSH、sudoers、known_hosts、firewall、WireGuard、NetworkPolicy 與 NodePort 不能只靠分散文件記憶。本段延續「先建立框架、只讀證據、低摩擦流程,再階段性收攏」原則,只做 repo-only 清冊,不連主機、不掃描、不改 live network。
|
||||
|
||||
**完成**:
|
||||
|
||||
- 新增 `ssh_network_access_inventory_v1` 產生器、schema、snapshot 與人讀文件,納入 `16` 個 repo-only surface。
|
||||
- 清冊覆蓋 SSH target、known_hosts workflow、CI deploy SSH、monitoring SSH、backup SSH capture、sudoers wrapper、NetworkPolicy、NodePort、WireGuard runbook 與 alert SSH action catalog。
|
||||
- SSH source surface `11`、NetworkPolicy surface `2`、NodePort surface `2`、sudoers surface `1`、WireGuard surface `1`、write-capable surface `6`。
|
||||
- 所有 surface 均固定 owner response required 與 live evidence required;owner response received / accepted、live evidence、maintenance window、rollback owner、runtime gate 與 action button 全部仍為 `0`。
|
||||
- 高價值配置覆蓋矩陣的 `ssh_firewall_network_access` 從 `48%` 推進到 `54%`;高價值配置平均只讀成熟度從 `64%` 調整為 `65%`。這只代表 repo-only 清冊完成,不代表主機、firewall 或 WireGuard 已驗證或可執行。
|
||||
- IwoooS posture projection snapshot / schema、`security-mirror-progress-guard.py`、高價值配置文件、配置控管總清冊與前端高價值配置卡已同步新口徑。
|
||||
- `/zh-TW/iwooos` 的 P1-2 卡由 `48%` 更新為 `54%`,並新增 `ssh_network_access_inventory_surface_count=16`、`ssh_network_access_inventory_write_capable_surface_count=6`、`ssh_read_authorized=false`、`sudo_action_authorized=false`、`firewall_change_authorized=false`、`network_policy_apply_authorized=false`、`nodeport_change_authorized=false`、`wireguard_change_authorized=false`、`known_hosts_patch_authorized=false`、`host_keyscan_authorized=false` 等前台邊界標記;仍無任何操作按鈕。
|
||||
|
||||
**本地驗證**:
|
||||
|
||||
- `python3 scripts/security/ssh-network-access-inventory.py --root . --output /tmp/ssh-network-access-inventory-check.json`:`SSH_NETWORK_ACCESS_INVENTORY_OK surfaces=16 ssh_sources=11 nodeports=2 runtime_gate=0`。
|
||||
- `python3 scripts/security/high-value-config-control-coverage.py --root . --output /tmp/high-value-config-control-coverage-check.json`:`HIGH_VALUE_CONFIG_CONTROL_COVERAGE_OK categories=14 c0=8 avg=65 runtime_gate=0`。
|
||||
- `python3 scripts/security/security-mirror-progress-guard.py --root .`:`SECURITY_MIRROR_PROGRESS_GUARD_OK`。
|
||||
- `python3 scripts/security/source-control-owner-response-guard.py --root .`:`SOURCE_CONTROL_OWNER_RESPONSE_GUARD_OK`。
|
||||
- `python3 -m py_compile scripts/security/ssh-network-access-inventory.py scripts/security/high-value-config-control-coverage.py scripts/security/security-mirror-progress-guard.py`:通過。
|
||||
- JSON parse:SSH / network snapshot / schema、高價值覆蓋 snapshot、IwoooS posture projection snapshot / schema、`zh-TW.json`、`en.json` 通過。
|
||||
- `cmp -s apps/web/messages/zh-TW.json apps/web/messages/en.json`:通過。
|
||||
- `python3 scripts/ops/doc-secrets-sanity-check.py docs .gitea`:`DOC_SECRET_SANITY_OK scanned_files=684`。
|
||||
- `pnpm --filter @awoooi/web typecheck`:通過。暫存 worktree 原本缺 `node_modules`,已用 lockfile 安裝本地依賴後驗證。
|
||||
- `git diff --check`:通過。
|
||||
|
||||
**完成度同步**:
|
||||
|
||||
- P1-2 repo-only surface 註冊:`100%`。
|
||||
- source existence / SHA256 hash:`100%`。
|
||||
- SSH / network 高價值配置成熟度:`48% -> 54%`。
|
||||
- owner response 收件 / 接受:`0%`。
|
||||
- live evidence collection:`0%`。
|
||||
- SSH / sudo / firewall / NetworkPolicy / NodePort / WireGuard / known_hosts gate:`0%`。
|
||||
- IwoooS 整體仍維持 `64%`;active runtime gate 仍 `0`。
|
||||
|
||||
**待正式站驗證**:推送並等待 Gitea CD 完成後,需以 production `/zh-TW/iwooos` 做 desktop / mobile sanity,確認 P1-2 卡顯示 `54%`、新 boundary markers 可見、卡內操作元素 `0`、無水平溢出,並補 deploy marker、Gitea run 與截圖路徑。
|
||||
|
||||
**邊界**:本段未 SSH、未 keyscan、未讀 live host、未讀 live firewall、未讀 live sudoers、未套用 NetworkPolicy、未改 NodePort、未啟動 WireGuard、未執行 sudo、未 active scan、未收 secret value、未改主機與未新增任何前端執行按鈕。
|
||||
|
||||
## 2026-06-11|IwoooS P1-1 Docker / systemd repo-only 清冊
|
||||
|
||||
|
||||
@@ -195,6 +195,27 @@
|
||||
"host_service_config_inventory_action_button_count",
|
||||
"host_service_config_inventory_coverage_percent_before_inventory",
|
||||
"host_service_config_inventory_coverage_percent_after_inventory",
|
||||
"ssh_network_access_inventory_first_layer",
|
||||
"ssh_network_access_inventory_surface_count",
|
||||
"ssh_network_access_inventory_source_exists_count",
|
||||
"ssh_network_access_inventory_expected_scope_count",
|
||||
"ssh_network_access_inventory_ssh_source_surface_count",
|
||||
"ssh_network_access_inventory_network_policy_surface_count",
|
||||
"ssh_network_access_inventory_nodeport_surface_count",
|
||||
"ssh_network_access_inventory_sudoers_surface_count",
|
||||
"ssh_network_access_inventory_wireguard_surface_count",
|
||||
"ssh_network_access_inventory_write_capable_surface_count",
|
||||
"ssh_network_access_inventory_owner_response_required_count",
|
||||
"ssh_network_access_inventory_owner_response_received_count",
|
||||
"ssh_network_access_inventory_owner_response_accepted_count",
|
||||
"ssh_network_access_inventory_live_evidence_required_count",
|
||||
"ssh_network_access_inventory_live_evidence_received_count",
|
||||
"ssh_network_access_inventory_maintenance_window_accepted_count",
|
||||
"ssh_network_access_inventory_rollback_owner_accepted_count",
|
||||
"ssh_network_access_inventory_runtime_gate_count",
|
||||
"ssh_network_access_inventory_action_button_count",
|
||||
"ssh_network_access_inventory_coverage_percent_before_inventory",
|
||||
"ssh_network_access_inventory_coverage_percent_after_inventory",
|
||||
"high_value_config_owner_packet_first_layer",
|
||||
"high_value_config_owner_packet_summary_count",
|
||||
"high_value_config_owner_packet_item_count",
|
||||
@@ -513,7 +534,7 @@
|
||||
},
|
||||
"high_value_config_control_coverage_average_percent": {
|
||||
"type": "integer",
|
||||
"const": 64
|
||||
"const": 65
|
||||
},
|
||||
"high_value_config_control_coverage_needs_live_evidence_count": {
|
||||
"type": "integer",
|
||||
@@ -850,6 +871,90 @@
|
||||
"s4_9_owner_response_metadata_intake_action_buttons_allowed": {
|
||||
"type": "boolean",
|
||||
"const": false
|
||||
},
|
||||
"ssh_network_access_inventory_first_layer": {
|
||||
"type": "boolean",
|
||||
"const": true
|
||||
},
|
||||
"ssh_network_access_inventory_surface_count": {
|
||||
"type": "integer",
|
||||
"const": 16
|
||||
},
|
||||
"ssh_network_access_inventory_source_exists_count": {
|
||||
"type": "integer",
|
||||
"const": 16
|
||||
},
|
||||
"ssh_network_access_inventory_expected_scope_count": {
|
||||
"type": "integer",
|
||||
"const": 16
|
||||
},
|
||||
"ssh_network_access_inventory_ssh_source_surface_count": {
|
||||
"type": "integer",
|
||||
"const": 11
|
||||
},
|
||||
"ssh_network_access_inventory_network_policy_surface_count": {
|
||||
"type": "integer",
|
||||
"const": 2
|
||||
},
|
||||
"ssh_network_access_inventory_nodeport_surface_count": {
|
||||
"type": "integer",
|
||||
"const": 2
|
||||
},
|
||||
"ssh_network_access_inventory_sudoers_surface_count": {
|
||||
"type": "integer",
|
||||
"const": 1
|
||||
},
|
||||
"ssh_network_access_inventory_wireguard_surface_count": {
|
||||
"type": "integer",
|
||||
"const": 1
|
||||
},
|
||||
"ssh_network_access_inventory_write_capable_surface_count": {
|
||||
"type": "integer",
|
||||
"const": 6
|
||||
},
|
||||
"ssh_network_access_inventory_owner_response_required_count": {
|
||||
"type": "integer",
|
||||
"const": 16
|
||||
},
|
||||
"ssh_network_access_inventory_owner_response_received_count": {
|
||||
"type": "integer",
|
||||
"const": 0
|
||||
},
|
||||
"ssh_network_access_inventory_owner_response_accepted_count": {
|
||||
"type": "integer",
|
||||
"const": 0
|
||||
},
|
||||
"ssh_network_access_inventory_live_evidence_required_count": {
|
||||
"type": "integer",
|
||||
"const": 16
|
||||
},
|
||||
"ssh_network_access_inventory_live_evidence_received_count": {
|
||||
"type": "integer",
|
||||
"const": 0
|
||||
},
|
||||
"ssh_network_access_inventory_maintenance_window_accepted_count": {
|
||||
"type": "integer",
|
||||
"const": 0
|
||||
},
|
||||
"ssh_network_access_inventory_rollback_owner_accepted_count": {
|
||||
"type": "integer",
|
||||
"const": 0
|
||||
},
|
||||
"ssh_network_access_inventory_runtime_gate_count": {
|
||||
"type": "integer",
|
||||
"const": 0
|
||||
},
|
||||
"ssh_network_access_inventory_action_button_count": {
|
||||
"type": "integer",
|
||||
"const": 0
|
||||
},
|
||||
"ssh_network_access_inventory_coverage_percent_before_inventory": {
|
||||
"type": "integer",
|
||||
"const": 48
|
||||
},
|
||||
"ssh_network_access_inventory_coverage_percent_after_inventory": {
|
||||
"type": "integer",
|
||||
"const": 54
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
||||
211
docs/schemas/ssh_network_access_inventory_v1.schema.json
Normal file
211
docs/schemas/ssh_network_access_inventory_v1.schema.json
Normal file
@@ -0,0 +1,211 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://awoooi.wooo.work/schemas/ssh_network_access_inventory_v1.schema.json",
|
||||
"title": "IwoooS SSH / network access repo-only 清冊",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"schema_version",
|
||||
"generated_at",
|
||||
"git_commit",
|
||||
"status",
|
||||
"source_scope",
|
||||
"summary",
|
||||
"execution_boundaries",
|
||||
"expected_scopes",
|
||||
"access_surfaces",
|
||||
"write_capable_surfaces",
|
||||
"next_collection_order",
|
||||
"operator_interpretation"
|
||||
],
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"const": "ssh_network_access_inventory_v1"
|
||||
},
|
||||
"generated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"git_commit": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"const": "repo_only_inventory_ready"
|
||||
},
|
||||
"source_scope": {
|
||||
"const": "committed_repo_files_only"
|
||||
},
|
||||
"summary": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"surface_count",
|
||||
"source_exists_count",
|
||||
"expected_scope_count",
|
||||
"ssh_source_surface_count",
|
||||
"network_policy_surface_count",
|
||||
"nodeport_surface_count",
|
||||
"sudoers_surface_count",
|
||||
"wireguard_surface_count",
|
||||
"write_capable_surface_count",
|
||||
"surfaces_requiring_owner_response_count",
|
||||
"surfaces_requiring_live_evidence_count",
|
||||
"owner_response_received_count",
|
||||
"owner_response_accepted_count",
|
||||
"live_evidence_received_count",
|
||||
"maintenance_window_accepted_count",
|
||||
"rollback_owner_accepted_count",
|
||||
"runtime_gate_count",
|
||||
"action_button_count",
|
||||
"coverage_percent_after_inventory",
|
||||
"coverage_percent_before_inventory"
|
||||
],
|
||||
"properties": {
|
||||
"surface_count": { "const": 16 },
|
||||
"source_exists_count": { "const": 16 },
|
||||
"expected_scope_count": { "const": 16 },
|
||||
"ssh_source_surface_count": { "const": 11 },
|
||||
"network_policy_surface_count": { "const": 2 },
|
||||
"nodeport_surface_count": { "const": 2 },
|
||||
"sudoers_surface_count": { "const": 1 },
|
||||
"wireguard_surface_count": { "const": 1 },
|
||||
"write_capable_surface_count": { "const": 6 },
|
||||
"surfaces_requiring_owner_response_count": { "const": 16 },
|
||||
"surfaces_requiring_live_evidence_count": { "const": 16 },
|
||||
"owner_response_received_count": { "const": 0 },
|
||||
"owner_response_accepted_count": { "const": 0 },
|
||||
"live_evidence_received_count": { "const": 0 },
|
||||
"maintenance_window_accepted_count": { "const": 0 },
|
||||
"rollback_owner_accepted_count": { "const": 0 },
|
||||
"runtime_gate_count": { "const": 0 },
|
||||
"action_button_count": { "const": 0 },
|
||||
"coverage_percent_after_inventory": { "const": 54 },
|
||||
"coverage_percent_before_inventory": { "const": 48 }
|
||||
}
|
||||
},
|
||||
"execution_boundaries": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "const": false },
|
||||
"required": [
|
||||
"runtime_execution_authorized",
|
||||
"host_write_authorized",
|
||||
"ssh_read_authorized",
|
||||
"ssh_write_authorized",
|
||||
"sudo_action_authorized",
|
||||
"firewall_change_authorized",
|
||||
"network_policy_apply_authorized",
|
||||
"nodeport_change_authorized",
|
||||
"wireguard_change_authorized",
|
||||
"known_hosts_patch_authorized",
|
||||
"host_keyscan_authorized",
|
||||
"live_host_read_authorized",
|
||||
"secret_value_collection_allowed",
|
||||
"ssh_key_collection_allowed",
|
||||
"active_scan_authorized",
|
||||
"action_buttons_allowed"
|
||||
]
|
||||
},
|
||||
"expected_scopes": {
|
||||
"type": "array",
|
||||
"minItems": 16,
|
||||
"maxItems": 16,
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"access_surfaces": {
|
||||
"type": "array",
|
||||
"minItems": 16,
|
||||
"maxItems": 16,
|
||||
"items": {
|
||||
"$ref": "#/$defs/access_surface"
|
||||
}
|
||||
},
|
||||
"write_capable_surfaces": {
|
||||
"type": "array",
|
||||
"minItems": 6,
|
||||
"maxItems": 6,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"surface_id",
|
||||
"label",
|
||||
"config_kind",
|
||||
"expected_scope",
|
||||
"required_gate"
|
||||
],
|
||||
"properties": {
|
||||
"surface_id": { "type": "string" },
|
||||
"label": { "type": "string" },
|
||||
"config_kind": { "type": "string" },
|
||||
"expected_scope": { "type": "string" },
|
||||
"required_gate": {
|
||||
"const": "owner_response_plus_maintenance_window_plus_rollback_owner"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"next_collection_order": {
|
||||
"type": "array",
|
||||
"minItems": 10,
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"operator_interpretation": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"$defs": {
|
||||
"access_surface": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"surface_id",
|
||||
"label",
|
||||
"source_path",
|
||||
"expected_scope",
|
||||
"config_kind",
|
||||
"control_tier",
|
||||
"current_state",
|
||||
"access_scope",
|
||||
"requires_live_evidence",
|
||||
"requires_owner_response",
|
||||
"next_owner_action",
|
||||
"source_exists",
|
||||
"line_count",
|
||||
"sha256",
|
||||
"owner_response_received",
|
||||
"owner_response_accepted",
|
||||
"live_evidence_received",
|
||||
"maintenance_window_accepted",
|
||||
"rollback_owner_accepted",
|
||||
"runtime_gate_open",
|
||||
"action_buttons_allowed"
|
||||
],
|
||||
"properties": {
|
||||
"surface_id": { "type": "string" },
|
||||
"label": { "type": "string" },
|
||||
"source_path": { "type": "string" },
|
||||
"expected_scope": { "type": "string" },
|
||||
"config_kind": { "type": "string" },
|
||||
"control_tier": { "const": "C1" },
|
||||
"current_state": { "type": "string" },
|
||||
"access_scope": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"requires_live_evidence": { "const": true },
|
||||
"requires_owner_response": { "const": true },
|
||||
"next_owner_action": { "type": "string" },
|
||||
"source_exists": { "const": true },
|
||||
"line_count": { "type": "integer", "minimum": 1 },
|
||||
"sha256": { "type": "string", "minLength": 64, "maxLength": 64 },
|
||||
"owner_response_received": { "const": false },
|
||||
"owner_response_accepted": { "const": false },
|
||||
"live_evidence_received": { "const": false },
|
||||
"maintenance_window_accepted": { "const": false },
|
||||
"rollback_owner_accepted": { "const": false },
|
||||
"runtime_gate_open": { "const": false },
|
||||
"action_buttons_allowed": { "const": false }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@
|
||||
| C1 類別 | `4` | 監控、Docker / systemd、SSH / network、AI provider |
|
||||
| C2 類別 | `1` | 產品 runtime route 與跨產品邊界 |
|
||||
| C3 類別 | `1` | security evidence / snapshot / guard tooling |
|
||||
| 平均只讀控管成熟度 | `64%` | 僅代表框架 / evidence / owner packet 準備度,不代表 runtime 可執行 |
|
||||
| 平均只讀控管成熟度 | `65%` | 僅代表框架 / evidence / owner packet 準備度,不代表 runtime 可執行 |
|
||||
| 需要 live evidence 的類別 | `6` | 只能等 owner-provided redacted evidence 或維護窗口,不主動修改主機 |
|
||||
| owner response required | `14` | 每類都需要 owner response 才能往 accepted 前進 |
|
||||
| owner response received / accepted | `0 / 0` | 不得假性提高 |
|
||||
@@ -35,7 +35,7 @@
|
||||
| 優先 | 類別 | 目前成熟度 | 下一步 |
|
||||
|------|------|------------|--------|
|
||||
| P1-1 | Docker Compose / systemd / host service config | `50%` | repo-only 清冊已納入 9 個 surface;仍缺 110 / 188 live hash、restart window、rollback owner 與 post-check 指標 |
|
||||
| P1-2 | SSH / sudoers / known_hosts / firewall / WireGuard / NodePort | `48%` | 補 target whitelist、host key policy、ingress / egress matrix、network owner 與 rollback owner |
|
||||
| P1-2 | SSH / sudoers / known_hosts / firewall / WireGuard / NodePort | `54%` | repo-only 清冊已納入 16 個 SSH / network access surface;仍缺 live evidence、owner 與 rollback |
|
||||
| P1-3 | Backup / restore / escrow / retention | `52%` | 補 restore drill approval package、offsite escrow owner、retention owner 與 no-secret-value evidence |
|
||||
| P1-4 | Prometheus / Alertmanager / Grafana / SigNoz / Sentry / Langfuse | `56%` | 補 rule diff、receiver diff、reload owner、failure-only notification policy 與 route smoke |
|
||||
|
||||
@@ -100,3 +100,7 @@ python3 scripts/security/high-value-config-control-coverage.py \
|
||||
## 8. P1-1 Docker / systemd 清冊更新
|
||||
|
||||
`host_service_config_inventory_v1` 已把 Docker Compose、systemd / repair-bot、Ansible service role 與 host config backup capture 納入 repo-only 清冊,共 `9` 個 surface、`3` 個 write-capable surface、`2` 個 repair-bot whitelist、`1` 個 systemd restart surface。此更新只讓 `docker_compose_systemd_host_config` 從 `42%` 推進到 `50%`;owner response、live evidence、restart window、rollback owner、runtime gate 與 action button 仍全部為 `0`。
|
||||
|
||||
## 9. P1-2 SSH / network access 清冊更新
|
||||
|
||||
`ssh_network_access_inventory_v1` 已把 SSH target、known_hosts workflow、CI deploy SSH、monitoring SSH、backup SSH capture、sudoers wrapper、NetworkPolicy、NodePort、WireGuard runbook 與 alert SSH action catalog 納入 repo-only 清冊,共 `16` 個 surface、`6` 個 write-capable surface、`2` 個 NetworkPolicy、`2` 個 NodePort、`1` 個 sudoers surface 與 `1` 個 WireGuard surface。此更新只讓 `ssh_firewall_network_access` 從 `48%` 推進到 `54%`;owner response、live evidence、maintenance window、rollback owner、runtime gate 與 action button 仍全部為 `0`。
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
| 註冊配置類別 | `14` | 代表已進 Gate 分類,不代表已批准 |
|
||||
| C0 類別 | `8` | Nginx、DNS / TLS、K8s、secret、workflow / runner、runtime config、backup、agent-bounty runtime |
|
||||
| C1 類別 | `4` | 監控、Docker / systemd、SSH / network、AI provider |
|
||||
| 平均只讀控管成熟度 | `64%` | 只代表框架 / evidence / owner packet 準備度 |
|
||||
| 平均只讀控管成熟度 | `65%` | 只代表框架 / evidence / owner packet 準備度 |
|
||||
| 需要 live evidence 類別 | `6` | 只能等 owner-provided redacted evidence 或維護窗口,不主動 SSH |
|
||||
| owner response required | `14` | owner response received / accepted 仍 `0 / 0` |
|
||||
| runtime gate | `0` | 不提供執行按鈕 |
|
||||
@@ -45,6 +45,12 @@
|
||||
|
||||
此更新仍不是 live host truth:110 / 188 live hash、restart window、rollback owner、post-check 指標與 owner response received / accepted 全部仍為 `0`,也不得執行 `docker compose`、`systemctl`、repair-bot、Ansible apply 或任何 SSH 讀寫。
|
||||
|
||||
### 0.3 2026-06-11 SSH / network access repo-only 清冊
|
||||
|
||||
`ssh_network_access_inventory_v1` 已把 SSH target、known_hosts workflow、CI deploy SSH、monitoring SSH、backup SSH capture、sudoers wrapper、NetworkPolicy、NodePort、WireGuard runbook 與 alert SSH action catalog 納入只讀 snapshot。清冊目前共有 `16` 個 surface、`11` 個 SSH source surface、`6` 個 write-capable surface、`2` 個 NetworkPolicy、`2` 個 NodePort、`1` 個 sudoers surface 與 `1` 個 WireGuard surface,讓 SSH / network 類別成熟度從 `48%` 推進到 `54%`。
|
||||
|
||||
此更新仍不是 live network truth:live firewall、sudoers、known_hosts、NetworkPolicy、NodePort、WireGuard evidence、network owner、maintenance window、rollback owner 與 owner response received / accepted 全部仍為 `0`,也不得執行 SSH、keyscan、sudo、firewall change、NetworkPolicy apply、NodePort change 或 WireGuard cutover。
|
||||
|
||||
## 1. 目前已不符合新要求的項目
|
||||
|
||||
| 優先 | 項目 | 現況 | 風險 | 本階段處置 |
|
||||
|
||||
@@ -89,8 +89,9 @@ IwoooS 首版只讀取或對齊以下已提交 evidence:
|
||||
51. 10 個 frontend surface reverse bridge statuses,顯示既有資安入口目前是 embedded bridge、direct bridge 或 AwoooP read-only candidate;這只是連接狀態,不代表 owner response、runtime authorization、Code Review blocker、Gitea/GitHub action 或任何執行控制。
|
||||
52. 6 個 source control primary readiness items,顯示 GitHub primary 前置缺口:candidate repo inventory、primary ready counter、owner response validation、refs truth、workflow / secret name inventory、rollback ADR;這只是 readiness,不代表 repo 建立、visibility 變更、refs mutation、secret value collection、primary switch 或 Gitea 停用。
|
||||
53. 4 個 rollout risk read-only items,顯示風險來源部署 marker、`AWOOOI_ROLLOUT_RISK=1`、ArgoCD `Degraded` / `OutOfSync`、API health / smoke 已通過與執行期閘門仍為 0;這只是部署風險可見性,不代表 ArgoCD sync、kubectl、主機重啟、修復、部署或 runtime gate 已授權。
|
||||
54. 14 類 high-value config control coverage statuses,顯示 Nginx、DNS / TLS、K8s、secret、workflow、backup、agent-bounty runtime、monitoring、Docker / systemd、SSH / network、AI provider、產品 route 與 security evidence 的全域配置控管覆蓋矩陣;平均只讀成熟度 `64%`、C0 類別 `8`、需 live evidence 類別 `6`、owner response received / accepted 與 runtime gate 仍為 `0`,不代表 reload、sync、scan、secret rotation、payout 或主機操作授權。
|
||||
54. 14 類 high-value config control coverage statuses,顯示 Nginx、DNS / TLS、K8s、secret、workflow、backup、agent-bounty runtime、monitoring、Docker / systemd、SSH / network、AI provider、產品 route 與 security evidence 的全域配置控管覆蓋矩陣;平均只讀成熟度 `65%`、C0 類別 `8`、需 live evidence 類別 `6`、owner response received / accepted 與 runtime gate 仍為 `0`,不代表 reload、sync、scan、secret rotation、payout 或主機操作授權。
|
||||
55. 9 個 host-service config repo-only inventory surfaces,顯示 Docker Compose、systemd / repair-bot、Ansible service role 與 host config backup capture 的第一層清冊;write-capable surface `3`、repair-bot whitelist `2`、systemd restart surface `1`,owner response、live evidence、restart window、rollback owner、runtime gate 與 action button 仍全部為 `0`,不代表 `docker compose`、`systemctl`、repair-bot 或 Ansible apply 已授權。
|
||||
56. 16 個 SSH / network access repo-only inventory surfaces,顯示 SSH target、known_hosts workflow、CI deploy SSH、monitoring SSH、backup SSH capture、sudoers wrapper、NetworkPolicy、NodePort、WireGuard runbook 與 alert SSH action catalog 的第一層清冊;write-capable surface `6`、NetworkPolicy `2`、NodePort `2`、sudoers `1`、WireGuard `1`,owner response、live evidence、maintenance window、rollback owner、runtime gate 與 action button 仍全部為 `0`,不代表 SSH、sudo、firewall、NetworkPolicy、NodePort、WireGuard 或 known_hosts patch 已授權。
|
||||
|
||||
## 3.1 既有前端資安頁面整合
|
||||
|
||||
|
||||
111
docs/security/SSH-NETWORK-ACCESS-INVENTORY.md
Normal file
111
docs/security/SSH-NETWORK-ACCESS-INVENTORY.md
Normal file
@@ -0,0 +1,111 @@
|
||||
# IwoooS SSH / network access 只讀清冊
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 日期 | 2026-06-11 |
|
||||
| 狀態 | `repo_only_inventory_ready` |
|
||||
| 工具 | `scripts/security/ssh-network-access-inventory.py` |
|
||||
| Snapshot | `docs/security/ssh-network-access-inventory.snapshot.json` |
|
||||
| Schema | `docs/schemas/ssh_network_access_inventory_v1.schema.json` |
|
||||
| runtime gate | `0` |
|
||||
|
||||
## 1. 目的
|
||||
|
||||
這份清冊補齊高價值配置覆蓋矩陣中的 `ssh_firewall_network_access` 類別,把 repo 內會影響 SSH、sudoers、known_hosts、firewall / NetworkPolicy、NodePort 與 WireGuard 的配置來源先集中成可重跑 snapshot。
|
||||
|
||||
本階段仍是 repo-only 只讀清冊。它不是 live host truth,不是 firewall approval,不是 known_hosts patch approval,不是 NetworkPolicy apply approval,也不是 WireGuard cutover approval。
|
||||
|
||||
## 2. 覆蓋摘要
|
||||
|
||||
| 指標 | 目前值 | 說明 |
|
||||
|------|--------|------|
|
||||
| repo surface | `16` | 已納入 SSH / network access 相關 committed source |
|
||||
| source exists / hash | `16` | 每個 source path 皆存在並有 SHA-256 |
|
||||
| expected scope | `16` | 已整理每個 surface 的預期影響範圍 |
|
||||
| SSH source surface | `11` | 包含 inventory、CI deploy、monitoring、backup、alert action |
|
||||
| NetworkPolicy surface | `2` | production 與 ArgoCD metrics policy |
|
||||
| NodePort surface | `2` | ArgoCD metrics 與 Velero metrics |
|
||||
| sudoers surface | `1` | `awoooi-wrapper.sudoers` |
|
||||
| WireGuard surface | `1` | GCP Ollama WireGuard mesh runbook |
|
||||
| write-capable surface | `6` | CI deploy、monitoring deploy、sudoers、alert action catalog |
|
||||
| owner response received / accepted | `0 / 0` | 尚未收到或接受 owner response |
|
||||
| live evidence received | `0` | 尚未取得 owner-provided live evidence |
|
||||
| runtime / action | `0 / 0` | 未開 runtime gate,未提供操作按鈕 |
|
||||
| SSH / network 類別成熟度 | `48% -> 54%` | 只代表 repo-only 清冊完成,不代表 live 授權 |
|
||||
|
||||
## 3. 已納入 surface
|
||||
|
||||
| Surface | 類型 | 範圍 | 寫入能力 |
|
||||
|---------|------|------|----------|
|
||||
| `ansible_inventory_ssh_targets` | SSH target inventory | `110_111_112_120_121_188` | 否 |
|
||||
| `ansible_common_ssh_args` | SSH client policy | `multi_host` | 否 |
|
||||
| `gitea_cd_known_hosts_secret` | known_hosts workflow | `110_120_121_188_known_hosts` | 否 |
|
||||
| `gitea_cd_deploy_ssh` | CI deploy SSH | `k8s_ssh_host` | 是 |
|
||||
| `gitea_cd_dev_ssh` | CI deploy SSH | `192.168.0.120` | 是 |
|
||||
| `deploy_alerts_ssh_path` | CI deploy SSH | `192.168.0.110` | 是 |
|
||||
| `monitoring_discover_docker_ssh` | SSH discovery script | `110_188_docker_hosts` | 否 |
|
||||
| `monitoring_exporter_deploy_ssh` | monitoring SSH deploy script | `192.168.0.188` | 是 |
|
||||
| `backup_config_ssh_capture` | SSH backup capture | `110_188_120_121_cluster` | 否 |
|
||||
| `host_ops_sudoers_wrapper` | sudoers policy | `host_ops_minimal_sudo` | 是 |
|
||||
| `k8s_prod_network_policy` | K8s NetworkPolicy | `awoooi_prod_namespace` | 否 |
|
||||
| `argocd_metrics_network_policy` | K8s NetworkPolicy | `argocd_namespace` | 否 |
|
||||
| `argocd_metrics_nodeport` | K8s NodePort service | `argocd_nodeport_30882_30883` | 否 |
|
||||
| `velero_metrics_nodeport` | K8s NodePort service | `velero_nodeport_30885` | 否 |
|
||||
| `wireguard_mesh_runbook` | WireGuard runbook | `110_111_120_121_gcp_a_gcp_b` | 否 |
|
||||
| `alert_rules_ssh_actions` | alert SSH action rules | `ssh_mcp_action_catalog` | 是 |
|
||||
|
||||
## 4. 固定 0 / false 邊界
|
||||
|
||||
```text
|
||||
runtime_execution_authorized=false
|
||||
host_write_authorized=false
|
||||
ssh_read_authorized=false
|
||||
ssh_write_authorized=false
|
||||
sudo_action_authorized=false
|
||||
firewall_change_authorized=false
|
||||
network_policy_apply_authorized=false
|
||||
nodeport_change_authorized=false
|
||||
wireguard_change_authorized=false
|
||||
known_hosts_patch_authorized=false
|
||||
host_keyscan_authorized=false
|
||||
live_host_read_authorized=false
|
||||
secret_value_collection_allowed=false
|
||||
ssh_key_collection_allowed=false
|
||||
active_scan_authorized=false
|
||||
action_buttons_allowed=false
|
||||
```
|
||||
|
||||
## 5. 判讀規則
|
||||
|
||||
1. `source_exists=true` 只代表 repo 檔案存在,不代表 live host 與 repo 一致。
|
||||
2. `sha256` 是 committed source 的 hash,不是 live `/etc/ssh`、firewall、sudoers、NetworkPolicy 或 WireGuard hash。
|
||||
3. `write_capable_surface_count=6` 代表需要 owner review 的高風險入口,不代表可執行。
|
||||
4. `accept-new`、known_hosts、NodePort、NetworkPolicy 與 WireGuard 只能先形成 owner 問題,不得自動 patch、keyscan、apply 或 cutover。
|
||||
5. 後續若要取得 live evidence,只能走 owner-provided redacted evidence、維護窗口與 rollback owner;不得在本階段主動 SSH、sudo、掃描或讀 secret。
|
||||
|
||||
## 6. 指令
|
||||
|
||||
```bash
|
||||
python3 scripts/security/ssh-network-access-inventory.py \
|
||||
--root . \
|
||||
--output docs/security/ssh-network-access-inventory.snapshot.json
|
||||
```
|
||||
|
||||
固定 committed snapshot 時間:
|
||||
|
||||
```bash
|
||||
python3 scripts/security/ssh-network-access-inventory.py \
|
||||
--root . \
|
||||
--generated-at 2026-06-11T23:55:00+08:00 \
|
||||
--output docs/security/ssh-network-access-inventory.snapshot.json
|
||||
```
|
||||
|
||||
## 7. 完成度
|
||||
|
||||
| 工作 | 完成度 | 說明 |
|
||||
|------|--------|------|
|
||||
| repo-only surface 註冊 | `100%` | 已納入 16 個 SSH / network access surface |
|
||||
| source existence / hash | `100%` | 16 個 source path 皆已驗證存在並產生 hash |
|
||||
| owner response 收件 | `0%` | 尚未收到或接受 owner response |
|
||||
| live evidence collection | `0%` | 未 SSH、未 keyscan、未讀 live firewall、未讀 live sudoers |
|
||||
| SSH / sudo / firewall / NetworkPolicy / NodePort / WireGuard gate | `0%` | 全部維持未授權 |
|
||||
@@ -365,15 +365,17 @@
|
||||
"action_buttons_allowed": false,
|
||||
"category_id": "ssh_firewall_network_access",
|
||||
"control_tier": "C1",
|
||||
"coverage_percent": 48,
|
||||
"coverage_status": "policy_ready_needs_network_matrix",
|
||||
"current_gap": "尚未集中 ingress / egress、WireGuard、NodePort、firewall 與 known_hosts 矩陣。",
|
||||
"coverage_percent": 54,
|
||||
"coverage_status": "repo_only_inventory_ready_needs_live_owner_evidence",
|
||||
"current_gap": "repo-only 清冊已納入 16 個 SSH / network access surface;仍缺 live firewall / sudoers / known_hosts / NetworkPolicy / NodePort / WireGuard evidence、network owner 與 rollback owner。",
|
||||
"evidence_refs": [
|
||||
"docs/HARD_RULES.md",
|
||||
"docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md"
|
||||
"docs/security/IWOOOS-CONFIG-CONTROL-INVENTORY.md",
|
||||
"docs/security/SSH-NETWORK-ACCESS-INVENTORY.md",
|
||||
"docs/security/ssh-network-access-inventory.snapshot.json"
|
||||
],
|
||||
"label": "SSH / sudoers / known_hosts / firewall / WireGuard / NodePort",
|
||||
"next_owner_action": "補 target whitelist、host key policy、network owner、maintenance window 與 rollback owner。",
|
||||
"next_owner_action": "補 owner-provided live hash / disposition、host key pinning、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 post-check 指標。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"owner_response_required": true,
|
||||
@@ -520,16 +522,9 @@
|
||||
"secret_value_collection_allowed": false,
|
||||
"workflow_modification_authorized": false
|
||||
},
|
||||
"generated_at": "2026-06-11T23:21:00+08:00",
|
||||
"git_commit": "0a82648e",
|
||||
"generated_at": "2026-06-12T00:05:00+08:00",
|
||||
"git_commit": "7cd47558",
|
||||
"lowest_coverage_categories": [
|
||||
{
|
||||
"category_id": "ssh_firewall_network_access",
|
||||
"coverage_percent": 48,
|
||||
"current_gap": "尚未集中 ingress / egress、WireGuard、NodePort、firewall 與 known_hosts 矩陣。",
|
||||
"label": "SSH / sudoers / known_hosts / firewall / WireGuard / NodePort",
|
||||
"next_owner_action": "補 target whitelist、host key policy、network owner、maintenance window 與 rollback owner。"
|
||||
},
|
||||
{
|
||||
"category_id": "docker_compose_systemd_host_config",
|
||||
"coverage_percent": 50,
|
||||
@@ -544,6 +539,13 @@
|
||||
"label": "Backup / restore / escrow / retention",
|
||||
"next_owner_action": "補 restore drill approval package、escrow owner、retention owner 與 no-secret-value evidence。"
|
||||
},
|
||||
{
|
||||
"category_id": "ssh_firewall_network_access",
|
||||
"coverage_percent": 54,
|
||||
"current_gap": "repo-only 清冊已納入 16 個 SSH / network access surface;仍缺 live firewall / sudoers / known_hosts / NetworkPolicy / NodePort / WireGuard evidence、network owner 與 rollback owner。",
|
||||
"label": "SSH / sudoers / known_hosts / firewall / WireGuard / NodePort",
|
||||
"next_owner_action": "補 owner-provided live hash / disposition、host key pinning、firewall owner、NetworkPolicy / NodePort owner、WireGuard owner、maintenance window、rollback owner 與 post-check 指標。"
|
||||
},
|
||||
{
|
||||
"category_id": "monitoring_alerting_observability",
|
||||
"coverage_percent": 56,
|
||||
@@ -573,7 +575,7 @@
|
||||
"status": "coverage_matrix_ready",
|
||||
"summary": {
|
||||
"action_button_count": 0,
|
||||
"average_coverage_percent": 64,
|
||||
"average_coverage_percent": 65,
|
||||
"c0_category_count": 8,
|
||||
"c1_category_count": 4,
|
||||
"c2_category_count": 1,
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
"docs/security/host-service-config-inventory.snapshot.json",
|
||||
"docs/security/HOST-SERVICE-CONFIG-INVENTORY.md",
|
||||
"docs/schemas/host_service_config_inventory_v1.schema.json",
|
||||
"docs/security/ssh-network-access-inventory.snapshot.json",
|
||||
"docs/security/SSH-NETWORK-ACCESS-INVENTORY.md",
|
||||
"docs/schemas/ssh_network_access_inventory_v1.schema.json",
|
||||
"docs/LOGBOOK.md",
|
||||
"docs/workplans/2026-06-04-iwooos-security-governance-p0.md",
|
||||
"apps/web/src/app/[locale]/iwooos/page.tsx",
|
||||
@@ -236,7 +239,7 @@
|
||||
"high_value_config_control_coverage_category_count": 14,
|
||||
"high_value_config_control_coverage_c0_category_count": 8,
|
||||
"high_value_config_control_coverage_c1_category_count": 4,
|
||||
"high_value_config_control_coverage_average_percent": 64,
|
||||
"high_value_config_control_coverage_average_percent": 65,
|
||||
"high_value_config_control_coverage_needs_live_evidence_count": 6,
|
||||
"high_value_config_control_coverage_owner_response_required_count": 14,
|
||||
"high_value_config_control_coverage_owner_response_received_count": 0,
|
||||
@@ -263,6 +266,27 @@
|
||||
"host_service_config_inventory_action_button_count": 0,
|
||||
"host_service_config_inventory_coverage_percent_before_inventory": 42,
|
||||
"host_service_config_inventory_coverage_percent_after_inventory": 50,
|
||||
"ssh_network_access_inventory_first_layer": true,
|
||||
"ssh_network_access_inventory_surface_count": 16,
|
||||
"ssh_network_access_inventory_source_exists_count": 16,
|
||||
"ssh_network_access_inventory_expected_scope_count": 16,
|
||||
"ssh_network_access_inventory_ssh_source_surface_count": 11,
|
||||
"ssh_network_access_inventory_network_policy_surface_count": 2,
|
||||
"ssh_network_access_inventory_nodeport_surface_count": 2,
|
||||
"ssh_network_access_inventory_sudoers_surface_count": 1,
|
||||
"ssh_network_access_inventory_wireguard_surface_count": 1,
|
||||
"ssh_network_access_inventory_write_capable_surface_count": 6,
|
||||
"ssh_network_access_inventory_owner_response_required_count": 16,
|
||||
"ssh_network_access_inventory_owner_response_received_count": 0,
|
||||
"ssh_network_access_inventory_owner_response_accepted_count": 0,
|
||||
"ssh_network_access_inventory_live_evidence_required_count": 16,
|
||||
"ssh_network_access_inventory_live_evidence_received_count": 0,
|
||||
"ssh_network_access_inventory_maintenance_window_accepted_count": 0,
|
||||
"ssh_network_access_inventory_rollback_owner_accepted_count": 0,
|
||||
"ssh_network_access_inventory_runtime_gate_count": 0,
|
||||
"ssh_network_access_inventory_action_button_count": 0,
|
||||
"ssh_network_access_inventory_coverage_percent_before_inventory": 48,
|
||||
"ssh_network_access_inventory_coverage_percent_after_inventory": 54,
|
||||
"high_value_config_owner_packet_first_layer": true,
|
||||
"high_value_config_owner_packet_summary_count": 4,
|
||||
"high_value_config_owner_packet_item_count": 6,
|
||||
|
||||
571
docs/security/ssh-network-access-inventory.snapshot.json
Normal file
571
docs/security/ssh-network-access-inventory.snapshot.json
Normal file
@@ -0,0 +1,571 @@
|
||||
{
|
||||
"access_surfaces": [
|
||||
{
|
||||
"access_scope": [
|
||||
"192.168.0.110",
|
||||
"192.168.0.111",
|
||||
"192.168.0.112",
|
||||
"192.168.0.120",
|
||||
"192.168.0.121",
|
||||
"192.168.0.188"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "ssh_target_inventory",
|
||||
"control_tier": "C1",
|
||||
"current_state": "repo_source_visible_needs_pinned_host_key_policy",
|
||||
"expected_scope": "110_111_112_120_121_188",
|
||||
"label": "Ansible inventory SSH targets",
|
||||
"line_count": 48,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 host owner、pinned known_hosts disposition、ProxyJump policy、key owner 與 rollback owner。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "86108dce9174b5c0a794d240dd40518966d9c340950fc6306845b704f12e6536",
|
||||
"source_exists": true,
|
||||
"source_path": "infra/ansible/inventory/hosts.yml",
|
||||
"surface_id": "ansible_inventory_ssh_targets"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"StrictHostKeyChecking=accept-new",
|
||||
"ConnectTimeout=10"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "ssh_client_policy",
|
||||
"control_tier": "C1",
|
||||
"current_state": "accept_new_policy_visible_needs_owner_disposition",
|
||||
"expected_scope": "multi_host",
|
||||
"label": "Ansible common SSH host key policy",
|
||||
"line_count": 20,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "確認 accept-new 是否只限 bootstrap,補升級 pinned known_hosts 的 owner 與時間窗。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "c3d5cb63cf84dea98195aa075e69ca90be7422b5805c0cfc50c1d97b832ad86e",
|
||||
"source_exists": true,
|
||||
"source_path": "infra/ansible/inventory/group_vars/all.yml",
|
||||
"surface_id": "ansible_common_ssh_args"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"192.168.0.110",
|
||||
"192.168.0.120",
|
||||
"192.168.0.121",
|
||||
"192.168.0.188"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "known_hosts_secret_workflow",
|
||||
"control_tier": "C1",
|
||||
"current_state": "repo_guard_visible_live_secret_not_verified",
|
||||
"expected_scope": "110_120_121_188_known_hosts",
|
||||
"label": "Gitea CD repair known_hosts secret",
|
||||
"line_count": 1562,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 owner-provided known_hosts secret metadata、缺 120 時的處置、key rotation owner 與失敗通知 owner。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "5b41cdc34c954a383ebea9e4109d10165ceb40589d55df9ee6e808d4092bf593",
|
||||
"source_exists": true,
|
||||
"source_path": ".gitea/workflows/cd.yaml",
|
||||
"surface_id": "gitea_cd_known_hosts_secret"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"K8S_SSH_HOST",
|
||||
"deploy_key",
|
||||
"kubectl apply",
|
||||
"ArgoCD sync"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "ci_deploy_ssh",
|
||||
"control_tier": "C1",
|
||||
"current_state": "write_capable_deploy_path_visible_gate_closed",
|
||||
"expected_scope": "k8s_ssh_host",
|
||||
"label": "Gitea CD K8s deploy SSH path",
|
||||
"line_count": 1562,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 deploy SSH host owner、maintenance window、rollback owner、post-check 指標與 break-glass policy。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "5b41cdc34c954a383ebea9e4109d10165ceb40589d55df9ee6e808d4092bf593",
|
||||
"source_exists": true,
|
||||
"source_path": ".gitea/workflows/cd.yaml",
|
||||
"surface_id": "gitea_cd_deploy_ssh"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"192.168.0.120",
|
||||
"deploy_key",
|
||||
"kubectl apply"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "ci_deploy_ssh",
|
||||
"control_tier": "C1",
|
||||
"current_state": "dev_write_capable_deploy_path_visible_gate_closed",
|
||||
"expected_scope": "192.168.0.120",
|
||||
"label": "Gitea CD dev deploy SSH path",
|
||||
"line_count": 262,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "確認 dev deploy key scope、host key policy、rollback owner 與 dev/prod 邊界。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "e344a4672cb543979c3bb8ea67967c103332587b4a52a939c837457aaeae686d",
|
||||
"source_exists": true,
|
||||
"source_path": ".gitea/workflows/cd-dev.yaml",
|
||||
"surface_id": "gitea_cd_dev_ssh"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"192.168.0.110",
|
||||
"deploy alert scripts"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "ci_deploy_ssh",
|
||||
"control_tier": "C1",
|
||||
"current_state": "write_capable_alert_deploy_path_visible_gate_closed",
|
||||
"expected_scope": "192.168.0.110",
|
||||
"label": "Deploy alerts SSH path",
|
||||
"line_count": 72,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 alert deploy owner、known_hosts pinning、rollback owner、post-check 與通知路徑。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "b0389fa65da643d411f6961928a276d555ad6a416366bf87f3f5c2c06ee45d13",
|
||||
"source_exists": true,
|
||||
"source_path": ".gitea/workflows/deploy-alerts.yaml",
|
||||
"surface_id": "deploy_alerts_ssh_path"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"192.168.0.110",
|
||||
"192.168.0.188",
|
||||
"docker ps"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "ssh_discovery_script",
|
||||
"control_tier": "C1",
|
||||
"current_state": "accept_new_scanner_visible_needs_read_only_gate",
|
||||
"expected_scope": "110_188_docker_hosts",
|
||||
"label": "Monitoring Docker discovery SSH scanner",
|
||||
"line_count": 314,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 scanner 執行 owner、read-only window、pinned known_hosts、輸出脫敏與失敗處置。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "563faf8efcfdbd5a79cc87e0d43c2ba11bebf755a773c97b9c0778f1f0634a15",
|
||||
"source_exists": true,
|
||||
"source_path": "ops/monitoring/discover_docker.py",
|
||||
"surface_id": "monitoring_discover_docker_ssh"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"192.168.0.188",
|
||||
"scp",
|
||||
"docker compose up -d"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "monitoring_ssh_deploy_script",
|
||||
"control_tier": "C1",
|
||||
"current_state": "write_capable_script_visible_gate_closed",
|
||||
"expected_scope": "192.168.0.188",
|
||||
"label": "Monitoring exporter deploy SSH script",
|
||||
"line_count": 76,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 exporter deploy owner、maintenance window、rollback owner、host key policy 與 post-check 指標。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "dbcbca21cf6fd5083177cb8a12c008c1aefed8e6ed05b70d738b3db37699cef3",
|
||||
"source_exists": true,
|
||||
"source_path": "ops/monitoring/deploy-exporters.sh",
|
||||
"surface_id": "monitoring_exporter_deploy_ssh"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"/etc/ssh",
|
||||
"/etc/nginx",
|
||||
"systemd",
|
||||
"docker",
|
||||
"k8s"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "ssh_backup_capture",
|
||||
"control_tier": "C1",
|
||||
"current_state": "read_capable_capture_visible_not_executed",
|
||||
"expected_scope": "110_188_120_121_cluster",
|
||||
"label": "Backup config SSH capture",
|
||||
"line_count": 359,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 backup execution owner、secret redaction proof、retention owner 與 restore validation。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "d24301cff44e464bd19ce0792362be16916ccde8c92f92351a19ef4ee988f15e",
|
||||
"source_exists": true,
|
||||
"source_path": "scripts/backup/backup-configs.sh",
|
||||
"surface_id": "backup_config_ssh_capture"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"awoooi-hosts-add",
|
||||
"docker kill SIGHUP",
|
||||
"promtool",
|
||||
"amtool"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "sudoers_policy",
|
||||
"control_tier": "C1",
|
||||
"current_state": "sudoers_source_visible_needs_live_owner_evidence",
|
||||
"expected_scope": "host_ops_minimal_sudo",
|
||||
"label": "Host ops sudoers wrapper",
|
||||
"line_count": 27,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 live sudoers hash、visudo validation、command owner、rollback owner 與 forbidden command proof。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "eff02c67402d2f5b2ac8d112dca26a15dc34f03593ca490a0682a6dfa9b0394d",
|
||||
"source_exists": true,
|
||||
"source_path": "scripts/host-ops/awoooi-wrapper.sudoers",
|
||||
"surface_id": "host_ops_sudoers_wrapper"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"default deny",
|
||||
"ingress",
|
||||
"egress",
|
||||
"SSH egress",
|
||||
"Ollama",
|
||||
"monitoring"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "k8s_network_policy",
|
||||
"control_tier": "C1",
|
||||
"current_state": "repo_policy_visible_needs_live_cluster_diff",
|
||||
"expected_scope": "awoooi_prod_namespace",
|
||||
"label": "K8s production NetworkPolicy",
|
||||
"line_count": 306,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 live NetworkPolicy diff、ingress / egress owner、rollback owner 與 route smoke。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "f5ea6a9f5fb0cc44664d97a3ed639fa4b43ffd9bcfd70a1f6b44640791b7859f",
|
||||
"source_exists": true,
|
||||
"source_path": "k8s/awoooi-prod/02-network-policy.yaml",
|
||||
"surface_id": "k8s_prod_network_policy"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"192.168.0.188",
|
||||
"argocd metrics",
|
||||
"192.168.0.0/24 UI"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "k8s_network_policy",
|
||||
"control_tier": "C1",
|
||||
"current_state": "repo_policy_visible_needs_prometheus_owner_confirmation",
|
||||
"expected_scope": "argocd_namespace",
|
||||
"label": "ArgoCD metrics NetworkPolicy",
|
||||
"line_count": 80,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 Prometheus scrape owner、NodePort exposure owner、live policy diff 與 rollback owner。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "41ccd0bb22410c48adc84eae74391106c3f28fe181786cfe4128a07f99d2942c",
|
||||
"source_exists": true,
|
||||
"source_path": "k8s/argocd/argocd-metrics-network-policy.yaml",
|
||||
"surface_id": "argocd_metrics_network_policy"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"nodePort 30882",
|
||||
"nodePort 30883"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "k8s_nodeport_service",
|
||||
"control_tier": "C1",
|
||||
"current_state": "nodeport_source_visible_needs_exposure_review",
|
||||
"expected_scope": "argocd_nodeport_30882_30883",
|
||||
"label": "ArgoCD metrics NodePort",
|
||||
"line_count": 47,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 NodePort exposure owner、firewall owner、Prometheus source whitelist 與 rollback owner。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "7f4a8f09206ce0afc185fe11d5e55265bb553b671471724cdcd83c259ec7d266",
|
||||
"source_exists": true,
|
||||
"source_path": "k8s/argocd/argocd-metrics-nodeport.yaml",
|
||||
"surface_id": "argocd_metrics_nodeport"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"nodePort 30885",
|
||||
"backup metrics"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "k8s_nodeport_service",
|
||||
"control_tier": "C1",
|
||||
"current_state": "nodeport_source_visible_needs_exposure_review",
|
||||
"expected_scope": "velero_nodeport_30885",
|
||||
"label": "Velero metrics NodePort",
|
||||
"line_count": 26,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 Velero metrics exposure owner、firewall owner、Prometheus source whitelist 與 rollback owner。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "684959def32b792e2bca34b477afcdfe2b0c6dfd0cb90f4b681a514922d62b75",
|
||||
"source_exists": true,
|
||||
"source_path": "k8s/velero/velero-metrics-service.yaml",
|
||||
"surface_id": "velero_metrics_nodeport"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"10.77.114.0/24",
|
||||
"51820/udp",
|
||||
"GCP-A",
|
||||
"GCP-B"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "wireguard_runbook",
|
||||
"control_tier": "C1",
|
||||
"current_state": "target_architecture_documented_not_applied",
|
||||
"expected_scope": "110_111_120_121_gcp_a_gcp_b",
|
||||
"label": "GCP Ollama WireGuard mesh runbook",
|
||||
"line_count": 280,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 WireGuard owner、public-key metadata、firewall rule owner、canary plan、rollback owner 與 cutover gate。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "0af082698c727176ca82c79f95f3950f4c32ed6aabc91c88aff41831fbf0c044",
|
||||
"source_exists": true,
|
||||
"source_path": "docs/runbooks/GCP-OLLAMA-WIREGUARD-MESH.md",
|
||||
"surface_id": "wireguard_mesh_runbook"
|
||||
},
|
||||
{
|
||||
"access_scope": [
|
||||
"ssh_diagnose",
|
||||
"docker restart",
|
||||
"systemctl restart",
|
||||
"docker compose",
|
||||
"docker prune"
|
||||
],
|
||||
"action_buttons_allowed": false,
|
||||
"config_kind": "alert_ssh_action_rules",
|
||||
"control_tier": "C1",
|
||||
"current_state": "ssh_action_catalog_visible_gate_closed",
|
||||
"expected_scope": "ssh_mcp_action_catalog",
|
||||
"label": "Alert rules SSH action surface",
|
||||
"line_count": 889,
|
||||
"live_evidence_received": false,
|
||||
"maintenance_window_accepted": false,
|
||||
"next_owner_action": "補 action owner、read/write/admin 分級、approval gate、cooldown、rollback owner 與 post-check 指標。",
|
||||
"owner_response_accepted": false,
|
||||
"owner_response_received": false,
|
||||
"requires_live_evidence": true,
|
||||
"requires_owner_response": true,
|
||||
"rollback_owner_accepted": false,
|
||||
"runtime_gate_open": false,
|
||||
"sha256": "5786505aa05073bbb2069203a443a75c8337a289dc015630792d0c201c85cafb",
|
||||
"source_exists": true,
|
||||
"source_path": "apps/api/alert_rules.yaml",
|
||||
"surface_id": "alert_rules_ssh_actions"
|
||||
}
|
||||
],
|
||||
"execution_boundaries": {
|
||||
"action_buttons_allowed": false,
|
||||
"active_scan_authorized": false,
|
||||
"firewall_change_authorized": false,
|
||||
"host_keyscan_authorized": false,
|
||||
"host_write_authorized": false,
|
||||
"known_hosts_patch_authorized": false,
|
||||
"live_host_read_authorized": false,
|
||||
"network_policy_apply_authorized": false,
|
||||
"nodeport_change_authorized": false,
|
||||
"runtime_execution_authorized": false,
|
||||
"secret_value_collection_allowed": false,
|
||||
"ssh_key_collection_allowed": false,
|
||||
"ssh_read_authorized": false,
|
||||
"ssh_write_authorized": false,
|
||||
"sudo_action_authorized": false,
|
||||
"wireguard_change_authorized": false
|
||||
},
|
||||
"expected_scopes": [
|
||||
"110_111_112_120_121_188",
|
||||
"110_111_120_121_gcp_a_gcp_b",
|
||||
"110_120_121_188_known_hosts",
|
||||
"110_188_120_121_cluster",
|
||||
"110_188_docker_hosts",
|
||||
"192.168.0.110",
|
||||
"192.168.0.120",
|
||||
"192.168.0.188",
|
||||
"argocd_namespace",
|
||||
"argocd_nodeport_30882_30883",
|
||||
"awoooi_prod_namespace",
|
||||
"host_ops_minimal_sudo",
|
||||
"k8s_ssh_host",
|
||||
"multi_host",
|
||||
"ssh_mcp_action_catalog",
|
||||
"velero_nodeport_30885"
|
||||
],
|
||||
"generated_at": "2026-06-11T23:55:00+08:00",
|
||||
"git_commit": "7cd47558",
|
||||
"next_collection_order": [
|
||||
"gitea_cd_known_hosts_secret",
|
||||
"ansible_inventory_ssh_targets",
|
||||
"host_ops_sudoers_wrapper",
|
||||
"k8s_prod_network_policy",
|
||||
"alert_rules_ssh_actions",
|
||||
"argocd_metrics_nodeport",
|
||||
"velero_metrics_nodeport",
|
||||
"wireguard_mesh_runbook",
|
||||
"monitoring_discover_docker_ssh",
|
||||
"backup_config_ssh_capture"
|
||||
],
|
||||
"operator_interpretation": [
|
||||
"這是 repo-only SSH / network access 清冊,不是 live host、firewall 或 cluster truth。",
|
||||
"source_exists=true 只代表 repo 檔案存在;不代表 known_hosts、sudoers、NetworkPolicy、NodePort 或 WireGuard 已套用。",
|
||||
"write-capable SSH / sudoers / alert action surface 可見代表需被管控,不代表 SSH、sudo、docker、systemctl 或 kubectl 已授權。",
|
||||
"所有 live hash、pinned host key、maintenance window、rollback owner、firewall owner 與 post-check 指標都仍需 owner response。"
|
||||
],
|
||||
"schema_version": "ssh_network_access_inventory_v1",
|
||||
"source_scope": "committed_repo_files_only",
|
||||
"status": "repo_only_inventory_ready",
|
||||
"summary": {
|
||||
"action_button_count": 0,
|
||||
"coverage_percent_after_inventory": 54,
|
||||
"coverage_percent_before_inventory": 48,
|
||||
"expected_scope_count": 16,
|
||||
"live_evidence_received_count": 0,
|
||||
"maintenance_window_accepted_count": 0,
|
||||
"network_policy_surface_count": 2,
|
||||
"nodeport_surface_count": 2,
|
||||
"owner_response_accepted_count": 0,
|
||||
"owner_response_received_count": 0,
|
||||
"rollback_owner_accepted_count": 0,
|
||||
"runtime_gate_count": 0,
|
||||
"source_exists_count": 16,
|
||||
"ssh_source_surface_count": 11,
|
||||
"sudoers_surface_count": 1,
|
||||
"surface_count": 16,
|
||||
"surfaces_requiring_live_evidence_count": 16,
|
||||
"surfaces_requiring_owner_response_count": 16,
|
||||
"wireguard_surface_count": 1,
|
||||
"write_capable_surface_count": 6
|
||||
},
|
||||
"write_capable_surfaces": [
|
||||
{
|
||||
"config_kind": "ci_deploy_ssh",
|
||||
"expected_scope": "k8s_ssh_host",
|
||||
"label": "Gitea CD K8s deploy SSH path",
|
||||
"required_gate": "owner_response_plus_maintenance_window_plus_rollback_owner",
|
||||
"surface_id": "gitea_cd_deploy_ssh"
|
||||
},
|
||||
{
|
||||
"config_kind": "ci_deploy_ssh",
|
||||
"expected_scope": "192.168.0.120",
|
||||
"label": "Gitea CD dev deploy SSH path",
|
||||
"required_gate": "owner_response_plus_maintenance_window_plus_rollback_owner",
|
||||
"surface_id": "gitea_cd_dev_ssh"
|
||||
},
|
||||
{
|
||||
"config_kind": "ci_deploy_ssh",
|
||||
"expected_scope": "192.168.0.110",
|
||||
"label": "Deploy alerts SSH path",
|
||||
"required_gate": "owner_response_plus_maintenance_window_plus_rollback_owner",
|
||||
"surface_id": "deploy_alerts_ssh_path"
|
||||
},
|
||||
{
|
||||
"config_kind": "monitoring_ssh_deploy_script",
|
||||
"expected_scope": "192.168.0.188",
|
||||
"label": "Monitoring exporter deploy SSH script",
|
||||
"required_gate": "owner_response_plus_maintenance_window_plus_rollback_owner",
|
||||
"surface_id": "monitoring_exporter_deploy_ssh"
|
||||
},
|
||||
{
|
||||
"config_kind": "sudoers_policy",
|
||||
"expected_scope": "host_ops_minimal_sudo",
|
||||
"label": "Host ops sudoers wrapper",
|
||||
"required_gate": "owner_response_plus_maintenance_window_plus_rollback_owner",
|
||||
"surface_id": "host_ops_sudoers_wrapper"
|
||||
},
|
||||
{
|
||||
"config_kind": "alert_ssh_action_rules",
|
||||
"expected_scope": "ssh_mcp_action_catalog",
|
||||
"label": "Alert rules SSH action surface",
|
||||
"required_gate": "owner_response_plus_maintenance_window_plus_rollback_owner",
|
||||
"surface_id": "alert_rules_ssh_actions"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user