Resource关系

5 阅读13分钟

IUpwindResource 之间的关系分析

本文档详细分析了所有 IUpwindResource 实现类之间的关系,包括继承关系、包含关系、引用关系、分类关系等。

相关文档: 查看 IUpwindResource_Complete_Reference.md 了解每个实现类的详细信息。


1. 继承关系(代码层面)

所有实现类都实现 IUpwindResource 接口,但彼此之间没有继承关系

  • 除了 WorkloadTreeStorageAssetSearchKeyObject,其他类都继承自 StorageObject
  • WorkloadTreeStorage 直接实现 IUpwindResource,不继承 StorageObject
  • AssetSearchKeyObject 继承自 StorageObject,但只是工具类,不是真正的资源

继承结构

StorageObject (shared-library)
├── GraphAsset implements IUpwindResource
├── Endpoint implements IUpwindResource
├── Resource implements IUpwindResource
├── DetectionResource implements IUpwindResource
├── FindingResource implements IUpwindResource
├── VulnerableResource implements IUpwindResource
├── EndpointSearch implements IUpwindResource
├── DetectionEndpointDetails implements IUpwindResource
├── MonitoredResource implements IUpwindResource
├── InventoryStorageAsset implements IUpwindResource
├── InventoryNetworkAsset implements IUpwindResource
├── InventoryComputeAsset implements IUpwindResource
└── AssetSearchKeyObject implements IUpwindResource (工具类)

WorkloadTreeStorage implements IUpwindResource (不继承 StorageObject)

2. 数据源和用途的根本差异(为什么需要同时存在)

GraphAsset vs WorkloadTreeStorage:为什么不能复用?

核心差异:它们代表同一物理资源的不同维度,数据来源、结构和用途完全不同

维度GraphAssetWorkloadTreeStorage
数据来源Graph Query API (inventory-api/search)Workload API (clusters/workloadViewNew)
数据性质静态配置信息运行时拓扑信息
代表内容云资源的配置、标签、ARN、类型等集群、命名空间、端点的层级关系和连接
时间维度配置快照(无时间范围)运行时状态(需要时间范围 {from, to}
数据结构单个资产对象树形结构(Cluster → Namespace → Endpoint)
主要用途展示资产基本信息、配置详情展示网络拓扑、连接关系、流量数据

为什么需要同时存在?

  1. 互补的信息

    • GraphAsset 提供:资源名称、类型、标签、ARN、区域、云账户等静态配置信息
    • WorkloadTreeStorage 提供:集群层级、命名空间、端点连接、网络流量等运行时拓扑信息
  2. 不同的使用场景

    • 查看资源配置 → 使用 GraphAsset
    • 查看网络拓扑 → 使用 WorkloadTreeStorage
    • AssetDetailsSidePane 中,两者同时使用:
      // GraphAsset 用于展示基本信息
      <ResourceViewHeader resource={asset} graphAsset={asset} />
      
      // WorkloadTreeStorage 用于展示网络拓扑标签页
      <ResourceOverviewTabs treeStorage={treeStorage} resource={asset} />
      
  3. 数据获取流程

    // 1. 先获取 GraphAsset(总是尝试获取)
    const [asset] = useGraphAssetByIdOrRefId(orgId, graphId, refId);
    
    // 2. 根据 GraphAsset 的属性决定是否获取 WorkloadTreeStorage
    if (asset?.getEndpointId()) → 按 endpoint 获取 WorkloadTreeStorage
    if (asset?.isCluster() && asset?.getK8sClusterId()) → 按 cluster 获取
    if (asset?.getResourceId() || asset?.getIdentifier()) → 按 resource 获取
    
    // 3. 两者可以同时存在,提供不同维度的信息
    

结论:不能复用,因为它们的数据来源、结构和用途完全不同,是互补关系而非替代关系。


3. 包含关系 vs 引用关系(关键区别)

WorkloadTreeStorage ⊃ Endpoint(真正的包含关系,一对多)

关系WorkloadTreeStorage 真正包含 Endpoint 对象,且是一对多关系

  • WorkloadTreeStorage 内部维护 endpointIndex: Map<string, Endpoint>
  • Endpoint 对象存储在 WorkloadTreeStorage 内部
  • EndpointWorkloadTreeStorage 树结构中的叶子节点
  • 一个 WorkloadTreeStorage 可以包含多个 Endpoint
  • Endpoint 通过 WorkloadTreeStorage.putEndpointsObjects() 方法添加

代码证据

class WorkloadTreeStorage {
  private endpointIndex: Map<string, Endpoint>;  // 真正存储 Endpoint 对象
  public putEndpointsObjects(objects: Endpoint[]) { 
    // 将 Endpoint 对象添加到内部 Map
  }
  public getEndpointById(id: string): Endpoint | undefined { 
    return this.endpointIndex.get(id);  // 直接从内部 Map 获取
  }
  public getAllEndpoints(): Endpoint[] {
    return Array.from(this.endpointIndex.values());  // 获取所有 Endpoint
  }
}

GraphAsset → Endpoint(一对一关系,只是 ID 引用)

关系GraphAsset 不包含 Endpoint,只是通过 endpointId 引用,且是一对一关系

  • GraphAsset 有一个 private endpointId: string 字段(只有一个,不是数组)
  • 这只是一个 ID 字符串,不是 Endpoint 对象
  • 一对一关系:一个 GraphAsset 最多对应一个 Endpoint
  • 需要通过 endpointIdWorkloadDataModel.unfilteredEndpointsStorage 中查找对应的 Endpoint
  • GraphAssetEndpoint独立的对象,通过 ID 关联

为什么 GraphAsset 和 Endpoint 是一对一,而 WorkloadTreeStorage 和 Endpoint 是一对多?

  • GraphAsset:代表单个资源(如一个 EC2 实例、一个 S3 Bucket),这个资源可能对应一个运行时端点
  • WorkloadTreeStorage:代表树形结构(Cluster → Namespace → Endpoint),一个树节点可以包含多个端点
    • 例如:一个 Namespace 节点可能包含多个 Pod(每个 Pod 是一个 Endpoint)
    • 例如:一个 Cluster 节点包含多个 Namespace,每个 Namespace 又包含多个 Endpoint

代码证据

class GraphAsset {
  private endpointId: string;  // 只有一个 endpointId,一对一关系
  
  getEndpointId(): string | undefined {
    return this.endpointId;
  }
  
  // 需要通过 ID 在外部 storage 中查找
  // const endpoint = workloadDataModel.unfilteredEndpointsStorage.getObjectByID(endpointId);
}

关键区别

  • WorkloadTreeStorage ⊃ Endpoint:真正的包含关系,一对多Endpoint 对象存储在 WorkloadTreeStorage 内部
  • GraphAsset → Endpoint:只是引用关系,一对一GraphAsset 只存储一个 endpointId,需要通过 ID 查找

4. 分类关系(同一概念的不同类型)

Inventory 资产分类(联合类型,互斥)

关系:三种 Inventory 资产是同一概念(Inventory Asset)的不同类型,互斥

type InventoryAsset = 
  | InventoryStorageAsset    // 存储资产(S3, GCS 等)
  | InventoryNetworkAsset    // 网络资产(Security Groups, Firewalls 等)
  | InventoryComputeAsset    // 计算资产(EC2, VMs 等)
  • 它们都来自 Inventory API,但按资产类型分类
  • 一个资源只能是其中一种类型,不能同时是多种
  • 存储在 InventoryModel.storages 的不同 storage 中

现实世界例子

  • InventoryStorageAsset: AWS S3 Bucket my-company-data-bucket
  • InventoryNetworkAsset: AWS Security Group sg-0123456789abcdef0
  • InventoryComputeAsset: EC2 Instance i-1234567890abcdef0

安全相关资源分类(不同数据源,可能重叠)

关系:这些类都代表"资源"概念,但来自不同的数据源和用途,可能指向同一个物理资源

  • Resource:新检测系统中的资源(来自 detections API)
  • DetectionResource:检测/威胁资源(来自 detections API,旧系统)
  • FindingResource:Posture Findings 资源(来自 posture/findings API)
  • VulnerableResource:漏洞资源(来自 vulnerabilities API)

可能的关系

  • 同一个物理资源(如一个 EC2 实例)可能同时有:
    • FindingResource(有配置问题)
    • DetectionResource(有威胁检测)
    • VulnerableResource(有漏洞)
  • 它们通过 resourceIdendpointId 等字段关联到同一个资源
  • FindingResourceendpointIdendpointRefId 字段,可以关联到 Endpoint

现实世界例子

  • 同一个 EC2 实例 i-1234567890abcdef0 可能同时有:
    • FindingResource: Security Group 配置问题
    • DetectionResource: 检测到异常网络活动
    • VulnerableResource: 运行有漏洞的 Docker 镜像

5. 关联关系(通过 ID 引用,不包含对象)

FindingResource → Endpoint(通过 ID 引用)

关系FindingResource 通过 endpointIdendpointRefId 引用 Endpoint,但不包含它

endpointId vs endpointRefId 的区别

字段类型含义用途
endpointIdstringEndpoint 在 Workload 系统中的 ID直接在 WorkloadDataModel.unfilteredEndpointsStorage 中查找 Endpoint 对象
endpointRefIdstringEndpoint 的 refId(resourceId),用于在 Graph 数据库中查找需要通过 getEndpointIdByRefId API 转换为 endpointId,然后再查找 Endpoint

转换流程

// 如果有 endpointId,直接使用
if (findingResource.getEndpointId()) {
  const endpoint = workloadDataModel.unfilteredEndpointsStorage.getObjectByID(
    findingResource.getEndpointId()
  );
}

// 如果只有 endpointRefId,需要先转换为 endpointId
if (!endpointId && findingResource.getEndpointRefId()) {
  const response = await getEndpointIdByRefId(orgId, findingResource.getEndpointRefId());
  const endpointId = response.id;
  const endpoint = workloadDataModel.unfilteredEndpointsStorage.getObjectByID(endpointId);
}

具体含义

  • FindingResourceendpointId?: stringendpointRefId?: string 字段
  • 这些字段只是 ID 字符串,不是 Endpoint 对象
  • 含义:这个 Finding 是针对某个 Endpoint 的配置问题
  • 需要通过 ID 在 WorkloadDataModel.unfilteredEndpointsStorage 中查找对应的 Endpoint

使用场景

// FindingResource 表示一个配置问题
const finding = new FindingResource({
  id: "finding-123",
  endpointId: "endpoint-456",  // 引用某个 Endpoint
  type: FINDING_RESOURCE_TYPES.AWS_S3_BUCKET,
  // ...
});

// 需要通过 ID 查找对应的 Endpoint
const endpoint = workloadDataModel.unfilteredEndpointsStorage.getObjectByID(
  finding.getEndpointId()
);

// 现在可以同时使用 FindingResource 和 Endpoint
// FindingResource 提供配置问题信息
// Endpoint 提供运行时信息

为什么需要这种关联?

  • FindingResource 来自 Posture Findings API,表示配置问题
  • Endpoint 来自 Workload API,表示运行时端点
  • 同一个物理资源可能既有配置问题(FindingResource),又有运行时信息(Endpoint)
  • 通过 endpointId 关联,可以同时展示配置问题和运行时状态

Resource → GraphAsset(通过 refId/resourceId 引用)

关系Resource 通过 refIdresourceId 引用 GraphAsset,表示同一个物理资源

具体含义

  • ResourcerefId?: stringresourceId?: string 字段
  • 这些字段指向同一个 GraphAsset 的 ID 或 refId
  • 含义:Resource(来自新检测系统)和 GraphAsset(来自 Graph 数据库)代表同一个物理资源

使用场景

// 在 AssetDetailsSidePane 中,从 GraphAsset 创建 Resource
const resource = new Resource({
  id: asset?.getId(),              // 使用 GraphAsset 的 ID
  resourceName: asset?.getName(),  // 使用 GraphAsset 的名称
  refId: asset?.getRefId(),        // 引用 GraphAsset 的 refId
  cloudProvider: asset?.getCloudProvider(),
  region: asset?.getRegion(),
  // ...
});

// Resource 和 GraphAsset 指向同一个物理资源
// Resource 提供检测相关的信息
// GraphAsset 提供配置信息

为什么需要这种关联?

  • Resource 来自新检测系统(detections API),表示检测到的资源
  • GraphAsset 来自 Graph 数据库,表示配置中的资源
  • 同一个物理资源可能同时有:
    • 配置信息(GraphAsset)
    • 检测信息(Resource)
  • 通过 refId 关联,可以同时展示配置和检测信息

GraphAsset → Endpoint(通过 endpointId 引用)

关系GraphAsset 通过 endpointId 引用 Endpoint,表示配置资源可能关联到运行时端点

具体含义

  • GraphAssetprivate endpointId: string 字段
  • 这只是一个 ID 字符串,不是 Endpoint 对象
  • 含义:这个配置资源(GraphAsset)可能关联到一个运行时端点(Endpoint)
  • 需要通过 endpointIdWorkloadDataModel.unfilteredEndpointsStorage 中查找对应的 Endpoint

使用场景

// GraphAsset 表示配置中的资源
const asset = new GraphAsset({
  id: "asset-123",
  label: "aws_ec2_instance",
  endpointId: "endpoint-456",  // 引用某个 Endpoint
  // ...
});

// 需要通过 ID 查找对应的 Endpoint
const endpoint = workloadDataModel.unfilteredEndpointsStorage.getObjectByID(
  asset.getEndpointId()
);

// 现在可以同时使用 GraphAsset 和 Endpoint
// GraphAsset 提供配置信息
// Endpoint 提供运行时信息

关联关系总结

关联类型关系含义查找方式
FindingResource → EndpointID 引用Finding 针对某个 EndpointworkloadDataModel.unfilteredEndpointsStorage.getObjectByID(endpointId)
Resource → GraphAssetID/refId 引用同一物理资源的不同表示graphAssetStorage.getObjectByID(refId) 或通过 useGraphAssetByIdOrRefId
GraphAsset → EndpointID 引用GraphAsset 可能关联到 EndpointworkloadDataModel.unfilteredEndpointsStorage.getObjectByID(endpointId)

关键理解

  • 这些关联都是通过 ID 引用,不是包含关系
  • 需要通过 ID 在对应的 storage 中查找实际对象
  • 允许同一个物理资源有多个维度的表示(配置、运行时、检测、问题等)

6. 工具类(非真实资源)

AssetSearchKeyObject

关系:不是真正的资源,只是序列化工具

  • 用于在 URL 或存储中传递 Asset Search Key
  • 不存储,仅用于传递和序列化
  • 可以转换为其他资源类型(如 GraphAsset

现实世界例子

  • 序列化的 Asset Search Key: s3://my-company-data-bucketarn:aws:ec2:us-east-1:123456789012:instance/i-123

7. 独立资源(无直接关系)

DetectionEndpointDetails

关系:独立的端点详情对象

  • 用于检测图模型
  • 与其他资源类型没有直接关系

现实世界例子

  • 攻击链中的端点:在检测图中,作为攻击路径一部分的端点

EndpointSearch

关系:独立的端点搜索对象

  • 用于 Secrets、Sensitive Data、API Security 等场景
  • 与其他资源类型没有直接关系
  • 可能是临时创建的(如 Cloud Scanners 扫描的资源)

现实世界例子

  • 暴露敏感数据的 Pod:在代码中硬编码了 AWS 凭证的 Pod
  • API Security 端点:有 SQL 注入漏洞的 API 端点

MonitoredResource

关系:独立的 Agent 监控资源

  • 代表安装了 Agent 的监控资源
  • 与其他资源类型没有直接关系

现实世界例子

  • 安装了 Agent 的 EC2 实例:i-1234567890abcdef0 - 运行 Upwind Agent 的 EC2 实例
  • 安装了 Agent 的 Auto Scaling Group:my-asg - 包含多个安装了 Agent 的实例的 ASG

关系总结表

关系类型资源对关系性质具体含义
互补(不同维度)GraphAsset ↔ WorkloadTreeStorage同一物理资源的不同维度表示GraphAsset 提供静态配置信息,WorkloadTreeStorage 提供运行时拓扑信息,两者互补,不能复用
包含(对象存储)WorkloadTreeStorage ⊃ Endpoint真正的包含关系,一对多WorkloadTreeStorage 内部存储 Endpoint 对象(通过 endpointIndex Map),一个 WorkloadTreeStorage 可以包含多个 Endpoint
引用(ID 关联)GraphAsset → EndpointID 引用,不包含对象,一对一GraphAsset 只存储 endpointId 字符串,需要通过 ID 在 storage 中查找 Endpoint,一个 GraphAsset 最多对应一个 Endpoint
引用(ID 关联)FindingResource → EndpointID 引用,不包含对象FindingResource 存储 endpointId/endpointRefId,表示配置问题针对某个 Endpoint,需要通过 ID 查找
引用(ID 关联)Resource → GraphAssetID/refId 引用,不包含对象Resource 和 GraphAsset 代表同一物理资源,Resource 通过 refId 引用 GraphAsset
分类(互斥)InventoryStorageAsset / InventoryNetworkAsset / InventoryComputeAsset同一概念的不同类型,互斥都是 Inventory 资产,但按类型分类(存储/网络/计算),一个资源只能是其中一种
分类(可能重叠)Resource / DetectionResource / FindingResource / VulnerableResource不同数据源,可能指向同一物理资源都代表"资源"概念,但来自不同 API,可能通过 resourceId/endpointId 关联到同一物理资源
工具类AssetSearchKeyObject序列化工具,非真实资源用于在 URL 或存储中传递 Asset Search Key,可以转换为其他资源类型
独立DetectionEndpointDetails / EndpointSearch / MonitoredResource与其他资源无直接关系独立的资源类型,用于特定场景(检测图、Secrets、Agent 监控)

关键理解:关系的整体逻辑

1. 数据源决定类型,用途决定共存

核心原则:同一个物理资源(如一个 EC2 实例)可能在不同数据源中有不同的表示

  • GraphAsset:来自 Graph 数据库,提供静态配置信息
  • WorkloadTreeStorage:来自 Workload API,提供运行时拓扑信息
  • FindingResource:来自 Posture API,提供配置问题信息
  • DetectionResource:来自 Detections API,提供威胁检测信息
  • VulnerableResource:来自 Vulnerabilities API,提供漏洞信息

为什么需要同时存在?

  • 它们提供不同维度的信息,互补而非替代
  • AssetDetailsSidePane 中,可以同时使用多个资源类型展示完整信息

2. 包含 vs 引用的关键区别

包含关系(真正的对象存储)

  • WorkloadTreeStorage ⊃ EndpointEndpoint 对象存储在 WorkloadTreeStorage 内部,一对多

引用关系(只是 ID 关联)

  • GraphAsset → Endpoint:只存储 endpointId 字符串,一对一
  • FindingResource → Endpoint:只存储 endpointId/endpointRefId 字符串
  • Resource → GraphAsset:只存储 refId 字符串

为什么需要引用而不是包含?

  • 避免数据重复:Endpoint 只存储一次,多个资源类型通过 ID 引用
  • 解耦:不同资源类型可以独立更新,不需要同步
  • 灵活性:可以根据需要查找关联的资源

3. 关联关系的实际含义

FindingResource → Endpoint

  • 含义:这个配置问题(Finding)是针对某个运行时端点(Endpoint)的
  • 使用:通过 endpointId 查找对应的 Endpoint,可以同时展示配置问题和运行时状态

Resource → GraphAsset

  • 含义:这个检测到的资源(Resource)和配置中的资源(GraphAsset)是同一个物理资源
  • 使用:通过 refId 查找对应的 GraphAsset,可以同时展示检测信息和配置信息

GraphAsset → Endpoint

  • 含义:这个配置资源(GraphAsset)可能关联到一个运行时端点(Endpoint)
  • 使用:通过 endpointId 查找对应的 Endpoint,可以同时展示配置和运行时信息

4. 数据获取流程示例

// 在 AssetDetailsSidePane 中的典型流程:

// 1. 获取 GraphAsset(静态配置)
const [asset] = useGraphAssetByIdOrRefId(orgId, graphId, refId);

// 2. 根据 GraphAsset 的属性决定是否获取 WorkloadTreeStorage(运行时拓扑)
if (asset?.getEndpointId()) {
  const [treeStorage] = useAssetTreeStorage(/* ... */);
  // treeStorage 内部包含 Endpoint 对象(一对多)
}

// 3. 如果需要,可以通过 ID 查找关联的资源
const endpointId = asset?.getEndpointId();
const endpoint = workloadDataModel.unfilteredEndpointsStorage.getObjectByID(endpointId);

// 4. 现在可以同时使用多个资源类型
// - asset (GraphAsset): 提供配置信息
// - treeStorage (WorkloadTreeStorage): 提供拓扑信息,包含多个 Endpoint
// - endpoint (Endpoint): 提供运行时端点信息(通过 GraphAsset 的 endpointId 查找)

5. 总结:为什么不能简单复用?

GraphAsset 和 WorkloadTreeStorage 不能复用的根本原因

  1. 数据来源不同:Graph Query API vs Workload API
  2. 数据结构不同:单个对象 vs 树形结构
  3. 时间维度不同:配置快照 vs 运行时状态(需要时间范围)
  4. 用途不同:展示配置信息 vs 展示拓扑关系
  5. 更新频率不同:配置相对稳定 vs 运行时状态实时变化

它们的关系是互补的,不是替代的

  • 需要配置信息 → 使用 GraphAsset
  • 需要拓扑信息 → 使用 WorkloadTreeStorage
  • 需要完整信息 → 同时使用两者

GraphAsset 和 Endpoint 是一对一,WorkloadTreeStorage 和 Endpoint 是一对多的原因

  • GraphAsset 代表单个资源,一个资源最多对应一个运行时端点
  • WorkloadTreeStorage 代表树形结构,一个树节点(如 Namespace)可以包含多个端点(多个 Pod)

文档生成时间: 2026-01-21 最后更新: 2026-01-21 (从 IUpwindResource_Complete_Reference.md 拆分)