mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-14 03:15:16 +03:00
c21af3347e
- Add scripts/agent.py and references/api-reference.md to all remaining skills - Update all 648 LICENSE files: copyright now reads 'Mahipal' - Add implementing-security-monitoring-with-datadog (new skill with full anatomy) - All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
158 lines
6.9 KiB
Python
158 lines
6.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Agent for performing oil & gas sector cybersecurity assessment based on IEC 62443 and NIST frameworks."""
|
|
|
|
import json
|
|
import argparse
|
|
import csv
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
|
|
|
|
IEC62443_SECURITY_LEVELS = {
|
|
"SL1": "Protection against casual or coincidental violation",
|
|
"SL2": "Protection against intentional violation using simple means",
|
|
"SL3": "Protection against sophisticated attacks with moderate resources",
|
|
"SL4": "Protection against state-sponsored attacks with extensive resources",
|
|
}
|
|
|
|
OT_ASSET_CATEGORIES = {
|
|
"SCADA": {"criticality": "CRITICAL", "zone": "Level 2", "purdue": 2},
|
|
"DCS": {"criticality": "CRITICAL", "zone": "Level 1-2", "purdue": 2},
|
|
"PLC": {"criticality": "HIGH", "zone": "Level 1", "purdue": 1},
|
|
"RTU": {"criticality": "HIGH", "zone": "Level 1", "purdue": 1},
|
|
"HMI": {"criticality": "HIGH", "zone": "Level 2", "purdue": 2},
|
|
"EWS": {"criticality": "MEDIUM", "zone": "Level 2", "purdue": 2},
|
|
"Historian": {"criticality": "MEDIUM", "zone": "Level 3", "purdue": 3},
|
|
"SIS": {"criticality": "CRITICAL", "zone": "Level 0-1", "purdue": 1},
|
|
"Firewall_OT": {"criticality": "HIGH", "zone": "DMZ", "purdue": 3.5},
|
|
}
|
|
|
|
|
|
def assess_network_segmentation(asset_file):
|
|
"""Assess OT/IT network segmentation based on asset inventory."""
|
|
with open(asset_file, "r", encoding="utf-8", errors="replace") as f:
|
|
reader = csv.DictReader(f)
|
|
assets = list(reader)
|
|
zones = {}
|
|
findings = []
|
|
for asset in assets:
|
|
zone = asset.get("zone", asset.get("network_zone", "unknown"))
|
|
atype = asset.get("type", asset.get("asset_type", "unknown"))
|
|
zones.setdefault(zone, []).append(asset)
|
|
expected = OT_ASSET_CATEGORIES.get(atype, {})
|
|
if expected and expected.get("zone") and zone != expected["zone"]:
|
|
findings.append({
|
|
"asset": asset.get("name", asset.get("hostname", "")),
|
|
"type": atype, "current_zone": zone,
|
|
"expected_zone": expected["zone"],
|
|
"issue": "ZONE_MISMATCH",
|
|
})
|
|
dmz_exists = any("dmz" in z.lower() for z in zones.keys())
|
|
if not dmz_exists:
|
|
findings.append({"issue": "NO_DMZ", "severity": "CRITICAL", "recommendation": "Implement IT/OT DMZ"})
|
|
return {
|
|
"total_assets": len(assets),
|
|
"zones": {z: len(a) for z, a in zones.items()},
|
|
"zone_mismatches": len([f for f in findings if f.get("issue") == "ZONE_MISMATCH"]),
|
|
"dmz_present": dmz_exists,
|
|
"findings": findings[:20],
|
|
}
|
|
|
|
|
|
def assess_iec62443_compliance(assessment_csv):
|
|
"""Assess IEC 62443 compliance from questionnaire responses."""
|
|
with open(assessment_csv, "r", encoding="utf-8", errors="replace") as f:
|
|
reader = csv.DictReader(f)
|
|
rows = list(reader)
|
|
requirements = {}
|
|
for row in rows:
|
|
req_id = row.get("requirement", row.get("control", ""))
|
|
sl_achieved = int(row.get("sl_achieved", row.get("score", 0)))
|
|
sl_target = int(row.get("sl_target", row.get("target", 2)))
|
|
zone = row.get("zone", row.get("scope", ""))
|
|
requirements.setdefault(zone, []).append({
|
|
"requirement": req_id, "achieved": sl_achieved,
|
|
"target": sl_target, "gap": sl_target - sl_achieved,
|
|
"compliant": sl_achieved >= sl_target,
|
|
})
|
|
zone_scores = {}
|
|
for zone, reqs in requirements.items():
|
|
compliant = sum(1 for r in reqs if r["compliant"])
|
|
zone_scores[zone] = {
|
|
"total_requirements": len(reqs), "compliant": compliant,
|
|
"non_compliant": len(reqs) - compliant,
|
|
"compliance_pct": round(compliant / len(reqs) * 100, 1),
|
|
}
|
|
return {
|
|
"framework": "IEC 62443",
|
|
"zone_compliance": zone_scores,
|
|
"overall_compliance": round(sum(z["compliance_pct"] for z in zone_scores.values()) / max(len(zone_scores), 1), 1),
|
|
"critical_gaps": [r for reqs in requirements.values() for r in reqs if r["gap"] >= 2],
|
|
}
|
|
|
|
|
|
def assess_safety_systems(asset_file):
|
|
"""Assess Safety Instrumented System (SIS) security posture."""
|
|
with open(asset_file, "r", encoding="utf-8", errors="replace") as f:
|
|
reader = csv.DictReader(f)
|
|
assets = list(reader)
|
|
sis_assets = [a for a in assets if a.get("type", "").upper() in ("SIS", "ESD", "F&G", "HIPPS")]
|
|
findings = []
|
|
for asset in sis_assets:
|
|
if asset.get("network_connected", "").lower() in ("yes", "true", "1"):
|
|
findings.append({"asset": asset.get("name"), "issue": "SIS_NETWORK_CONNECTED", "severity": "CRITICAL"})
|
|
if asset.get("remote_access", "").lower() in ("yes", "true", "1"):
|
|
findings.append({"asset": asset.get("name"), "issue": "SIS_REMOTE_ACCESS", "severity": "CRITICAL"})
|
|
if asset.get("shared_controller", "").lower() in ("yes", "true", "1"):
|
|
findings.append({"asset": asset.get("name"), "issue": "SIS_SHARED_CONTROLLER", "severity": "HIGH"})
|
|
return {
|
|
"total_sis_assets": len(sis_assets),
|
|
"findings": findings,
|
|
"sis_isolated": len(sis_assets) - len(set(f["asset"] for f in findings)),
|
|
"recommendation": "SIS must be air-gapped from process control and IT networks per IEC 61511",
|
|
}
|
|
|
|
|
|
def generate_assessment_report(asset_file, assessment_csv=None):
|
|
"""Generate comprehensive oil & gas cybersecurity assessment report."""
|
|
report = {
|
|
"generated": datetime.utcnow().isoformat(),
|
|
"framework": "IEC 62443 / NIST CSF / API 1164",
|
|
"network_segmentation": assess_network_segmentation(asset_file),
|
|
"safety_systems": assess_safety_systems(asset_file),
|
|
}
|
|
if assessment_csv:
|
|
report["iec62443_compliance"] = assess_iec62443_compliance(assessment_csv)
|
|
return report
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Oil & Gas Cybersecurity Assessment Agent")
|
|
sub = parser.add_subparsers(dest="command")
|
|
n = sub.add_parser("network", help="Assess network segmentation")
|
|
n.add_argument("--assets", required=True, help="Asset inventory CSV")
|
|
c = sub.add_parser("compliance", help="IEC 62443 compliance check")
|
|
c.add_argument("--csv", required=True)
|
|
s = sub.add_parser("safety", help="SIS security assessment")
|
|
s.add_argument("--assets", required=True)
|
|
r = sub.add_parser("report", help="Full assessment report")
|
|
r.add_argument("--assets", required=True)
|
|
r.add_argument("--compliance-csv", help="IEC 62443 assessment CSV")
|
|
args = parser.parse_args()
|
|
if args.command == "network":
|
|
result = assess_network_segmentation(args.assets)
|
|
elif args.command == "compliance":
|
|
result = assess_iec62443_compliance(args.csv)
|
|
elif args.command == "safety":
|
|
result = assess_safety_systems(args.assets)
|
|
elif args.command == "report":
|
|
result = generate_assessment_report(args.assets, args.compliance_csv)
|
|
else:
|
|
parser.print_help()
|
|
return
|
|
print(json.dumps(result, indent=2, default=str))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|