Zero Trust and Security Enhancement
EnerOS fully implements a zero trust architecture: Never Trust, Always Verify. All internal service-to-service communication enforces mTLS mutual authentication, with certificates issued by the built-in CA; all command decision chains are chain-audited via HMAC signatures and land in WORM forensics storage; it is also equipped with Intrusion Detection (IDS), Key Management (KMS), and compliance frameworks (NERC CIP / IEC 62443 / GB/T 22239).
Zero trust security is provided collaboratively by three crates—eneros-trust, eneros-ids, and eneros-audit—covering the four dimensions of identity, transport, decision, and storage.
Security Architecture Overview
┌────────────────────────────────────────────────────────────┐
│ External Access Layer │
│ REST / GraphQL / WebSocket / SSE ──▶ Gateway (mTLS) │
└──────────────────────────┬─────────────────────────────────┘
│
┌──────────────────────────▼─────────────────────────────────┐
│ Identity and Authorization Layer │
│ X.509 + SPIFFE ─▶ RBAC + ABAC ─▶ Audit Decision │
└──────────────────────────┬─────────────────────────────────┘
│
┌──────────────────────────▼─────────────────────────────────┐
│ Service Communication Layer │
│ Agent ◀─mTLS──▶ Kernel Agent ◀─mTLS──▶ Agent │
│ All RPC enforces TLS 1.3 + PQC hybrid cipher │
└──────────────────────────┬─────────────────────────────────┘
│
┌──────────────────────────▼─────────────────────────────────┐
│ Audit and Forensics Layer │
│ HMAC chain audit ─▶ WORM storage (7-year retention) │
│ IDS rules + anomaly detection ─▶ SOC alert channel │
└────────────────────────────────────────────────────────────┘
| Security Dimension | Implementing Crate | Key Technology |
|---|---|---|
| Identity authentication | eneros-trust | mTLS + X.509 + SPIFFE SVID |
| Authorization decision | eneros-trust | RBAC + ABAC policy engine |
| Transport encryption | eneros-trust | TLS 1.3 + Kyber768 hybrid |
| Audit chain | eneros-audit | HMAC-SHA256 chain structure |
| Forensics storage | eneros-audit | WORM + Zstd + 7-year retention |
| Intrusion detection | eneros-ids | Rule matching + behavior baseline |
| Key management | eneros-trust | SoftHSM2 / PKCS#11 / cloud KMS |
Internal CA and Certificates
EnerOS has a built-in private CA that automatically issues and rotates all internal service certificates. The CA supports a two-level structure of Root CA and Intermediate CA, following the X.509 v3 standard.
use eneros_security::{Ca, CertificateSpec, KeyUsage, KeyAlgorithm};
use std::time::Duration;
let ca = Ca::builder()
.root_key_path("/etc/eneros/ca.key")
.root_cert_path("/etc/eneros/ca.crt")
.intermediate_key_path("/etc/eneros/intermediate.key")
.intermediate_cert_path("/etc/eneros/intermediate.crt")
.build().await?;
// Issue a certificate for an internal service
let spec = CertificateSpec::new("agent-runtime.eneros.internal")
.sans(vec!["agent-runtime", "10.0.0.5", "agent-runtime.default.svc"])
.validity(Duration::from_secs(86400 * 90))
.key_usage(KeyUsage::ServerAndClient)
.key_algorithm(KeyAlgorithm::EcdsaP256)
.extensions(vec![
Extension::spiffe_uri("spiffe://eneros/agent-runtime"),
Extension::basic_constraints(ca: false, path_len: 0),
]);
let cert = ca.issue(spec).await?;
println!("Issued certificate serial number: {}", cert.serial_number);
println!("Valid until: {}", cert.not_after);
Certificate Auto-Rotation
The CA monitors all issued certificates and automatically renews them 30 days before expiration, with zero downtime:
use eneros_security::ca::RotationPolicy;
let rotation = RotationPolicy::new()
.renew_before(Duration::from_secs(86400 * 30))
.on_renew(|old, new| async move {
kernel.reload_tls_cert(new).await?;
notify_service("agent-runtime").await
})
.parallelism(4); // Concurrent renewal
ca.enable_rotation(rotation).await?;
CA Configuration Parameters
| Parameter | Default | Description |
|---|---|---|
| root_key_path | /etc/eneros/ca.key | Root CA private key path |
| root_cert_path | /etc/eneros/ca.crt | Root CA certificate path |
| validity | 90 days | Service certificate validity period |
| renew_before | 30 days | Advance renewal window |
| key_algorithm | ECDSA P-256 | Certificate signature algorithm |
| signature_algorithm | SHA-256 | Hash algorithm |
| serial_length | 128 bit | Serial number length |
mTLS Mutual Authentication
All RPC channels (Agent ↔ Kernel, Agent ↔ Agent, Gateway ↔ Backend) enforce mTLS. Connections that fail authentication are rejected at the TCP handshake stage.
use eneros_security::tls::{TlsConfig, TlsVersion, CipherSuite};
let tls = TlsConfig::mutual()
.server_cert("/etc/eneros/certs/server.crt")
.server_key("/etc/eneros/certs/server.key")
.client_ca("/etc/eneros/ca.crt")
.min_version(TlsVersion::TLS_1_3)
.cipher_suites(CipherSuite::post_quantum())
.session_resumption(false)
.client_auth(ClientAuth::RequireAnyCert)
.verify_callback(|cert| async move {
let chain = cert_chain_store.verify(&cert).await?;
if !chain.has_spiffe_uri() {
return Err(TlsError::InvalidIdentity);
}
Ok(())
});
server.listen(addr, tls).await?;
TLS Configuration Parameters
| Parameter | Default | Description |
|---|---|---|
| min_version | TLS 1.3 | Minimum TLS version |
| cipher_suites | PQC hybrid | Cipher suites (including Kyber768) |
| session_resumption | false | Session resumption (disabled for security) |
| client_auth | RequireAnyCert | Client certificate requirement |
| verify_timeout | 5s | Certificate verification timeout |
| handshake_timeout | 10s | Handshake timeout |
HMAC Chain Audit
Each audit record contains the HMAC-SHA256 of the previous one, forming a tamper-proof chain structure. Any modification of an intermediate record will cause the chain to break for all subsequent records.
use eneros_security::audit::{AuditChain, AuditEntry, AuditContext};
use std::collections::HashMap;
let mut chain = AuditChain::open("/var/eneros/audit.chain")?;
// The first record automatically forms the genesis block
chain.append(AuditEntry::new()
.actor("dispatch_agent")
.actor_identity("spiffe://eneros/dispatch-agent")
.action("open_breaker")
.target(breaker_id.to_string())
.target_type("breaker")
.verdict("allow")
.context(AuditContext::new()
.insert("reason", "fault_isolation")
.insert("command_id", "cmd-7821")
.insert("safety_check", "passed"))
.timestamp(now())).await?;
// Subsequent records automatically reference the HMAC of the previous one
chain.append(AuditEntry::new()
.actor("self_healing_agent")
.action("restore_power")
.target(feeder_id.to_string())
.verdict("allow")
.timestamp(now())).await?;
// Verify chain integrity
let valid = chain.verify().await?;
assert!(valid, "Audit chain has been tampered with");
Audit Field Reference
| Field | Type | Description |
|---|---|---|
| actor | String | Operation initiator (Agent name / user) |
| actor_identity | String | SPIFFE SVID identity |
| action | String | Operation type (open_breaker / restore_power, etc.) |
| target | String | Operation target ID |
| target_type | String | Target type (breaker / feeder / generator) |
| verdict | String | Decision result (allow / deny / modified) |
| context | HashMap | Custom context |
| prev_hash | [u8; 32] | HMAC of the previous record |
| hash | [u8; 32] | HMAC of the current record |
WORM Forensics Storage
Audit logs are written to WORM (Write Once Read Many) storage, meeting NERC CIP-007 and IEC 62443 requirements. The underlying layer uses a file system with read-only mounts, and any subsequent modification attempts are directly rejected by the file system.
use eneros_security::worm::{WormStore, Compression, HashAlgo, RetentionPolicy};
let worm = WormStore::mount("/var/eneros/worm")?
.retention(RetentionPolicy::years(7)) // 7-year retention
.compression(Compression::Zstd { level: 6 })
.hash_chain(HashAlgo::Sha256)
.segment_size(64 * 1024 * 1024) // 64MB segment
.immutable_after_close(true);
worm.append(&audit_entry).await?;
// Attempting to tamper will fail
let result = worm.overwrite(0, &fake_entry).await;
assert!(result.is_err(), "WORM storage rejects writes");
// Read historical audit
let records = worm.query(Query::by_actor("dispatch_agent")
.range(now() - Duration::from_secs(86400) .. now()))
.await?;
WORM Configuration Parameters
| Parameter | Default | Description |
|---|---|---|
| mount_path | /var/eneros/worm | Mount point |
| retention | 7 years | Retention period |
| compression | Zstd level 6 | Compression algorithm |
| hash_chain | SHA-256 | Hash algorithm |
| segment_size | 64MB | Single segment size |
| immutable_after_close | true | Segment immutable after close |
Intrusion Detection (IDS)
Built-in rule-based and anomaly-based IDS, covering typical power OT attack patterns. Rules can be hot-loaded at runtime without restarting the service.
use eneros_security::ids::{Ids, Signature, AlertAction, Severity};
let mut ids = Ids::new()
.signature(Signature::modbus_anomaly()
.severity(Severity::High))
.signature(Signature::scada_unauthorized_command()
.severity(Severity::Critical))
.signature(Signature::rapid_breaker_operation()
.window(Duration::from_secs(60))
.threshold(10)) // Command storm: ≥10 switching operations within 60 seconds
.signature(Signature::lateral_movement()
.severity(Severity::High))
.signature(Signature::unusual_login_time()
.baseline(Duration::from_secs(86400 * 30)))
.action_on_alert(AlertAction::BlockAndNotify);
ids.start().await?;
// Subscribe to alerts
while let Some(alert) = ids.alerts().recv().await {
println!("[{}] {}", alert.severity, alert.message);
notify_soc(&alert).await?;
if alert.severity == Severity::Critical {
kernel.lockdown().await?;
}
}
IDS Rule Library
| Rule | Detection Scenario | Default Action |
|---|---|---|
| modbus_anomaly | Modbus abnormal function code | Block + Notify |
| scada_unauthorized_command | SCADA unauthorized command | Block + Notify |
| rapid_breaker_operation | Command storm (frequent switching) | Block |
| lateral_movement | Lateral movement | Notify + Trace |
| unusual_login_time | Unusual login time | Notify |
| port_scan | Port scanning | Block |
| dga_domain | DGA domain access | Block + Notify |
| iec104_apdu_flood | IEC 104 APDU flood | Block |
Key Management (KMS)
Supports local KMS, SoftHSM2, PKCS#11 hardware HSM, and cloud KMS integration:
use eneros_security::kms::{Kms, KeyId, KeyAlgorithm, KmsBackend, KeyPolicy};
let kms = Kms::builder()
.backend(KmsBackend::SoftHsm2)
.config("/etc/eneros/kms.conf")
.build().await?;
// Create a key
let key_id = kms.create_key(KeyAlgorithm::Aes256Gcm)
.policy(KeyPolicy::rotate_every(Duration::from_secs(86400 * 90)))
.await?;
// Encrypt / decrypt
let ciphertext = kms.encrypt(&key_id, plaintext).await?;
let plaintext = kms.decrypt(&key_id, &ciphertext).await?;
// Key rotation
kms.rotate(&key_id).await?;
// List keys
for key in kms.list_keys().await? {
println!("Key {} current version {}", key.id, key.current_version);
}
KMS Backend Comparison
| Backend | Security Level | Performance | Applicable |
|---|---|---|---|
| Local file | Low | < 50μs | Development and testing |
| SoftHSM2 | Medium | < 200μs | Production environment |
| PKCS#11 HSM | High | < 500μs | Critical infrastructure |
| AWS KMS | High | < 50ms | Cloud deployment |
| Azure Key Vault | High | < 50ms | Cloud deployment |
Compliance Framework
EnerOS has multiple built-in compliance frameworks that can be configured per tenant:
| Standard | Coverage | Status | Mandatory Items |
|---|---|---|---|
| NERC CIP | North American Electric Reliability | ✅ | CIP-007 audit, CIP-011 data protection |
| IEC 62443 | Industrial control security | ✅ | Zone classification, access control |
| GB/T 22239 | China MLPS 2.0 Level 3 | ✅ | Security audit, intrusion prevention |
| ISO 27001 | Information security management system | ✅ | Risk assessment, compliance audit |
| GDPR | EU data protection | ✅ | Data subject rights, cross-border transfer |
Security Capability Matrix
| Capability | Implementation Technology | Mandatory Level |
|---|---|---|
| Identity authentication | mTLS + X.509 + SPIFFE | Kernel-enforced |
| Authorization | RBAC + ABAC policy engine | Kernel-enforced |
| Encrypted transport | TLS 1.3 + PQC hybrid | Default on |
| Encrypted storage | AES-256-GCM | Default on |
| Audit | HMAC chain + WORM | Kernel-enforced |
| Intrusion detection | Rules + anomaly baseline | Default on |
| Key management | KMS + HSM | Default on |
| Key rotation | Automatic, 90 days | Default on |
| Safety gateway | Multi-layer defense + rate limiting | Kernel-enforced |
| Data masking | Dynamic masking + static masking | Configurable |
Performance Metrics
| Operation | Latency | Throughput |
|---|---|---|
| mTLS handshake | < 5ms | 10,000/s |
| Certificate issuance | < 100ms | - |
| HMAC chain audit write | < 50μs | 50,000/s |
| WORM write | < 100μs | 20,000/s |
| IDS rule matching | < 5μs | 1,000,000/s |
| KMS encryption | < 200μs | - |
| ABAC decision | < 100μs | 100,000/s |
| Certificate verification | < 2ms | - |
Relationship with Other Capabilities
- Safety Guard: The safety gateway makes decisions based on identity authentication results. See Safety Guard
- Multi-tenant Isolation: Tenant identities are bound to certificates, and SPIFFE namespaces are allocated per tenant
- Internationalization Compliance: The compliance framework supports differentiated multi-region configuration. See Internationalization and Compliance
- IoT Access: IoT devices use a dedicated certificate system for access. See IoT Ubiquitous Access
- High Availability: Audit logs are replicated across regions, and WORM segments maintain strong consistency across replicas
Related Documentation
- Safety Guard — The safety gateway is based on identity authentication
- Multi-tenant and Isolation — Tenant identities are bound to certificates
- Internationalization and Compliance — Multi-region compliance framework
- IoT Ubiquitous Access — IoT device certificate management
- High Availability Enhancement — Audit cross-region replication