feat(iwooos): add security operating system guard
Some checks failed
Code Review / ai-code-review (push) Successful in 13s
CD Pipeline / tests (push) Successful in 1m41s
CD Pipeline / build-and-deploy (push) Successful in 5m0s
CD Pipeline / post-deploy-checks (push) Successful in 1m30s
Ansible / Reboot Recovery Contract / validate (push) Has been cancelled

This commit is contained in:
ogt
2026-06-25 15:52:34 +08:00
parent 57e7b307c8
commit a22a0f612d
10 changed files with 1652 additions and 0 deletions

View File

@@ -0,0 +1,427 @@
#!/usr/bin/env python3
"""IwoooS 資安作戰系統產生器。
本工具只產生 repo 內 snapshot將主流資安框架、SOC / CSIRT / DevSecOps
分工、即時危害分流、告警訊息合約、Wazuh / Kali / Nginx / host / CI/CD
驗證節點與 AI 自動化閉環,收斂成一份可重跑的作戰系統。
它不連線主機、不呼叫 Wazuh / Kali、不 SSH、不讀 secret、不送 Telegram、
不 reload Nginx / Alertmanager、不改 firewall / K8s / workflow也不啟用
active response、active scan、SOAR 或 auto block。
"""
from __future__ import annotations
import argparse
import json
import re
import subprocess
import sys
from datetime import datetime, timedelta, timezone
from pathlib import Path
from typing import Any
TAIPEI = timezone(timedelta(hours=8))
SNAPSHOT_PATH = Path("docs/security/iwooos-security-operating-system.snapshot.json")
SCHEMA_VERSION = "iwooos_security_operating_system_v1"
REFERENCE_FRAMEWORKS = [
("nist_csf_2_0", "NIST CSF 2.0", "https://www.nist.gov/cyberframework"),
("nist_sp_800_61_r3", "NIST SP 800-61 Rev. 3", "https://csrc.nist.gov/pubs/sp/800/61/r3/final"),
("cis_controls_v8_1", "CIS Controls v8.1", "https://www.cisecurity.org/controls/v8-1"),
("cisa_zero_trust", "CISA Zero Trust Maturity Model", "https://www.cisa.gov/resources-tools/resources/zero-trust-maturity-model"),
("cisa_kev", "CISA Known Exploited Vulnerabilities", "https://www.cisa.gov/known-exploited-vulnerabilities-catalog"),
("first_epss", "FIRST EPSS", "https://www.first.org/epss/"),
("mitre_attack", "MITRE ATT&CK Enterprise", "https://attack.mitre.org/matrices/enterprise/"),
("mitre_d3fend", "MITRE D3FEND", "https://d3fend.mitre.org/"),
("owasp_asvs", "OWASP ASVS", "https://owasp.org/www-project-application-security-verification-standard/"),
("owasp_samm", "OWASP SAMM", "https://owaspsamm.org/"),
("wazuh_xdr_siem", "Wazuh XDR / SIEM", "https://documentation.wazuh.com/current/index.html"),
("wazuh_active_response", "Wazuh Active Response", "https://documentation.wazuh.com/current/user-manual/capabilities/active-response/index.html"),
("prometheus_alertmanager", "Prometheus Alertmanager", "https://prometheus.io/docs/alerting/latest/alertmanager/"),
("opentelemetry", "OpenTelemetry", "https://opentelemetry.io/docs/what-is-opentelemetry/"),
("ocsf", "Open Cybersecurity Schema Framework", "https://ocsf.io/"),
("sigma", "Sigma detection rules", "https://sigmahq.io/sigma/"),
("slsa", "SLSA", "https://slsa.dev/"),
("spdx_cyclonedx", "SPDX / CycloneDX", "https://spdx.dev/"),
("sigstore_cosign", "Sigstore / Cosign", "https://docs.sigstore.dev/cosign/signing/signing_with_containers/"),
("nist_ai_rmf", "NIST AI RMF", "https://www.nist.gov/itl/ai-risk-management-framework"),
]
OPERATING_ROLES = [
("security_program_owner", "資安作戰負責人", "維護控制面、優先序、完成度與停止線。"),
("soc_reviewer", "SOC 審查人", "審查告警、SIEM、Wazuh、Kali 與 no-false-green evidence。"),
("incident_commander", "事故指揮", "統一 severity、scope、containment 候選與跨專案同步。"),
("platform_owner", "平台負責人", "負責 host、Docker、systemd、Nginx、K8s、ArgoCD 與 public gateway 影響判讀。"),
("service_owner", "服務負責人", "負責產品、API、網站、admin、webhook 與 AI provider route 的驗證。"),
("evidence_custodian", "證據保管人", "維護脫敏 refs、chain of custody、retention 與 raw absence attestation。"),
("change_manager", "變更管理人", "確認維護窗口、rollback owner、postcheck、operator notification 與 freeze。"),
("supply_chain_owner", "供應鏈負責人", "負責 workflow、runner、Harbor、SBOM、SLSA、Cosign、KEV / package SLA。"),
("ai_security_reviewer", "AI 安全審查人", "審核 AI agent tool 權限、prompt redaction、過度代理與成本邊界。"),
("executive_risk_owner", "風險負責人", "接受風險、例外期限、資源優先序與治理報告。"),
]
SEVERITY_LANES = [
("SEV0", "已確認入侵或 active exploitation", "15 分鐘內形成 case / freeze / containment 候選;不得無 owner 直接執行。"),
("SEV1", "公開入口高風險、KEV、credential exposure、Wazuh agent 消失", "30 分鐘內形成 owner packet、證據缺口與維護窗口草案。"),
("SEV2", "Nginx / firewall / runner / workflow / runtime drift", "4 小時內完成 diff、owner、rollback 與 postcheck 計畫。"),
("SEV3", "告警噪音、coverage gap、dashboard degradation", "1 個工作日內進入 backlog 與 no-false-green 修正。"),
("SEV4", "治理、文件、成熟度與低風險 hardening", "納入週期報告與例外期限,不得混成緊急事件。"),
]
WORKSTREAMS = [
("P0-01", "asset_exposure_graph", "P0", "資產 / 暴露面總圖", "host、domain、route、service、port、package、repo、runner、secret metadata、backup、AI agent"),
("P0-02", "wazuh_registry_truth", "P0", "Wazuh manager registry truth", "agent total、active、disconnected、last seen、expected minimum、dashboard / API mismatch"),
("P0-03", "host_intrusion_forensics", "P0", "主機入侵與鑑識", "auth、sudo、process、network、FIM、persistence、package、service、Docker event"),
("P0-04", "gateway_config_control", "P0", "Nginx / Gateway config-control", "source-to-live diff、rendered diff、nginx test ref、route smoke、rollback"),
("P0-05", "network_access_baseline", "P0", "SSH / firewall / WireGuard / NodePort baseline", "before / after、actor、impact、operator notification、restoration evidence"),
("P0-06", "secret_identity_hygiene", "P0", "身分與 secret metadata", "SSH、sudo、deploy key、runner token name、webhook secret name、OIDC、break-glass"),
("P0-07", "alert_readability_receipt", "P0", "告警可讀性與 receipt", "Telegram / Alertmanager / Wazuh alert card、dedupe、noise budget、receipt"),
("P0-08", "incident_case_gate", "P0", "Incident case gate", "case id、timeline、owner、decision、containment、recovery、postcheck、lesson learned"),
("P0-09", "kev_exposure_patch_priority", "P0", "KEV / exposure / package SLA", "CISA KEV、EPSS、public exposure、asset criticality、maintenance window"),
("P0-10", "backup_restore_forensic_retention", "P0", "備份 / 還原 / 鑑識保存", "restore drill、offsite、escrow、chain of custody、retention、rollback proof"),
("P0-11", "runner_workflow_supply_chain", "P0", "Runner / workflow / supply-chain", "Gitea、workflow、runner、deploy key、Harbor、SBOM、Cosign、SLSA"),
("P0-12", "ai_agent_permission_gate", "P0", "AI Agent 權限閘", "tool allowlist、redaction、cost、privacy、approval、excessive agency"),
("P1-01", "kali_evidence_envelope", "P1", "Kali 112 evidence envelope", "health、tool version、scope、normalized finding、active scan approval packet"),
("P1-02", "detection_as_code", "P1", "Detection-as-code", "ATT&CK、D3FEND、Sigma、測試資料、false-positive budget、rule owner"),
("P1-03", "ndr_passive_sensor", "P1", "NDR passive sensor", "Suricata、Zeek、DNS / TLS / HTTP / flow logs不開 IPS"),
("P1-04", "k8s_docker_hardening", "P1", "K8s / Docker hardening", "CIS / NSA-CISA 對照、Pod Security、RBAC、NetworkPolicy、audit log"),
("P1-05", "appsec_api_asvs", "P1", "AppSec / API ASVS", "auth、authorization、session、rate limit、CORS、security headers、webhook abuse case"),
("P1-06", "sbom_slsa_cosign", "P1", "SBOM / SLSA / Cosign", "SPDX、CycloneDX、VEX、provenance、artifact signing、verify"),
("P1-07", "soar_dry_run_case_enrichment", "P1", "SOAR dry-run / case enrichment", "TheHive / Cortex 類 case draft、enrichment、blast radius、rollback"),
("P1-08", "grc_exception_register", "P1", "GRC / exception register", "risk register、accepted risk、expiry、audit evidence、control owner"),
("P2-01", "ueba_behavior_baseline", "P2", "UEBA / 行為基線", "使用者、service account、runner、AI agent、host process、egress baseline"),
("P2-02", "purple_team_validation", "P2", "Purple-team / tabletop", "ATT&CK emulation、BAS / canary、偵測回歸需授權 scope"),
("P2-03", "mdr_247_process", "P2", "MDR / 24x7 流程", "on-call、升級、SLA、交接、值班報表、演練"),
("P2-04", "exposure_management_graph", "P2", "Exposure management graph", "外部攻擊面、弱點、身份、雲端、repo、AI agent、資料流"),
]
ALERT_CONTRACT_FIELDS = [
"event_title",
"severity_and_confidence",
"asset_alias_and_scope",
"what_happened_plain_language",
"why_it_matters",
"redacted_evidence_refs",
"ai_triage_lane",
"next_candidate_action",
"owner_gate_and_verification",
]
AUTOMATION_LOOP_STAGES = [
"sensor_evidence",
"normalizer_redaction",
"ai_triage_lane",
"candidate_generation",
"owner_gate",
"execution_boundary",
"verifier_readback",
"learning_writeback",
]
VERIFICATION_STAGES = [
"source_guard",
"snapshot_schema",
"redaction_guard",
"owner_packet_preflight",
"wazuh_registry_readback",
"kali_scope_readback",
"alert_receipt_readback",
"route_desktop_mobile_smoke",
"postcheck_metrics",
"cross_session_sync",
"logbook_update",
"no_false_green_review",
]
NO_FALSE_GREEN_RULES = [
"route_200_is_not_security_clearance",
"dashboard_up_is_not_agent_registry",
"agent_active_is_not_intrusion_closed",
"alert_quiet_is_not_alert_chain_healthy",
"backup_fresh_is_not_restore_drill",
"cd_success_is_not_runtime_authorization",
"ui_visible_is_not_owner_acceptance",
"awooop_approval_is_not_security_approval",
"external_agent_claim_is_not_forensic_proof",
"transport_connection_is_not_registry_acceptance",
"source_snapshot_is_not_live_truth",
"general_continue_is_not_maintenance_window",
]
CROSS_SESSION_SYNC_CHECKPOINTS = [
"fetch_gitea_main_before_work",
"share_commit_and_run_ids",
"share_production_readback",
"declare_runtime_boundaries",
"freeze_same_host_or_same_gateway_edits",
"record_owner_gate_state",
"update_logbook_after_stage",
]
BLOCKED_ACTIONS = [
"ssh_write",
"host_live_secret_read",
"wazuh_active_response_enable",
"kali_active_scan",
"kali_execute",
"nginx_reload",
"firewall_change",
"docker_restart",
"systemd_restart",
"argocd_sync",
"kubectl_apply",
"workflow_modification",
"secret_rotation",
"telegram_live_send",
"soar_action",
"auto_block",
"production_write",
"force_push",
]
FORBIDDEN_TEXT_PATTERNS = [
re.compile(r"\b(?:10|127|172\.(?:1[6-9]|2\d|3[01])|192\.168)\.\d{1,3}\.\d{1,3}\b"),
re.compile(r"Authorization\s*:", re.IGNORECASE),
re.compile(r"Bearer\s+[A-Za-z0-9._-]{10,}", re.IGNORECASE),
re.compile(r"Basic\s+[A-Za-z0-9+/=]{10,}", re.IGNORECASE),
re.compile(r"password\s*[:=]\s*['\"][^'\"]+['\"]", re.IGNORECASE),
re.compile(r"token\s*[:=]\s*['\"][^'\"]+['\"]", re.IGNORECASE),
re.compile(r"cookie\s*[:=]\s*['\"][^'\"]+['\"]", re.IGNORECASE),
re.compile(r"<codex_delegation>", re.IGNORECASE),
]
def git_short_sha(root: Path) -> str:
try:
result = subprocess.run(
["git", "rev-parse", "--short", "HEAD"],
cwd=root,
check=True,
capture_output=True,
text=True,
)
return result.stdout.strip()
except Exception:
return "unknown"
def build_snapshot(root: Path, generated_at: str) -> dict[str, Any]:
p0 = [item for item in WORKSTREAMS if item[2] == "P0"]
p1 = [item for item in WORKSTREAMS if item[2] == "P1"]
p2 = [item for item in WORKSTREAMS if item[2] == "P2"]
return {
"schema_version": SCHEMA_VERSION,
"generated_at": generated_at,
"git_commit": git_short_sha(root),
"status": "iwooos_security_operating_system_ready_no_runtime_action",
"mode": "repo_snapshot_guard_frontstage_only",
"reference_frameworks": [
{"framework_id": framework_id, "label": label, "source_url": source_url}
for framework_id, label, source_url in REFERENCE_FRAMEWORKS
],
"operating_roles": [
{"role_id": role_id, "label": label, "responsibility": responsibility, "runtime_gate_open": False}
for role_id, label, responsibility in OPERATING_ROLES
],
"severity_lanes": [
{"severity": severity, "label": label, "triage_target": target, "runtime_gate_open": False}
for severity, label, target in SEVERITY_LANES
],
"workstreams": [
{
"workstream_id": workstream_id,
"lane_id": lane_id,
"priority": priority,
"title": title,
"scope": scope,
"owner_packet_required": True,
"runtime_gate_open": False,
}
for workstream_id, lane_id, priority, title, scope in WORKSTREAMS
],
"alert_message_contract": [
{"field_id": field_id, "required": True, "raw_payload_allowed": False}
for field_id in ALERT_CONTRACT_FIELDS
],
"automation_loop_stages": [
{"stage_id": stage_id, "runtime_gate_open": False} for stage_id in AUTOMATION_LOOP_STAGES
],
"verification_stages": [
{"stage_id": stage_id, "accepted": False} for stage_id in VERIFICATION_STAGES
],
"no_false_green_rules": [
{"rule_id": rule_id, "enforced": True} for rule_id in NO_FALSE_GREEN_RULES
],
"cross_session_sync_checkpoints": [
{"checkpoint_id": checkpoint_id, "required": True} for checkpoint_id in CROSS_SESSION_SYNC_CHECKPOINTS
],
"blocked_actions": BLOCKED_ACTIONS,
"summary": {
"reference_framework_count": len(REFERENCE_FRAMEWORKS),
"operating_role_count": len(OPERATING_ROLES),
"severity_lane_count": len(SEVERITY_LANES),
"workstream_count": len(WORKSTREAMS),
"p0_workstream_count": len(p0),
"p1_workstream_count": len(p1),
"p2_workstream_count": len(p2),
"alert_contract_field_count": len(ALERT_CONTRACT_FIELDS),
"automation_loop_stage_count": len(AUTOMATION_LOOP_STAGES),
"verification_stage_count": len(VERIFICATION_STAGES),
"no_false_green_rule_count": len(NO_FALSE_GREEN_RULES),
"cross_session_sync_checkpoint_count": len(CROSS_SESSION_SYNC_CHECKPOINTS),
"blocked_action_count": len(BLOCKED_ACTIONS),
"source_control_artifact_percent": 100,
"evidence_weighted_security_operating_system_percent": 56,
"soc_siem_framework_percent": 92,
"wazuh_manager_registry_acceptance_percent": 0,
"runtime_response_percent": 0,
"owner_response_received_count": 0,
"owner_response_accepted_count": 0,
"wazuh_registry_accepted_count": 0,
"kali_scope_accepted_count": 0,
"alert_receipt_accepted_count": 0,
"incident_case_accepted_count": 0,
"host_forensics_accepted_count": 0,
"runtime_gate_count": 0,
"action_button_count": 0,
},
"execution_boundaries": {
"runtime_execution_authorized": False,
"host_write_authorized": False,
"wazuh_active_response_authorized": False,
"kali_active_scan_authorized": False,
"kali_execute_authorized": False,
"nginx_reload_authorized": False,
"firewall_change_authorized": False,
"secret_value_collection_allowed": False,
"telegram_live_send_authorized": False,
"soar_action_authorized": False,
"auto_block_authorized": False,
"production_write_authorized": False,
"not_authorization": True,
},
}
def load_json(path: Path) -> dict[str, Any]:
return json.loads(path.read_text(encoding="utf-8"))
def assert_equal(label: str, actual: Any, expected: Any) -> None:
if actual != expected:
raise SystemExit(f"BLOCKED {label}: expected {expected!r}, got {actual!r}")
def assert_false(label: str, actual: Any) -> None:
assert_equal(label, actual, False)
def collect_string_values(value: Any) -> list[str]:
if isinstance(value, str):
return [value]
if isinstance(value, list):
values: list[str] = []
for item in value:
values.extend(collect_string_values(item))
return values
if isinstance(value, dict):
values = []
for item in value.values():
values.extend(collect_string_values(item))
return values
return []
def validate_no_forbidden_text(snapshot: dict[str, Any]) -> None:
for text in collect_string_values(snapshot):
for pattern in FORBIDDEN_TEXT_PATTERNS:
if pattern.search(text):
raise SystemExit("BLOCKED iwooos_security_operating_system: snapshot contains forbidden sensitive text")
def validate(root: Path) -> None:
snapshot = load_json(root / SNAPSHOT_PATH)
assert_equal("schema_version", snapshot.get("schema_version"), SCHEMA_VERSION)
assert_equal("status", snapshot.get("status"), "iwooos_security_operating_system_ready_no_runtime_action")
assert_equal("mode", snapshot.get("mode"), "repo_snapshot_guard_frontstage_only")
summary = snapshot.get("summary", {})
expected_counts = {
"reference_framework_count": 20,
"operating_role_count": 10,
"severity_lane_count": 5,
"workstream_count": 24,
"p0_workstream_count": 12,
"p1_workstream_count": 8,
"p2_workstream_count": 4,
"alert_contract_field_count": 9,
"automation_loop_stage_count": 8,
"verification_stage_count": 12,
"no_false_green_rule_count": 12,
"cross_session_sync_checkpoint_count": 7,
"blocked_action_count": 18,
"source_control_artifact_percent": 100,
"evidence_weighted_security_operating_system_percent": 56,
"soc_siem_framework_percent": 92,
"wazuh_manager_registry_acceptance_percent": 0,
"runtime_response_percent": 0,
"owner_response_received_count": 0,
"owner_response_accepted_count": 0,
"wazuh_registry_accepted_count": 0,
"kali_scope_accepted_count": 0,
"alert_receipt_accepted_count": 0,
"incident_case_accepted_count": 0,
"host_forensics_accepted_count": 0,
"runtime_gate_count": 0,
"action_button_count": 0,
}
for key, expected in expected_counts.items():
assert_equal(f"summary.{key}", summary.get(key), expected)
boundaries = snapshot.get("execution_boundaries", {})
for key, value in boundaries.items():
if key == "not_authorization":
assert_equal(f"execution_boundaries.{key}", value, True)
else:
assert_false(f"execution_boundaries.{key}", value)
validate_no_forbidden_text(snapshot)
def main() -> int:
parser = argparse.ArgumentParser(description="IwoooS 資安作戰系統")
parser.add_argument("--root", default=".", help="repo root")
parser.add_argument("--output", help="寫出 JSON snapshot")
parser.add_argument("--generated-at", help="固定報告時間,供 committed snapshot 使用")
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
root = Path(args.root).resolve()
generated_at = args.generated_at or datetime.now(TAIPEI).isoformat(timespec="seconds")
if args.output:
output = Path(args.output)
if not output.is_absolute():
output = root / output
snapshot = build_snapshot(root, generated_at)
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(json.dumps(snapshot, ensure_ascii=False, indent=2, sort_keys=True) + "\n", encoding="utf-8")
validate(root)
snapshot = load_json(root / SNAPSHOT_PATH)
if args.json:
print(json.dumps(snapshot, ensure_ascii=False, sort_keys=True))
return 0
summary = snapshot["summary"]
print(
"IWOOOS_SECURITY_OPERATING_SYSTEM_OK "
f"frameworks={summary['reference_framework_count']} "
f"workstreams={summary['workstream_count']} "
f"p0={summary['p0_workstream_count']} "
f"alert_contract={summary['alert_contract_field_count']} "
f"evidence_percent={summary['evidence_weighted_security_operating_system_percent']} "
f"runtime_gate={summary['runtime_gate_count']}"
)
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -131,6 +131,10 @@ def validate(root: Path) -> None:
str(root / "scripts" / "security" / "telegram-alert-readability-guard.py")
)
telegram_alert_readability_guard["validate"](root)
iwooos_security_operating_system = runpy.run_path(
str(root / "scripts" / "security" / "iwooos-security-operating-system.py")
)
iwooos_security_operating_system["validate"](root)
public_frontend_sensitive_surface = load_json(
security_dir / "public-frontend-sensitive-surface-guard.snapshot.json"
)