mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-07-20 22:40:58 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -0,0 +1,357 @@
|
||||
---
|
||||
name: implementing-conduit-security-for-ot-remote-access
|
||||
description: >
|
||||
Implement secure conduit architecture for OT remote access following IEC 62443
|
||||
zones and conduits model, deploying jump servers, MFA-enabled gateways, session
|
||||
recording, and approval-based workflows to control vendor and engineer access
|
||||
to industrial control systems without exposing OT networks directly.
|
||||
domain: cybersecurity
|
||||
subdomain: ot-ics-security
|
||||
tags: [ot-security, ics, remote-access, iec62443, jump-server, zero-trust, conduit, mfa]
|
||||
version: "1.0"
|
||||
author: mahipal
|
||||
license: MIT
|
||||
---
|
||||
|
||||
# Implementing Conduit Security for OT Remote Access
|
||||
|
||||
## When to Use
|
||||
|
||||
- When replacing direct VPN connections from IT or vendors into OT control networks
|
||||
- When implementing IEC 62443-compliant conduit architecture for remote access paths
|
||||
- When deploying secure remote access for third-party vendor maintenance of ICS equipment
|
||||
- When building approval-based access workflows for privileged OT system access
|
||||
- When remediating audit findings about uncontrolled remote access to SCADA systems
|
||||
|
||||
**Do not use** for designing the overall Purdue Model segmentation (see implementing-purdue-model-network-segmentation), for deploying IT-only remote access solutions, or for configuring local console access to PLCs.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- IT/OT DMZ (Level 3.5) deployed with dual-firewall architecture
|
||||
- Jump server or privileged access management (PAM) platform (CyberArk, BeyondTrust)
|
||||
- Multi-factor authentication (MFA) infrastructure for OT remote access users
|
||||
- Session recording capability for compliance and forensic purposes
|
||||
- Approval workflow system (ServiceNow, ticketing) for access requests
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Design Conduit Architecture for Remote Access
|
||||
|
||||
```yaml
|
||||
# IEC 62443 Conduit Security Architecture for OT Remote Access
|
||||
# All remote access terminates in DMZ - never passes through to OT directly
|
||||
|
||||
conduit_architecture:
|
||||
remote_access_conduit:
|
||||
conduit_id: "RA-001"
|
||||
source_zone: "Enterprise IT (Level 4)"
|
||||
destination_zone: "OT DMZ (Level 3.5)"
|
||||
security_level_target: "SL3"
|
||||
|
||||
components:
|
||||
external_gateway:
|
||||
type: "VPN Concentrator"
|
||||
location: "Enterprise DMZ"
|
||||
ip: "10.200.1.10"
|
||||
protocols: ["IPsec", "SSL-VPN"]
|
||||
authentication: "MFA required (certificate + OTP)"
|
||||
|
||||
dmz_jump_server:
|
||||
type: "Privileged Access Workstation"
|
||||
location: "OT DMZ (Level 3.5)"
|
||||
ip: "10.10.150.20"
|
||||
os: "Windows Server 2022 (hardened)"
|
||||
controls:
|
||||
- "Local admin accounts disabled"
|
||||
- "USB ports disabled"
|
||||
- "Clipboard transfer disabled by default"
|
||||
- "Session recording enabled (all keystrokes and screen)"
|
||||
- "Maximum session duration: 4 hours"
|
||||
- "Automatic logoff after 15 minutes idle"
|
||||
- "Application whitelisting enforced"
|
||||
|
||||
ot_access_gateway:
|
||||
type: "Industrial Remote Access Gateway"
|
||||
location: "OT DMZ / Level 3 boundary"
|
||||
ip: "10.10.150.25"
|
||||
controls:
|
||||
- "Only pre-approved destination IPs reachable"
|
||||
- "Protocol-level filtering (RDP, SSH, VNC only)"
|
||||
- "Time-limited sessions with automatic expiry"
|
||||
- "Approval-based access (plant manager must authorize)"
|
||||
|
||||
data_flow:
|
||||
- step: 1
|
||||
description: "User authenticates via enterprise VPN with MFA"
|
||||
source: "Remote user"
|
||||
destination: "VPN concentrator"
|
||||
protocol: "IPsec/SSL-VPN"
|
||||
- step: 2
|
||||
description: "User connects to jump server in OT DMZ"
|
||||
source: "VPN tunnel"
|
||||
destination: "DMZ jump server"
|
||||
protocol: "RDP with NLA"
|
||||
- step: 3
|
||||
description: "From jump server, user accesses specific OT system"
|
||||
source: "DMZ jump server"
|
||||
destination: "Approved OT target"
|
||||
protocol: "RDP/SSH/VNC"
|
||||
condition: "Only after manager approval and within time window"
|
||||
|
||||
prohibited_flows:
|
||||
- "Direct VPN tunnel from external to Level 1/2 OT devices"
|
||||
- "Split tunneling allowing internet access during OT session"
|
||||
- "File transfer from jump server to OT without scanning"
|
||||
- "Persistent VPN connections (auto-reconnect disabled)"
|
||||
|
||||
vendor_access_conduit:
|
||||
conduit_id: "VA-001"
|
||||
source_zone: "Vendor External Network"
|
||||
destination_zone: "OT DMZ (Level 3.5)"
|
||||
security_level_target: "SL3"
|
||||
|
||||
workflow:
|
||||
request:
|
||||
- "Vendor submits access request via portal (24h advance)"
|
||||
- "Request includes: purpose, target systems, duration, personnel"
|
||||
- "Plant operations manager reviews and approves/rejects"
|
||||
- "Time-limited credentials generated upon approval"
|
||||
session:
|
||||
- "Vendor connects via dedicated vendor VPN gateway"
|
||||
- "MFA authentication (vendor receives OTP via SMS/app)"
|
||||
- "Session lands on vendor-specific jump server (isolated from internal jump)"
|
||||
- "All actions recorded (video + keystroke logging)"
|
||||
- "OT engineer monitors vendor session in real-time"
|
||||
termination:
|
||||
- "Session auto-terminates at approved end time"
|
||||
- "Credentials automatically revoked"
|
||||
- "Session recording archived for 90 days"
|
||||
- "Access log forwarded to SIEM"
|
||||
```
|
||||
|
||||
### Step 2: Implement Access Control and Monitoring
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""OT Remote Access Conduit Manager.
|
||||
|
||||
Manages approval-based remote access to OT systems through
|
||||
secure conduit architecture with session recording, MFA
|
||||
enforcement, and time-limited access windows.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Dict, List, Optional
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class AccessRequestStatus(Enum):
|
||||
PENDING = "pending"
|
||||
APPROVED = "approved"
|
||||
REJECTED = "rejected"
|
||||
ACTIVE = "active"
|
||||
EXPIRED = "expired"
|
||||
REVOKED = "revoked"
|
||||
|
||||
|
||||
class RemoteAccessRequest:
|
||||
"""Represents an OT remote access request."""
|
||||
|
||||
def __init__(self, requestor: str, requestor_type: str, purpose: str,
|
||||
target_systems: List[str], duration_hours: int,
|
||||
requested_start: str):
|
||||
self.id = f"OT-RA-{datetime.now().strftime('%Y%m%d-%H%M%S')}"
|
||||
self.requestor = requestor
|
||||
self.requestor_type = requestor_type # "internal_engineer" or "vendor"
|
||||
self.purpose = purpose
|
||||
self.target_systems = target_systems
|
||||
self.duration_hours = duration_hours
|
||||
self.requested_start = requested_start
|
||||
self.status = AccessRequestStatus.PENDING
|
||||
self.created = datetime.now().isoformat()
|
||||
self.approved_by = None
|
||||
self.session_id = None
|
||||
self.audit_trail = []
|
||||
|
||||
def approve(self, approver: str, conditions: str = ""):
|
||||
"""Approve the access request."""
|
||||
self.status = AccessRequestStatus.APPROVED
|
||||
self.approved_by = approver
|
||||
self.audit_trail.append({
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"action": "APPROVED",
|
||||
"actor": approver,
|
||||
"conditions": conditions,
|
||||
})
|
||||
|
||||
def reject(self, rejector: str, reason: str):
|
||||
"""Reject the access request."""
|
||||
self.status = AccessRequestStatus.REJECTED
|
||||
self.audit_trail.append({
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"action": "REJECTED",
|
||||
"actor": rejector,
|
||||
"reason": reason,
|
||||
})
|
||||
|
||||
|
||||
class OTConduitManager:
|
||||
"""Manages OT remote access conduit security."""
|
||||
|
||||
def __init__(self):
|
||||
self.access_requests: Dict[str, RemoteAccessRequest] = {}
|
||||
self.active_sessions: Dict[str, dict] = {}
|
||||
self.policy = self._load_policy()
|
||||
|
||||
def _load_policy(self) -> dict:
|
||||
"""Load remote access policy."""
|
||||
return {
|
||||
"max_session_hours": 4,
|
||||
"idle_timeout_minutes": 15,
|
||||
"mfa_required": True,
|
||||
"session_recording": True,
|
||||
"clipboard_transfer": False,
|
||||
"file_transfer": "scan_required",
|
||||
"advance_notice_hours": 24,
|
||||
"vendor_escort_required": True,
|
||||
"prohibited_targets": ["SIS-*", "SAFETY-*"],
|
||||
"allowed_protocols": ["RDP", "SSH", "VNC"],
|
||||
"blocked_protocols": ["Telnet", "FTP", "SMB"],
|
||||
}
|
||||
|
||||
def submit_request(self, request: RemoteAccessRequest) -> str:
|
||||
"""Submit a new remote access request."""
|
||||
# Validate against policy
|
||||
violations = []
|
||||
|
||||
if request.duration_hours > self.policy["max_session_hours"]:
|
||||
violations.append(
|
||||
f"Duration {request.duration_hours}h exceeds maximum {self.policy['max_session_hours']}h"
|
||||
)
|
||||
|
||||
for target in request.target_systems:
|
||||
for prohibited in self.policy["prohibited_targets"]:
|
||||
pattern = prohibited.replace("*", "")
|
||||
if target.startswith(pattern):
|
||||
violations.append(f"Target {target} is in prohibited list (safety systems)")
|
||||
|
||||
if violations:
|
||||
print(f"[!] Policy violations found:")
|
||||
for v in violations:
|
||||
print(f" - {v}")
|
||||
return ""
|
||||
|
||||
self.access_requests[request.id] = request
|
||||
print(f"[+] Access request {request.id} submitted for approval")
|
||||
return request.id
|
||||
|
||||
def list_pending_requests(self):
|
||||
"""List all pending access requests for approval."""
|
||||
pending = [r for r in self.access_requests.values()
|
||||
if r.status == AccessRequestStatus.PENDING]
|
||||
|
||||
print(f"\n{'='*65}")
|
||||
print("PENDING OT REMOTE ACCESS REQUESTS")
|
||||
print(f"{'='*65}")
|
||||
|
||||
if not pending:
|
||||
print(" No pending requests")
|
||||
return
|
||||
|
||||
for req in pending:
|
||||
print(f"\n Request: {req.id}")
|
||||
print(f" Requestor: {req.requestor} ({req.requestor_type})")
|
||||
print(f" Purpose: {req.purpose}")
|
||||
print(f" Targets: {', '.join(req.target_systems)}")
|
||||
print(f" Duration: {req.duration_hours} hours")
|
||||
print(f" Start: {req.requested_start}")
|
||||
print(f" Submitted: {req.created}")
|
||||
|
||||
def generate_audit_report(self):
|
||||
"""Generate audit report of all remote access activity."""
|
||||
print(f"\n{'='*65}")
|
||||
print("OT REMOTE ACCESS AUDIT REPORT")
|
||||
print(f"{'='*65}")
|
||||
print(f"Report Date: {datetime.now().isoformat()}")
|
||||
print(f"Total Requests: {len(self.access_requests)}")
|
||||
|
||||
status_counts = {}
|
||||
for req in self.access_requests.values():
|
||||
status = req.status.value
|
||||
status_counts[status] = status_counts.get(status, 0) + 1
|
||||
|
||||
print(f"\nRequest Status:")
|
||||
for status, count in status_counts.items():
|
||||
print(f" {status}: {count}")
|
||||
|
||||
print(f"\nDetailed Audit Trail:")
|
||||
for req in self.access_requests.values():
|
||||
print(f"\n {req.id} - {req.requestor} ({req.requestor_type})")
|
||||
print(f" Status: {req.status.value}")
|
||||
print(f" Targets: {', '.join(req.target_systems)}")
|
||||
for entry in req.audit_trail:
|
||||
print(f" [{entry['timestamp']}] {entry['action']} by {entry['actor']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
manager = OTConduitManager()
|
||||
|
||||
# Vendor access request
|
||||
vendor_req = RemoteAccessRequest(
|
||||
requestor="John Smith - Siemens Field Service",
|
||||
requestor_type="vendor",
|
||||
purpose="Annual PLC firmware update for S7-1500 controllers",
|
||||
target_systems=["PLC-REACTOR-01", "PLC-REACTOR-02"],
|
||||
duration_hours=3,
|
||||
requested_start="2025-03-15T08:00:00",
|
||||
)
|
||||
|
||||
req_id = manager.submit_request(vendor_req)
|
||||
if req_id:
|
||||
manager.list_pending_requests()
|
||||
|
||||
# Simulate approval
|
||||
manager.access_requests[req_id].approve(
|
||||
approver="Plant Manager - Jane Doe",
|
||||
conditions="OT engineer must shadow the vendor session",
|
||||
)
|
||||
|
||||
manager.generate_audit_report()
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
| Term | Definition |
|
||||
|------|------------|
|
||||
| Conduit | IEC 62443 controlled communication path between security zones with defined security policies |
|
||||
| Jump Server | Hardened intermediary server in the DMZ through which all remote OT access must transit |
|
||||
| Session Recording | Capture of all screen activity, keystrokes, and commands during a remote access session for audit |
|
||||
| Approval-Based Access | Workflow requiring plant operations manager authorization before remote access credentials are activated |
|
||||
| Vendor Escort | Practice of having an internal OT engineer monitor vendor remote sessions in real time |
|
||||
| Break-Glass Access | Emergency access procedure bypassing normal approval workflow for critical situations |
|
||||
|
||||
## Output Format
|
||||
|
||||
```
|
||||
OT REMOTE ACCESS CONDUIT REPORT
|
||||
==================================
|
||||
Date: YYYY-MM-DD
|
||||
|
||||
CONDUIT STATUS:
|
||||
Internal Access Conduit: [Active/Inactive]
|
||||
Vendor Access Conduit: [Active/Inactive]
|
||||
|
||||
ACCESS REQUESTS (Last 30 Days):
|
||||
Submitted: [count]
|
||||
Approved: [count]
|
||||
Rejected: [count]
|
||||
Average Session Duration: [hours]
|
||||
|
||||
POLICY COMPLIANCE:
|
||||
MFA Enforcement: [100%]
|
||||
Session Recording: [100%]
|
||||
Time-Limited Sessions: [compliance %]
|
||||
Prohibited Target Attempts: [count blocked]
|
||||
```
|
||||
Reference in New Issue
Block a user