4. 组件拓扑建模基础:节点、边、属性定义、拓扑图数据结构设计

在构建日志平台的安全权限模型之前,必须首先建立精确的组件拓扑图。拓扑图是策略引擎(OPA)评估访问路径、检测权限滥用、验证网络隔离的基础数据源。本章将定义拓扑图的三大核心要素:节点(Node)、边(Edge)、属性(Attribute),并设计标准化的数据结构。

4.1 节点(Node):拓扑中的实体

节点代表日志平台中所有可被策略评估的资源实体。每个节点必须拥有全局唯一的标识符(ID)和明确的类型(Type)。

节点类型 描述 示例 ID
service 微服务或应用进程 svc:log-collector
pod Kubernetes Pod 实例 pod:fluentbit-abc123
storage 日志存储后端(如 S3、ES 索引) storage:es-prod-logs-2025
network 虚拟网络或子网段 net:log-ingress-vpc
identity 服务账号、用户或角色 id:svc:log-writer@prod
policy OPA 策略或 RBAC 规则 policy:restrict-es-write
节点命名规范:建议采用 类型:命名空间:名称 的三段式结构,例如 pod:logging:fluentbit-main,确保在跨集群、跨环境的拓扑中不会发生 ID 冲突。

4.2 边(Edge):实体间的关系

边定义了节点之间的有向关系。在安全权限建模中,边通常代表数据流、调用链或权限授予。每条边必须包含源节点(source)、目标节点(target)和关系类型(relation)。

关系类型 语义 示例
reads_from 数据读取 svc:log-analyzer → reads_from → storage:es-prod-logs
writes_to 数据写入 pod:fluentbit → writes_to → storage:s3-log-bucket
calls RPC/API 调用 svc:auth-gateway → calls → svc:log-query
belongs_to 从属关系 pod:fluentbit-abc → belongs_to → svc:log-collector
has_permission 权限绑定 id:svc:log-writer → has_permission → policy:write-logs

4.3 属性(Attribute):节点的元数据

属性为节点和边附加上下文信息,这些信息在 OPA 策略评估时作为 input 的一部分被引用。属性以键值对(Key-Value)形式存储。

// 节点属性示例(JSON 格式)
{
  "id": "pod:fluentbit-main-x1y2",
  "type": "pod",
  "attributes": {
    "namespace": "logging",
    "labels": {
      "app": "fluentbit",
      "version": "1.9"
    },
    "ip": "10.0.1.25",
    "service_account": "sa:fluentbit-sa",
    "security_context": {
      "run_as_non_root": true,
      "read_only_root_filesystem": true
    }
  }
}

// 边属性示例
{
  "source": "pod:fluentbit-main-x1y2",
  "target": "storage:s3-log-bucket",
  "relation": "writes_to",
  "attributes": {
    "protocol": "https",
    "port": 443,
    "encrypted": true,
    "rate_limit": "1000/s"
  }
}
属性设计原则:只存储策略评估所需的最小必要属性。避免将大量运行时指标(如 CPU、内存)塞入拓扑属性,这些应通过独立的监控系统处理。属性应聚焦于身份、权限、网络上下文三类信息。

4.4 拓扑图数据结构设计

为了支持 OPA 的高效查询,拓扑图数据采用邻接表(Adjacency List)结构存储。整体数据结构分为三个顶层字段:nodes、edges、metadata。

// 完整拓扑图数据结构(JSON Schema 风格)
{
  "metadata": {
    "version": "1.0",
    "environment": "production",
    "generated_at": "2025-04-10T08:00:00Z",
    "source": "topology-sync-controller"
  },
  "nodes": [
    {
      "id": "svc:log-collector",
      "type": "service",
      "attributes": {
        "namespace": "logging",
        "owner": "platform-team"
      }
    },
    {
      "id": "storage:es-prod-logs",
      "type": "storage",
      "attributes": {
        "type": "elasticsearch",
        "index_pattern": "logs-*",
        "access_level": "restricted"
      }
    }
  ],
  "edges": [
    {
      "source": "svc:log-collector",
      "target": "storage:es-prod-logs",
      "relation": "writes_to",
      "attributes": {
        "protocol": "http",
        "auth_method": "service-account"
      }
    }
  ]
}

4.5 拓扑图可视化:节点与边的关系

下图展示了一个简化的日志平台组件拓扑,包含采集、传输、存储、查询四个核心节点及其关系。

日志平台组件拓扑图 - 节点与边关系 日志平台组件拓扑图(节点与边关系) 日志采集器 pod:fluentbit-main 消息队列 svc:kafka-ingest 日志存储 storage:es-prod 查询服务 svc:log-query IAM 策略 policy:es-read writes_to writes_to reads_from has_permission controls_access 图例:实线 = 数据流(writes_to / reads_from) 虚线 = 权限控制(has_permission / controls_access)

4.6 拓扑图在 OPA 中的使用方式

拓扑图数据通常以 data.topology 的形式加载到 OPA 的基础文档(Base Document)中。策略编写者可以通过 Rego 的 data.topology.nodes 和 data.topology.edges 进行遍历查询。

// Rego 策略示例:检查某个 Pod 是否有权限写入存储
package platform.logs

import future.keywords.in

# 查询拓扑中所有从指定 Pod 出发的 writes_to 边
allowed_targets[target] {
    some edge in data.topology.edges
    edge.source == input.pod_id
    edge.relation == "writes_to"
    target := edge.target
}

# 检查目标存储是否允许该 Pod 写入
allow_write {
    input.action == "write"
    input.target_storage in allowed_targets
}
性能注意事项:当拓扑图节点数超过 10,000 时,建议在 OPA 外部预计算可达性矩阵(Reachability Matrix),或使用 OPA 的 graph.reachable 内置函数进行高效路径查询,避免在策略中全量遍历边列表。

4.7 拓扑图版本管理与增量更新

生产环境中,组件拓扑会频繁变化(Pod 扩缩容、服务升级、网络策略调整)。建议采用快照+增量补丁的策略:

  • 全量快照:每 5 分钟生成一次完整拓扑,用于 OPA 冷启动和数据恢复。
  • 增量补丁:每次拓扑变化时,仅推送变更的节点和边(add / remove / update),减少 OPA 数据加载开销。
// 增量补丁示例
{
  "patch": [
    {"op": "add", "path": "/nodes/-", "value": {"id": "pod:fluentbit-new", "type": "pod", "attributes": {...}}},
    {"op": "add", "path": "/edges/-", "value": {"source": "pod:fluentbit-new", "target": "storage:es-prod", "relation": "writes_to"}},
    {"op": "remove", "path": "/nodes/3"}  // 移除已下线的节点
  ]
}

4.8 拓扑图数据质量检查清单

检查项 要求 验证方式
节点 ID 唯一性 所有节点 ID 不可重复 拓扑生成器自动校验
边引用完整性 每条边的 source 和 target 必须在 nodes 中存在 拓扑加载时做外键检查
属性类型一致性 同一类型节点的属性 schema 必须一致 JSON Schema 校验
无孤立节点 每个节点至少有一条入边或出边(根节点除外) 拓扑分析工具扫描
版本时间戳 metadata.generated_at 必须为有效 UTC 时间 格式校验