Files
awoooi/scripts/security/iwooos-security-operating-system.py
ogt a22a0f612d
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
feat(iwooos): add security operating system guard
2026-06-25 15:55:20 +08:00

428 lines
20 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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())