零信任架构与 mTLS
零信任(Zero Trust)的核心原则是”从不信任,始终校验”(Never Trust, Always Verify)。它摒弃了传统的”城堡与护城河”模型——内部网络默认可信、外部网络默认不可信——转而假设任何网络(无论内外)都不可信,每一次访问请求都必须经过严格的身份认证、设备健康校验与权限授权。
EnerOS 自 v0.43 起全面落地零信任架构,作为 IEC 62443、NERC CIP 与等保 2.0 的共同技术基座。零信任不仅是 EnerOS 的安全实现方式,更是工控与电力系统抵御 APT、勒索软件、供应链攻击等高级威胁的核心防线。
NIST SP 800-207
美国国家标准与技术研究院(NIST)发布的 SP 800-207《零信任架构》是零信任领域的权威参考框架。它定义了零信任的三大核心原则、逻辑组件与部署模型。
三大核心原则
| 原则 | 含义 | EnerOS 实现 |
|---|---|---|
| 显式验证 | 所有访问须显式认证与授权 | mTLS + SPIFFE + 持续评估 |
| 最小权限 | 仅授予完成任务所需的最小权限 | RBAC + ABAC + 默认拒绝 |
| 假设泄露 | 假设系统已被攻破,限制爆炸半径 | 网络分段 + 微隔离 + WORM |
逻辑组件
NIST 800-207 定义了零信任架构的两个核心逻辑组件:
| 组件 | 职责 | EnerOS 实现 |
|---|---|---|
| 策略决策点(PDP) | 评估访问请求并作出决策 | eneros-trust PolicyEngine |
| 策略执行点(PEP) | 在资源前拦截请求并执行决策 | eneros-gateway Sidecar |
部署模型
EnerOS 支持三种零信任部署模型:
| 模型 | 描述 | 适用场景 |
|---|---|---|
| 设备代理 | 每台设备运行代理与 PDP 通信 | 终端用户设备 |
| 资源代理 | 资源前置代理拦截请求 | 服务端 API |
| 混合代理 | 设备 + 资源双层代理 | 关键控制系统 |
零信任五大支柱
参考 CISA 零信任成熟度模型,EnerOS 落地五大支柱:
| 支柱 | 实践 | EnerOS 实现 |
|---|---|---|
| 身份 | 每个服务具备可验证身份 | 内部 CA + SPIFFE ID |
| 设备 | 设备健康度量 | 启动度量 + 镜像签名 |
| 网络 | 网络分段加密 | mTLS + 命名空间隔离 |
| 应用 | 应用间最小权限 | RBAC + ABAC 策略 |
| 数据 | 数据分类与加密 | 字段级加密 + WORM |
身份支柱
SPIFFE 身份框架
每个 EnerOS 服务都拥有唯一的 SPIFFE ID,作为其加密身份:
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))?;
身份生命周期
| 阶段 | 操作 | 自动化 |
|---|---|---|
| 注册 | 服务向 SPIRE 注册身份 | 自动 |
| 签发 | CA 签发 X.509 SVID | 自动(90 天) |
| 轮转 | 证书到期前自动轮转 | 自动(30 天前) |
| 撤销 | 服务下线时撤销身份 | 自动 |
| 审计 | 身份操作全量审计 | 自动 + WORM |
设备支柱
启动度量
[device_attestation]
enabled = true
tpm_required = true # 强制 TPM 度量
secure_boot = true # 强制安全启动
measured_boot = true # 度量启动
[device_attestation.pcrs]
# 度量寄存器预期值
pcr0 = "sha256:abc123..." # 启动代码
pcr7 = "sha256:def456..." # 安全启动策略
pcr9 = "sha256:789abc..." # 镜像度量
use eneros_trust::attestation::{TpmAttestor, PcrMeasurement};
let attestor = TpmAttestor::new();
let measurement = attestor.measure().await?;
if !measurement.verify(&expected_pcrs) {
return Err("设备健康度量失败,拒绝接入".into());
}
println!("设备健康: 通过");
println!("PCR0 (启动代码): {}", measurement.pcr0);
println!("PCR7 (安全启动): {}", measurement.pcr7);
网络支柱
mTLS 强制策略
所有内部 RPC 通道默认拒绝明文,证书到期前 30 天自动轮转:
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) // 校验 SAN
.verify_tenant_id(true) // 校验 tenant_id
.cert_rotation_days(90)
.build()?;
server.listen(addr, tls).await?;
握手时校验证书 SAN 与 tenant_id,不匹配即拒绝。
网络分段
[network_segmentation]
enabled = true
default_deny = true # 默认拒绝
namespace_isolation = true # 命名空间隔离
[[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"]
应用支柱
RBAC + ABAC 策略引擎
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!("允许访问"),
DecisionAction::Deny => println!("拒绝访问: {}", decision.reason),
DecisionAction::RequireApproval => println!("需要审批: {}", decision.approver),
}
策略示例
# 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 # 双因子操作
audit: true
数据支柱
数据分类与加密
[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 # 永久
[[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
持续验证
零信任的”持续”特性意味着验证不是一次性的,而是贯穿整个会话:
会话风险评估
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!("低风险,继续会话"),
s if s < 70 => {
println!("中风险,要求重新认证");
session.require_reauthentication().await?;
}
s if s >= 70 => {
println!("高风险,立即终止会话");
session.terminate().await?;
notify_security_team(&session).await?;
}
}
风险信号
| 信号类别 | 示例 | 风险权重 |
|---|---|---|
| 地理异常 | 异地登录 | 30 |
| 时间异常 | 凌晨操作 | 20 |
| 设备异常 | 新设备 | 25 |
| 行为异常 | 大量数据下载 | 40 |
| 速率异常 | 高频请求 | 35 |
| 协议异常 | 异常协议 | 50 |
mTLS 配置示例
eneros.toml 完整零信任配置
[compliance]
standard = "zero-trust"
framework = "nist-800-207"
enforce = true
[zero_trust]
enabled = true
default_deny = true # 默认拒绝
continuous_verification = true # 持续验证
risk_based_access = true # 基于风险的访问
# 身份
[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 # 30 天前自动轮转
# 设备
[zero_trust.device]
attestation_required = true
tpm_required = true
secure_boot = true
measured_boot = true
health_check_interval_minutes = 60
# 网络
[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
# 应用
[zero_trust.application]
rbac_enabled = true
abac_enabled = true
sbo_required_for_critical = true
policy_engine = "eneros-trust"
# 数据
[zero_trust.data]
classification = true
field_encryption = "AES-256-GCM"
worm_audit = true
key_management = "kms"
# 持续验证
[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 代码:mTLS 服务端
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 代码:客户端
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
针对关键操作,零信任要求额外的双因子控制:
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?;
合规检查清单
部署前请逐项确认:
- 所有服务间通信启用 mTLS,无任何明文端口
- 内部 CA 离线签发根证书,工作证书自动轮转(90 天)
- 证书 SAN 绑定
tenant_id与spiffe_id - 默认拒绝策略,显式 allow 才放行
- 关键操作启用 select-before-operate
- 审计链 HMAC 校验通过,WORM 写入正常
- IDS 覆盖横向移动、命令风暴、Modbus 异常等模式
- 密钥由 KMS / HSM 托管,禁用明文密钥文件
- 设备启动度量(TPM)启用并校验通过
- 安全启动(Secure Boot)启用
- SPIFFE 身份框架部署并自动轮转 SVID
- 网络分段策略生效,命名空间隔离
- RBAC + ABAC 策略引擎在线
- 持续验证机制运行,会话风险实时评估
- 策略决策点(PDP)与策略执行点(PEP)解耦部署
- IDS 特征库定期更新(24 小时内)
- 关键操作双因子认证(TOTP 或硬件令牌)
- 数据分类与字段加密覆盖全部敏感数据
合规映射
零信任是多项标准的共同技术要求:
| 标准 | 条款 | 零信任映射 |
|---|---|---|
| IEC 62443-4-2 | CR 1.1 / 2.1 | mTLS + 身份认证 |
| NERC CIP-005 | R1 | 电子安全边界 |
| NERC CIP-007 | R4 / R6 | 端口管理 + 日志 |
| 等保 2.0 三级 | 通信加密 + 访问控制 | mTLS + RBAC |
| GDPR | Art. 32 | 数据加密 + 访问控制 |
| PIPL | 第 51 条 | 安全保护措施 |
| CCPA | § 1798.130 | 合理安全措施 |