IUpwindResource 之间的关系分析
本文档详细分析了所有 IUpwindResource 实现类之间的关系,包括继承关系、包含关系、引用关系、分类关系等。
相关文档: 查看 IUpwindResource_Complete_Reference.md 了解每个实现类的详细信息。
1. 继承关系(代码层面)
所有实现类都实现 IUpwindResource 接口,但彼此之间没有继承关系:
- 除了
WorkloadTreeStorage和AssetSearchKeyObject,其他类都继承自StorageObject WorkloadTreeStorage直接实现IUpwindResource,不继承StorageObjectAssetSearchKeyObject继承自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:为什么不能复用?
核心差异:它们代表同一物理资源的不同维度,数据来源、结构和用途完全不同
| 维度 | GraphAsset | WorkloadTreeStorage |
|---|---|---|
| 数据来源 | Graph Query API (inventory-api/search) | Workload API (clusters/workloadViewNew) |
| 数据性质 | 静态配置信息 | 运行时拓扑信息 |
| 代表内容 | 云资源的配置、标签、ARN、类型等 | 集群、命名空间、端点的层级关系和连接 |
| 时间维度 | 配置快照(无时间范围) | 运行时状态(需要时间范围 {from, to}) |
| 数据结构 | 单个资产对象 | 树形结构(Cluster → Namespace → Endpoint) |
| 主要用途 | 展示资产基本信息、配置详情 | 展示网络拓扑、连接关系、流量数据 |
为什么需要同时存在?
-
互补的信息:
GraphAsset提供:资源名称、类型、标签、ARN、区域、云账户等静态配置信息WorkloadTreeStorage提供:集群层级、命名空间、端点连接、网络流量等运行时拓扑信息
-
不同的使用场景:
- 查看资源配置 → 使用
GraphAsset - 查看网络拓扑 → 使用
WorkloadTreeStorage - 在
AssetDetailsSidePane中,两者同时使用:// GraphAsset 用于展示基本信息 <ResourceViewHeader resource={asset} graphAsset={asset} /> // WorkloadTreeStorage 用于展示网络拓扑标签页 <ResourceOverviewTabs treeStorage={treeStorage} resource={asset} />
- 查看资源配置 → 使用
-
数据获取流程:
// 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内部Endpoint是WorkloadTreeStorage树结构中的叶子节点- 一个
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 - 需要通过
endpointId在WorkloadDataModel.unfilteredEndpointsStorage中查找对应的Endpoint GraphAsset和Endpoint是独立的对象,通过 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:新检测系统中的资源(来自
detectionsAPI) - DetectionResource:检测/威胁资源(来自
detectionsAPI,旧系统) - FindingResource:Posture Findings 资源(来自
posture/findingsAPI) - VulnerableResource:漏洞资源(来自
vulnerabilitiesAPI)
可能的关系:
- 同一个物理资源(如一个 EC2 实例)可能同时有:
FindingResource(有配置问题)DetectionResource(有威胁检测)VulnerableResource(有漏洞)
- 它们通过
resourceId、endpointId等字段关联到同一个资源 FindingResource有endpointId和endpointRefId字段,可以关联到Endpoint
现实世界例子:
- 同一个 EC2 实例
i-1234567890abcdef0可能同时有:FindingResource: Security Group 配置问题DetectionResource: 检测到异常网络活动VulnerableResource: 运行有漏洞的 Docker 镜像
5. 关联关系(通过 ID 引用,不包含对象)
FindingResource → Endpoint(通过 ID 引用)
关系:FindingResource 通过 endpointId 和 endpointRefId 引用 Endpoint,但不包含它
endpointId vs endpointRefId 的区别:
| 字段 | 类型 | 含义 | 用途 |
|---|---|---|---|
| endpointId | string | Endpoint 在 Workload 系统中的 ID | 直接在 WorkloadDataModel.unfilteredEndpointsStorage 中查找 Endpoint 对象 |
| endpointRefId | string | Endpoint 的 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);
}
具体含义:
FindingResource有endpointId?: string和endpointRefId?: 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 通过 refId 和 resourceId 引用 GraphAsset,表示同一个物理资源
具体含义:
Resource有refId?: string和resourceId?: 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来自新检测系统(detectionsAPI),表示检测到的资源GraphAsset来自 Graph 数据库,表示配置中的资源- 同一个物理资源可能同时有:
- 配置信息(GraphAsset)
- 检测信息(Resource)
- 通过
refId关联,可以同时展示配置和检测信息
GraphAsset → Endpoint(通过 endpointId 引用)
关系:GraphAsset 通过 endpointId 引用 Endpoint,表示配置资源可能关联到运行时端点
具体含义:
GraphAsset有private endpointId: string字段- 这只是一个 ID 字符串,不是
Endpoint对象 - 含义:这个配置资源(GraphAsset)可能关联到一个运行时端点(Endpoint)
- 需要通过
endpointId在WorkloadDataModel.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 → Endpoint | ID 引用 | Finding 针对某个 Endpoint | workloadDataModel.unfilteredEndpointsStorage.getObjectByID(endpointId) |
| Resource → GraphAsset | ID/refId 引用 | 同一物理资源的不同表示 | graphAssetStorage.getObjectByID(refId) 或通过 useGraphAssetByIdOrRefId |
| GraphAsset → Endpoint | ID 引用 | GraphAsset 可能关联到 Endpoint | workloadDataModel.unfilteredEndpointsStorage.getObjectByID(endpointId) |
关键理解:
- 这些关联都是通过 ID 引用,不是包含关系
- 需要通过 ID 在对应的 storage 中查找实际对象
- 允许同一个物理资源有多个维度的表示(配置、运行时、检测、问题等)
6. 工具类(非真实资源)
AssetSearchKeyObject
关系:不是真正的资源,只是序列化工具
- 用于在 URL 或存储中传递 Asset Search Key
- 不存储,仅用于传递和序列化
- 可以转换为其他资源类型(如
GraphAsset)
现实世界例子:
- 序列化的 Asset Search Key:
s3://my-company-data-bucket或arn: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 → Endpoint | ID 引用,不包含对象,一对一 | GraphAsset 只存储 endpointId 字符串,需要通过 ID 在 storage 中查找 Endpoint,一个 GraphAsset 最多对应一个 Endpoint |
| 引用(ID 关联) | FindingResource → Endpoint | ID 引用,不包含对象 | FindingResource 存储 endpointId/endpointRefId,表示配置问题针对某个 Endpoint,需要通过 ID 查找 |
| 引用(ID 关联) | Resource → GraphAsset | ID/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 ⊃ Endpoint:Endpoint对象存储在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 不能复用的根本原因:
- 数据来源不同:Graph Query API vs Workload API
- 数据结构不同:单个对象 vs 树形结构
- 时间维度不同:配置快照 vs 运行时状态(需要时间范围)
- 用途不同:展示配置信息 vs 展示拓扑关系
- 更新频率不同:配置相对稳定 vs 运行时状态实时变化
它们的关系是互补的,不是替代的:
- 需要配置信息 → 使用
GraphAsset - 需要拓扑信息 → 使用
WorkloadTreeStorage - 需要完整信息 → 同时使用两者
GraphAsset 和 Endpoint 是一对一,WorkloadTreeStorage 和 Endpoint 是一对多的原因:
- GraphAsset 代表单个资源,一个资源最多对应一个运行时端点
- WorkloadTreeStorage 代表树形结构,一个树节点(如 Namespace)可以包含多个端点(多个 Pod)
文档生成时间: 2026-01-21 最后更新: 2026-01-21 (从 IUpwindResource_Complete_Reference.md 拆分)