Skip to main content

Zero Trust Architecture & mTLS

Compliance & Security

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

PrincipleMeaningEnerOS Implementation
Verify explicitlyAll access must be explicitly authenticated and authorizedmTLS + SPIFFE + continuous evaluation
Least privilegeGrant only the minimum privileges needed to complete tasksRBAC + ABAC + default deny
Assume breachAssume the system has been breached, limit blast radiusNetwork segmentation + micro-segmentation + WORM

Logical Components

NIST 800-207 defines two core logical components of the Zero Trust architecture:

ComponentResponsibilityEnerOS Implementation
Policy Decision Point (PDP)Evaluates access requests and makes decisionseneros-trust PolicyEngine
Policy Enforcement Point (PEP)Intercepts requests in front of resources and enforces decisionseneros-gateway Sidecar

Deployment Models

EnerOS supports three Zero Trust deployment models:

ModelDescriptionApplicable Scenario
Device agentEach device runs an agent to communicate with PDPEnd-user devices
Resource agentProxy in front of resources intercepts requestsServer-side APIs
Hybrid agentDevice + resource dual-layer proxyCritical control systems

Five Pillars of Zero Trust

Referencing the CISA Zero Trust Maturity Model, EnerOS implements five pillars:

PillarPracticeEnerOS Implementation
IdentityEach service has a verifiable identityInternal CA + SPIFFE ID
DeviceDevice health measurementBoot measurement + image signing
NetworkNetwork segmentation encryptionmTLS + namespace isolation
ApplicationLeast privilege between applicationsRBAC + ABAC policies
DataData classification and encryptionField-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

PhaseOperationAutomation
RegistrationService registers identity with SPIREAutomatic
IssuanceCA issues X.509 SVIDAutomatic (90 days)
RotationAuto-rotate before certificate expiryAutomatic (30 days prior)
RevocationRevoke identity when service goes offlineAutomatic
AuditFull audit of identity operationsAutomatic + 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 CategoryExampleRisk Weight
Geographic anomalyLogin from different location30
Time anomalyLate-night operation20
Device anomalyNew device25
Behavior anomalyLarge data download40
Rate anomalyHigh-frequency requests35
Protocol anomalyAbnormal protocol50

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_id and spiffe_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:

StandardArticleZero Trust Mapping
IEC 62443-4-2CR 1.1 / 2.1mTLS + identity authentication
NERC CIP-005R1Electronic security perimeter
NERC CIP-007R4 / R6Port management + logging
MLPS 2.0 Level 3Communication encryption + access controlmTLS + RBAC
GDPRArt. 32Data encryption + access control
PIPLArticle 51Security protection measures
CCPA§ 1798.130Reasonable security measures