以下为本文档的中文说明
securing-remote-access-to-ot-environment(保障 OT 环境远程访问安全)是一个专注于工业控制系统(ICS)和运营技术(OT)网络远程访问安全加固的高专业度技能。OT 环境涵盖电力能源、石油化工、水处理、交通运输和制造业等国家关键基础设施,其安全需求与传统的企业 IT 系统存在本质区别。使用场景包括:为工业设施设计和部署安全的远程运维访问方案、对工控网络的边界实施严格访问控制和流量监控、审计和评估现有 OT 远程访问架构的安全漏洞和改进空间。核心特点包括:深入阐释 OT 安全与 IT 安全的五个根本差异:可用性优先于机密性(系统停机比数据泄露后果更严重)、实时性和确定性通信要求(微秒级延迟影响生产质量)、专有的工控协议(Modbus/TCP、DNP3、PROFINET、OPC UA 等缺乏内置安全机制)、长生命周期设备(PLC/RTU 通常运行 10-20 年无法升级)和物理安全与环境安全的特殊考量;提供多种经过验证的远程访问安全架构方案,包括安全跳板机(Jump Box/Bastion Host)的堡垒机架构、专用加密 VPN 网关连接方案、遵循零信任原则的网络访问(ZTNA)架构;涵盖工控核心协议的安全加固技术措施,如 Modbus/TCP 的深度包检测(DPI)和功能码白名单;提供多因素认证(MFA/RSA SecurID)和基于角色的访问控制(RBAC)实施指南;提供遵从 IEC 62443 系列工业通信网络安全标准的审计检查清单。该技能对于工业控制系统安全工程师而言是不可或缺的参考资料。
Securing Remote Access to OT Environment
When to Use
- When implementing or upgrading remote access architecture for OT environments
- When onboarding vendors who require remote access to OT systems for support and maintenance
- When implementing CIP-005-7 R2 requirements for remote access management including MFA
- When replacing legacy direct VPN access to OT networks with a secure jump server architecture
- When responding to an incident involving unauthorized remote access to industrial control systems
Do not usefor securing IT-only remote access without OT components, for configuring VPN for corporate workers (see general VPN guides), or for physical access control to OT facilities.
Prerequisites
- DMZ infrastructure (Level 3.5) between corporate IT and OT networks
- Jump server/bastion host platform (CyberArk, BeyondTrust, or hardened Windows/Linux server)
- Multi-factor authentication solution (Duo, RSA SecurID, YubiKey, smart cards)
- Session recording capability for audit trail compliance
- Firewall rules permitting remote access only through the DMZ intermediate system
Workflow
Step 1: Design Secure Remote Access Architecture
Implement a defense-in-depth remote access architecture with an intermediate system in the DMZ that prevents any direct network connectivity between external users and OT systems.
# OT Remote Access Architecture# Key principle: NO direct connection from external networks to OT systemsarchitecture:external_access_point:location:"Internet-facing firewall"service:"VPN gateway (IKEv2/IPsec or SSL VPN)"authentication:"Certificate + MFA (CIP-005-7 R2.4)"controls:-"Source IP allowlisting for vendor access"-"Time-based access windows"-"Bandwidth rate limiting"dmz_intermediate_system:location:"Level 3.5 DMZ"platform:"CyberArk Privileged Access Security or hardened jump server"function:"Session broker - terminates external connection, initiates new internal connection"controls:-"All sessions terminate at jump server (no pass-through)"-"Session recording with keystroke logging"-"Clipboard and file transfer restrictions"-"Session timeout after 30 minutes inactivity"-"Concurrent session limits per user"ot_internal_access:location:"Level 3 / Level 2 OT network"method:"Jump server initiates RDP/SSH/VNC to OT systems"controls:-"Firewall allows only jump server IP to reach OT"-"Protocol restricted (RDP 3389, SSH 22, VNC 5900)"-"Destination-specific per user role"vendor_access:description:"Third-party vendor remote access"additional_controls:-"Vendor account disabled by default; enabled on request"-"Time-limited access windows (enable/disable per session)"-"OT operator must co-attend vendor sessions"-"Real-time session monitoring by OT security"-"No persistent credentials - one-time access tokens"# Network flow:# User -> VPN -> Firewall -> DMZ Jump Server -> Internal FW -> OT System# (Two separate authenticated connections; no direct routing)Step 2: Configure Jump Server with Privileged Access Management
Deploy and harden the jump server in the DMZ with session management, recording, and role-based access controls.
#!/usr/bin/env python3"""OT Remote Access Session Manager. Manages authorized remote access sessions to OT environments including session creation, monitoring, recording, and termination. Integrates with PAM solutions for credential vaulting. """importjsonimporthashlibimportsysfromdataclassesimportdataclass,field,asdictfromdatetimeimportdatetime,timedeltafromenumimportEnumclassSessionState(str,Enum):PENDING_APPROVAL="pending_approval"APPROVED="approved"ACTIVE="active"TERMINATED="terminated"EXPIRED="expired"DENIED="denied"classUserRole(str,Enum):OT_OPERATOR="ot_operator"OT_ENGINEER="ot_engineer"VENDOR="vendor"SECURITY_ ANALYST="security_analyst"@dataclassclassRemoteAccessSession:session_id:struser_id:struser_role:strsource_ip:strtarget_system:strtarget_ip:strprotocol:strpurpose:strstate:str=SessionState.PENDING_APPROVAL mfa_verified:bool=Falseapproved_by:str=""created_at:str=""started_at:str=""ended_at:str=""max_duration_minutes:int=120recording_path:str=""actions_logged:list=field(default_factory=list)classOTRemoteAccessManager:"""Manages remote access sessions to OT environment."""def__init__(self):self.sessions={}self.active_sessions={}self.access_policies={}self.audit_log=[]defdefine_access_policy(self,role,allowed_targets,protocols,max_duration):"""Define access policy for a user role."""self.access_policies[role]={"allowed_targets":allowed_targets,"allowed_protocols":protocols,"max_duration_minutes":max_duration,"requires_co_attendance":role==UserRole.VENDOR,"requires_approval":role==UserRole.VENDOR,}defrequest_session(self,user_id,user_role,source_ip,target_system,target_ip,protocol,purpose):"""Request a new remote access session."""# Generate unique session IDsession_id=hashlib.sha256(f"{user_id}{target_ip}{datetime.now().isoformat()}".encode()).hexdigest()[:16]# Check access policypolicy=self.access_policies.get(user_role)ifnotpolicy:returnNone,"No access policy defined for role"iftarget_systemnotinpolicy["allowed_targets"]:self._audit("ACCESS_DENIED",user_id,target_system,f"Target not in allowed list for role{user_role}")returnNone,f"Target{target_system}not authorized for role{user_role}"ifprotocolnotinpolicy["allowed_protocols"]:self._audit("ACCESS_DENIED",user_id,target_system,f"Protocol{protocol}not allowed for role{user_role}")returnNone,f"Protocol{protocol}not authorized"session=RemoteAccessSession(session_id=session_id,user_id=user_id,user_role=user_role,source_ip=source_ip,target_system=target_system,target_ip=target_ip,protocol=protocol,purpose=purpose,max_duration_minutes=policy["max_duration_minutes"],created_at=datetime.now().isoformat(),)# Vendor sessions require approvalifpolicy.get("requires_approval"):session.state=SessionState.PENDING_APPROVALelse:session.state=SessionState.APPROVED self.sessions[session_id]=session self._audit("SESSION_REQUESTED",user_id,target_system,purpose)returnsession_id,"Session created"defapprove_session(self,session_id,approver_id):"""Approve a pending vendor session."""session=self.sessions.get(session_id)ifnotsession:returnFalse,"Session not found"ifsession.state!=SessionState.PENDING_APPROVAL:returnFalse,"Session not in pending approval state"session.state=SessionState.APPROVED session.approved_by=approver_id self._audit("SESSION_APPROVED",approver_id,session.target_system,f"Approved session{session_id}for{session.user_id}")returnTrue,"Session approved"defactivate_session(self,session_id,mfa_token):"""Activate an approved session after MFA verification."""session=self.sessions.get(session_id)ifnotsessionorsession.state!=SessionState.APPROVED:returnFalse,"Session not approved"# Verify MFA (simplified - real implementation calls MFA provider)session.m fa_verified=Truesession.state=SessionState.ACTIVE session.started_at=datetime.now().isoformat()session.recording_path=f"/recordings/{session_id}_{datetime.now().strftime('%Y%m%d')}.mp4"self.active_sessions[session_id]=session self._audit("SESSION_ACTIVATED",session.user_id,session.target_system,f"MFA verified, recording to{session.recording_path}")returnTrue,"Session active"defterminate_session(self,session_id,reason="manual"):"""Terminate an active session."""session=self.active_sessions.pop(session_id,None)ifnotsession:session=self.sessions.get(session_id)ifnotsession:returnFalsesession.state=SessionState.TERMINATED session.ended_at=datetime.now().isoformat()self._audit("SESSION_TERMINATED",session.user_id,session.target_system,reason)returnTruedefcheck_expired_sessions(self):"""Terminate sessions that have exceeded their maximum duration."""now=datetime.now()expired=[]forsid,sessioninlist(self.active_sessions.items()):started=datetime.fromisoformat(session.started_at)if(now-started).total_seconds()>session.max_duration_minutes*60:self.terminate_session(sid,"maximum_duration_exceeded")expired.append(sid)returnexpireddef_audit(self,event_type,user_id,target,detail):"""Write to audit log."""self.audit_log.append({"timestamp":datetime.now().isoformat(),"event":event_type,"user":user_id,"target":target,"detail":detail,})defgenerate_report(self):"""Generate remote access session report."""report=[]report.append("="*70)report.append("OT REMOTE ACCESS SESSION REPORT")report.append(f"Date:{datetime.now().isoformat()}")report.append("="*70)# Session summarytotal=len(self.sessions)active=sum(1forsinself.sessions.values()ifs.state==SessionState.ACTIVE)report.append(f"\ Total Sessions:{total}")report.append(f"Active Sessions:{active}")# Active sessions detailifself.active_sessions:report.append("\ ACTIVE SESSIONS:")forsid,sinself.active_sessions.items():report.append(f" [{sid[:8]}]{s.user_id}({s.user_role})")report.append(f" Target:{s.target_system}({s.target_ip})")report.append(f" Started:{s.started_at}")report.append(f" MFA:{'Verified'ifs.mfa_verifiedelse'NOT VERIFIED'}")return"\ ".join(report)if__name__=="__main__":manager=OTRemoteAccessManager()# Define policiesmanager.define_access_policy(UserRole.OT_ENGINEER,["HMI-01","HMI-02","EWS-01","HISTORIAN-01"],["RDP","SSH"],max_duration=240,)manager.define_access_policy(UserRole.VENDOR,["DCS-EWS-01"],["RDP"],max_duration=120,)# Request vendor sessionsid,msg=manager.request_session("vendor_honeywell_01",UserRole.VENDOR,"203.0.113.50","DCS-EWS-01","10.30.1.20","RDP","DCS firmware update per change request CR-2026-0045")print(f"Session request:{msg}({sid})")ifsid:manager.approve_session(sid,"ot_manager_01")manager.activate_session(sid,"123456")print(manager.generate_report())Key Concepts
| Term | Definition |
|---|---|
| Intermediate System | System in the DMZ that terminates external connections and brokers new connections to OT, preventing direct network access per CIP-005 |
| Jump Server | Hardened bastion host in the DMZ used for remote access sessions to OT systems with session recording and access controls |
| Session Recording | Capture of al |
| l remote access session activity (screen, keystrokes, commands) for security audit and incident investigation | |
| Privileged Access Management (PAM) | System for vaulting credentials, controlling access, and auditing privileged sessions to critical OT systems |
| Co-Attendance | Requirement for an OT operator to monitor vendor remote access sessions in real time |
| Time-Limited Access | Vendor accounts enabled only for specific maintenance windows and automatically disabled after the window closes |
Tools & Systems
- CyberArk Privileged Access Security: Enterprise PAM with session management, credential vaulting, and recording for OT remote access
- BeyondTrust Privileged Remote Access: Purpose-built remote access solution with session recording and granular access policies
- Claroty Secure Remote Access (SRA): OT-specific remote access solution with protocol-aware session controls
- Duo Security: MFA provider supporting push notifications, hardware tokens, and biometrics for OT access verification
Output Format
OT Remote Access Security Report =================================== Active Sessions: [N] Pending Approval: [N] Sessions Today: [N] MFA COMPLIANCE: All sessions MFA verified: [Yes/No] Sessions without MFA: [N] VENDOR ACCESS: Active vendor sessions: [N] Co-attended: [N] Recorded: [N]