跳到主内容

零信任架构与 mTLS

合规与安全

零信任架构与 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_idspiffe_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-2CR 1.1 / 2.1mTLS + 身份认证
NERC CIP-005R1电子安全边界
NERC CIP-007R4 / R6端口管理 + 日志
等保 2.0 三级通信加密 + 访问控制mTLS + RBAC
GDPRArt. 32数据加密 + 访问控制
PIPL第 51 条安全保护措施
CCPA§ 1798.130合理安全措施

相关文档