Zero Trust Architecture & mTLS
The core principle of Zero Trust is “Never Trust, Always Verify.” It abandons the traditional “castle and moat” model—where the internal network is trusted by default and the external network is untrusted by default—instead assuming that any network (internal or external) is untrusted, and every access request must undergo strict identity authentication, device health verification, and permission authorization.
EnerOS has fully implemented Zero Trust architecture since v0.43, serving as the common technical foundation for IEC 62443, NERC CIP, and MLPS 2.0 (Multi-Level Protection Scheme). Zero Trust is not only EnerOS’s security implementation approach but also the core defense line for industrial control and power systems against APT, ransomware, supply chain attacks, and other advanced threats.
NIST SP 800-207
SP 800-207 “Zero Trust Architecture” published by the National Institute of Standards and Technology (NIST) is the authoritative reference framework for Zero Trust. It defines the three core principles, logical components, and deployment models of Zero Trust.
Three Core Principles
| Principle | Meaning | EnerOS Implementation |
|---|---|---|
| Verify explicitly | All access must be explicitly authenticated and authorized | mTLS + SPIFFE + continuous evaluation |
| Least privilege | Grant only the minimum privileges needed to complete tasks | RBAC + ABAC + default deny |
| Assume breach | Assume the system has been breached, limit blast radius | Network segmentation + micro-segmentation + WORM |
Logical Components
NIST 800-207 defines two core logical components of the Zero Trust architecture:
| Component | Responsibility | EnerOS Implementation |
|---|---|---|
| Policy Decision Point (PDP) | Evaluates access requests and makes decisions | eneros-trust PolicyEngine |
| Policy Enforcement Point (PEP) | Intercepts requests in front of resources and enforces decisions | eneros-gateway Sidecar |
Deployment Models
EnerOS supports three Zero Trust deployment models:
| Model | Description | Applicable Scenario |
|---|---|---|
| Device agent | Each device runs an agent to communicate with PDP | End-user devices |
| Resource agent | Proxy in front of resources intercepts requests | Server-side APIs |
| Hybrid agent | Device + resource dual-layer proxy | Critical control systems |
Five Pillars of Zero Trust
Referencing the CISA Zero Trust Maturity Model, EnerOS implements five pillars:
| Pillar | Practice | EnerOS Implementation |
|---|---|---|
| Identity | Each service has a verifiable identity | Internal CA + SPIFFE ID |
| Device | Device health measurement | Boot measurement + image signing |
| Network | Network segmentation encryption | mTLS + namespace isolation |
| Application | Least privilege between applications | RBAC + ABAC policies |
| Data | Data classification and encryption | Field-level encryption + WORM |
Identity Pillar
SPIFFE Identity Framework
Every EnerOS service has a unique SPIFFE ID as its cryptographic identity:
use eneros_trust::spiffe::{SpiffeId, TrustDomain};
let trust_domain = TrustDomain::new("eneros.internal")?;
let agent_id = SpiffeId::new(&trust_domain, "agent/dispatch-agent-7");
let gateway_id = SpiffeId::new(&trust_domain, "gateway/eneros-gateway-01");
// SVID (SPIFFE Verifiable Identity Document)
let svid = agent_id.issue_x509_svid(&ca, Duration::from_days(90))?;
Identity Lifecycle
| Phase | Operation | Automation |
|---|---|---|
| Registration | Service registers identity with SPIRE | Automatic |
| Issuance | CA issues X.509 SVID | Automatic (90 days) |
| Rotation | Auto-rotate before certificate expiry | Automatic (30 days prior) |
| Revocation | Revoke identity when service goes offline | Automatic |
| Audit | Full audit of identity operations | Automatic + WORM |
Device Pillar
Boot Measurement
[device_attestation]
enabled = true
tpm_required = true # Enforce TPM measurement
secure_boot = true # Enforce secure boot
measured_boot = true # Measured boot
[device_attestation.pcrs]
# Platform Configuration Register expected values
pcr0 = "sha256:abc123..." # Boot code
pcr7 = "sha256:def456..." # Secure boot policy
pcr9 = "sha256:789abc..." # Image measurement
use eneros_trust::attestation::{TpmAttestor, PcrMeasurement};
let attestor = TpmAttestor::new();
let measurement = attestor.measure().await?;
if !measurement.verify(&expected_pcrs) {
return Err("Device health measurement failed, refusing to connect".into());
}
println!("Device health: passed");
println!("PCR0 (boot code): {}", measurement.pcr0);
println!("PCR7 (secure boot): {}", measurement.pcr7);
Network Pillar
mTLS Enforcement Policy
All internal RPC channels deny plaintext by default, with certificates auto-rotating 30 days before expiry:
use eneros_trust::tls::{TlsConfig, TlsVersion, CipherSuite};
let tls = TlsConfig::mutual()
.min_version(TlsVersion::TLS_1_3)
.cipher_suites(CipherSuite::post_quantum())
.client_ca("/etc/eneros/ca.crt")
.server_ca("/etc/eneros/ca.crt")
.spiffe_trust_domain("eneros.internal")
.verify_subject_alt_name(true) // Verify SAN
.verify_tenant_id(true) // Verify tenant_id
.cert_rotation_days(90)
.build()?;
server.listen(addr, tls).await?;
During handshake, the certificate SAN and tenant_id are verified; mismatches are rejected.
Network Segmentation
[network_segmentation]
enabled = true
default_deny = true # Default deny
namespace_isolation = true # Namespace isolation
[[network_segmentation.zones]]
name = "control-plane"
namespace = "eneros-control"
allowed_egress = ["data-plane"]
[[network_segmentation.zones]]
name = "data-plane"
namespace = "eneros-data"
allowed_egress = ["storage"]
[[network_segmentation.zones]]
name = "management"
namespace = "eneros-mgmt"
allowed_egress = ["control-plane", "data-plane"]
Application Pillar
RBAC + ABAC Policy Engine
use eneros_trust::policy::{PolicyEngine, Subject, Action, Resource, Context};
let engine = PolicyEngine::new();
let request = AccessRequest::builder()
.subject(Subject::user("operator-7").role("dispatcher"))
.action(Action::Write)
.resource(Resource::device("breaker-123"))
.context(Context::new()
.set("time", "business-hours")
.set("location", "control-room")
.set("mfa_verified", true))
.build()?;
let decision = engine.evaluate(&request).await?;
match decision.action {
DecisionAction::Allow => println!("Access allowed"),
DecisionAction::Deny => println!("Access denied: {}", decision.reason),
DecisionAction::RequireApproval => println!("Approval required: {}", decision.approver),
}
Policy Example
# policies/dispatcher.yaml
apiVersion: eneros.io/v1
kind: Policy
metadata:
name: dispatcher-breaker-control
spec:
subject:
role: dispatcher
action: ["read", "write"]
resource:
type: device
category: breaker
effect: allow
conditions:
- time: business-hours
- mfa_verified: true
- location: control-room
require_sbo: true # Two-factor operation
audit: true
Data Pillar
Data Classification and Encryption
[data_protection]
classification = true
field_encryption = "AES-256-GCM"
worm_audit = true
key_management = "kms"
[[data_protection.classes]]
name = "public"
encryption = false
retention_days = -1 # Permanent
[[data_protection.classes]]
name = "internal"
encryption = true
retention_days = 2555
[[data_protection.classes]]
name = "confidential"
encryption = true
access_log = true
retention_days = 2555
[[data_protection.classes]]
name = "restricted"
encryption = true
access_log = true
worm_storage = true
sbo_required = true
retention_days = 2555
Continuous Verification
The “continuous” characteristic of Zero Trust means verification is not one-time but spans the entire session:
Session Risk Assessment
use eneros_trust::risk::{RiskEngine, RiskScore};
let engine = RiskEngine::new();
let risk = engine.evaluate_session(&session).await?;
match risk.score {
s if s < 30 => println!("Low risk, continue session"),
s if s < 70 => {
println!("Medium risk, require re-authentication");
session.require_reauthentication().await?;
}
s if s >= 70 => {
println!("High risk, terminate session immediately");
session.terminate().await?;
notify_security_team(&session).await?;
}
}
Risk Signals
| Signal Category | Example | Risk Weight |
|---|---|---|
| Geographic anomaly | Login from different location | 30 |
| Time anomaly | Late-night operation | 20 |
| Device anomaly | New device | 25 |
| Behavior anomaly | Large data download | 40 |
| Rate anomaly | High-frequency requests | 35 |
| Protocol anomaly | Abnormal protocol | 50 |
mTLS Configuration Example
Complete Zero Trust Configuration in eneros.toml
[compliance]
standard = "zero-trust"
framework = "nist-800-207"
enforce = true
[zero_trust]
enabled = true
default_deny = true # Default deny
continuous_verification = true # Continuous verification
risk_based_access = true # Risk-based access
# Identity
[zero_trust.identity]
spiffe_enabled = true
trust_domain = "eneros.internal"
ca_endpoint = "https://spire.eneros.internal:8081"
svid_rotation_days = 90
auto_rotate_days = 30 # Auto-rotate 30 days prior
# Device
[zero_trust.device]
attestation_required = true
tpm_required = true
secure_boot = true
measured_boot = true
health_check_interval_minutes = 60
# Network
[zero_trust.network]
mtls_required = true
allow_plaintext = false
tls_min_version = "TLS_1_3"
cipher_suites = ["post-quantum"]
namespace_isolation = true
default_deny = true
# Application
[zero_trust.application]
rbac_enabled = true
abac_enabled = true
sbo_required_for_critical = true
policy_engine = "eneros-trust"
# Data
[zero_trust.data]
classification = true
field_encryption = "AES-256-GCM"
worm_audit = true
key_management = "kms"
# Continuous verification
[zero_trust.continuous]
risk_engine_enabled = true
session_timeout_minutes = 60
reauth_threshold_score = 70
terminate_threshold_score = 90
check_interval_seconds = 60
# IDS
[zero_trust.ids]
enabled = true
signatures = ["lateral-movement", "command-storm", "modbus-anomaly"]
update_frequency_hours = 24
alert_webhook = "https://soc.eneros.internal/alerts"
Rust Code: mTLS Server
use eneros_trust::tls::{TlsConfig, TlsVersion, CipherSuite};
use eneros_gateway::Server;
let tls = TlsConfig::mutual()
.min_version(TlsVersion::TLS_1_3)
.cipher_suites(CipherSuite::post_quantum())
.client_ca("/etc/eneros/ca.crt")
.server_cert("/etc/eneros/server.crt")
.server_key("/etc/eneros/server.key")
.spiffe_trust_domain("eneros.internal")
.verify_subject_alt_name(true)
.verify_tenant_id(true)
.build()?;
let server = Server::new()
.listen("0.0.0.0:9090", tls)
.policy_engine(policy_engine)
.audit_chain(audit_chain)
.build()?;
server.start().await?;
Rust Code: Client
use eneros_trust::tls::{TlsConfig, ClientIdentity};
let identity = ClientIdentity::from_spiffe_svid()?;
let tls = TlsConfig::mutual()
.min_version(TlsVersion::TLS_1_3)
.client_identity(identity)
.server_ca("/etc/eneros/ca.crt")
.spiffe_trust_domain("eneros.internal")
.build()?;
let client = reqwest::Client::builder()
.use_preconfigured_tls(tls)
.build()?;
let response = client.get("https://dispatch-agent.eneros.internal/api/v1/dispatch")
.header("X-Tenant-Id", "tenant-7")
.send().await?;
select-before-operate
For critical operations, Zero Trust requires additional two-factor control:
use eneros_trust::sbo::{SboSession, SboConfirm};
let mut sbo = SboSession::new("breaker-123")
.operation("open")
.actor("dispatch-agent-7")
.ttl_seconds(30)
.require_totp(true)
.require_approver(true);
sbo.select().await?;
let confirm = SboConfirm::builder()
.totp_code("123456")
.approver_id("operator-7")
.build();
sbo.confirm(confirm).await?;
sbo.execute().await?;
Compliance Checklist
Confirm each item before deployment:
- All inter-service communication has mTLS enabled, with no plaintext ports
- Internal CA offline-issues root certificates, work certificates auto-rotate (90 days)
- Certificate SAN binds
tenant_idandspiffe_id - Default deny policy, explicit allow to pass
- Critical operations have select-before-operate enabled
- Audit chain HMAC verification passes, WORM writes normally
- IDS covers lateral movement, command storm, Modbus anomaly, and other patterns
- Keys are managed by KMS / HSM, plaintext key files disabled
- Device boot measurement (TPM) enabled and verification passes
- Secure Boot enabled
- SPIFFE identity framework deployed and SVIDs auto-rotate
- Network segmentation policies effective, namespace isolation
- RBAC + ABAC policy engine online
- Continuous verification mechanism running, session risk assessed in real-time
- Policy Decision Point (PDP) and Policy Enforcement Point (PEP) decoupled deployment
- IDS signature database updated regularly (within 24 hours)
- Critical operations use two-factor authentication (TOTP or hardware tokens)
- Data classification and field encryption cover all sensitive data
Compliance Mapping
Zero Trust is a common technical requirement across multiple standards:
| Standard | Article | Zero Trust Mapping |
|---|---|---|
| IEC 62443-4-2 | CR 1.1 / 2.1 | mTLS + identity authentication |
| NERC CIP-005 | R1 | Electronic security perimeter |
| NERC CIP-007 | R4 / R6 | Port management + logging |
| MLPS 2.0 Level 3 | Communication encryption + access control | mTLS + RBAC |
| GDPR | Art. 32 | Data encryption + access control |
| PIPL | Article 51 | Security protection measures |
| CCPA | § 1798.130 | Reasonable security measures |