云环境资产发现(AWS/Azure/GCP)
我最早接触云资产发现时,是在一次多云环境整合项目里。客户把一批核心应用分散在三家云上,团队说「我们都有资产清单」。结果一审计,AWS 上挂着 3 台没人用的红移集群,Azure 那边躺了一堆孤立的函数应用,GCP 的存储桶权限直接对公网开放。
你看,没有统一的资产发现,安全就是个笑话。DSPM 的第一步,就是把云上到底跑着什么、存着什么、怎么连的,全给翻出来。
一、为什么云环境资产发现更棘手?
传统 IDC 里资产是固定的——IP、机柜、端口,你写个 CMDB 就能管个七七八八。云上不一样。一个人用控制台点几下,一台 EC2 就出来了,30 秒后又删了。嗯,这就是云资产的第一个特性:动态性。
我把云资产发现的难点总结成 3 点:
- API 驱动:所有操作都靠 API。DSPM 必须通过云厂商 API 去拉数据,不能指望人工录入。
- 资源种类爆炸:十年前你只需要管虚机和数据库。现在有 S3 桶、Lambda 函数、托管 K8s、消息队列、数据湖……每类资源都有自己的元数据。
- 权限网络复杂:同一个账号下,IAM 角色、策略、VPC 流日志、安全组、KMS 密钥全部纠缠在一起。你发现一个存储桶,不一定能找到「谁通过什么路径在访问它」。
我当时就踩过一个坑:只拉 AWS EC2 列表,没拉安全组和网络 ACL。结果客户的数据泄露事件发生在 S3 上,EC2 那页清单一丁点线索都没有。
二、三大云平台的资产发现策略
AWS、Azure、GCP 虽然都是云,但 API 设计哲学完全不同。我习惯从三个维度去拆:计算、存储、网络。
| 维度 | AWS | Azure | GCP |
|---|---|---|---|
| 计算 | EC2、ECS、EKS、Lambda | VM、AKS、Functions | GCE、GKE、Cloud Run |
| 存储 | S3、EBS、RDS、DynamoDB | Blob、Disk、SQL DB、Cosmos DB | GCS、Persistent Disk、Cloud SQL、Firestore |
| 网络/权限 | VPC、Security Group、IAM | VNet、NSG、RBAC | VPC、Firewall Rules、IAM |
| 发现入口 API | ec2:DescribeInstances, s3:ListBuckets | az vm list, az storage account list | gcloud compute instances list, gsutil ls |
| 分页限制 | 单次 1000 条,需 NextToken | 20 条/页,需 continuation_ | 单次 500 条,需 pageToken |
| 跨账号 | 通过 Organizations + AssumeRole | 通过 Management Group + Lighthouse | 通过 Resource Manager + 聚合视图 |
你看,API 名称完全不同,但逻辑是相通的。关键是你得知道每家云的「资源树」怎么遍历。我个人习惯按这张图去规划发现流程:
三、AWS 资产发现实战要点
AWS 的 API 是我用过最全的,几乎可以拉到每一条资源的全部元数据。但有一个问题:API 调用频次限制。我曾在项目中一次性拉 5 个账号的 10 个区域的全量资源,结果触发了 DescribeInstances 的限流(每区域每秒 100 次)。
这么做可以降低风险:
- 按服务分区拉取,比如先拉 EC2,再拉 S3,不要并发拉所有。
- 使用
NextToken循环拉取,单次最多 1000 条。 - 对 Lambda 和 RDS 等低频资源,降低轮询频率。
我个人的建议:先通过 AWS Organizations 列出所有成员账号,再用 AssumeRole 切换到每个账号。否则你光是在主账号里拉,子账号的 S3 桶一个都看不到。
# 伪代码:AWS 全账号资产发现
accounts = list_accounts() # 通过 Organizations API
for acct in accounts:
role = assume_role(acct.id, 'DSPMDiscoveryRole')
# 拉计算
ec2_list = ec2_client.describe_instances(MaxResults=1000)
while True:
# 处理 NextToken
...
# 拉存储
buckets = s3_client.list_buckets()
for b in buckets:
# 检查公共权限
acl = s3_client.get_bucket_acl(Bucket=b['Name'])
# 拉网络
sgs = ec2_client.describe_security_groups()
我曾经遇到过:某些废弃的 EC2 实例在 DescribeInstances 里返回了,但 DescribeInstanceStatus 返回 terminated。如果只拉列表不校验状态,资产清单里就会多一堆死资源。
四、Azure 资产发现实战要点
Azure 的 API 设计跟 AWS 区别很大。最大的坑是:资源分类层级复杂——订阅(Subscription)→资源组(Resource Group)→资源。拉一个虚拟机,你得先知道它在哪个资源组下面。
我的做法是先用 az account list 拿到所有订阅,然后用 az resource list 拉资源组,最后逐个资源组去拉 VM、Blob 等。
# Azure 资产发现示例(Python SDK)
from azure.identity import DefaultAzureCredential
from azure.mgmt.resource import ResourceManagementClient
credential = DefaultAzureCredential()
subscriptions = list(credential.list_subscriptions())
for sub in subscriptions:
client = ResourceManagementClient(credential, sub.subscription_id)
# 列出所有资源
resources = client.resources.list()
for r in resources:
if r.type == 'Microsoft.Compute/virtualMachines':
# 拉 VM 详情
vm = client.virtual_machines.get(r.resource_group, r.name)
elif r.type == 'Microsoft.Storage/storageAccounts':
# 检查 Blob 公开访问
...
另外,Azure 的 RBAC 权限检查不是靠 API 直接返回的。你得调用 role assignments API 才能看到谁有什么角色。嗯,这是跟 AWS IAM 最大的区别。
五、GCP 资产发现实战要点
GCP 的资产发现相对简洁。它的资源模型是:项目(Project)→区域(Region)→资源。API 调用时,通常需要指定 --project 参数。
我建议你用 asset inventory API,它是 GCP 官方的资产清单服务,能一次性拉出项目内的所有资源。不过要注意,这个 API 有 7 天缓存,新创建的资源可能要等几分钟才能被扫到。
# 使用 gcloud CLI 预处理
gcloud asset list \
--project=my-project \
--asset-types="compute.googleapis.com/Instance,storage.googleapis.com/Bucket" \
--content-type=resource \
--format=json
# API 调用示例(Python)
from google.cloud import asset_v1
client = asset_v1.AssetServiceClient()
request = {
"parent": "projects/my-project",
"content_type": "RESOURCE",
"asset_types": ["compute.googleapis.com/Instance"]
}
response = client.list_assets(request)
for asset in response:
print(asset.name)
关键差距:GCP 的存储桶默认是公开的?不对。GCP 的权限模型是统一 IAM,没有独立的桶 ACL(除非你开启 FM 模式)。所以拉 GCS 桶时,必须同时拉它绑定的 IAM 策略,否则你判断不了对象是否可公开访问。
六、统一资产发现框架的设计思路
你不可能为每家云写一套完全独立的发现引擎。我接过一个活儿,需要同时扫 AWS 和 Azure,当时我设计了一个统一的 Provider 接口:
- 定义抽象类:包含
discover_compute()、discover_storage()、discover_network()三个方法。 - 每个云实现一个具体类:内部处理各自的 API 分页、限流、凭证管理。
- 统一输出资产对象:不管来自 AWS 还是 GCP,最终输出相同的
Asset结构(包括 ID、类型、区域、标签、关联的 IAM、网络策略)。
这样做的好处是,后续的接口测绘、敏感数据扫描都只需要面向这个统一的资产模型,不用再关心底层是哪个云。
| 抽象方法 | AWS 实现 | <GCP 实现 | |
|---|---|---|---|
discover_compute() |
DescribeInstances + DescribeAutoScalingGroups | VirtualMachines.list + instance group.list | Instances.list |
discover_storage() |
ListBuckets + DescribeRDSInstances | BlobAccounts.list + CosmosDB.list | Buckets.list + SQLInstances.list |
discover_network() |
DescribeSecurityGroups + DescribeVpcs | NetworkSecurityGroups.list + VirtualNetworks.list | Firewalls.list + Vpc.list |
| 凭证处理 | AssumeRole + IAM User | Service Principal + Managed Identity | Service Account + Workload Identity |
七、避坑指南与经验总结
做了这么多项目,我总结了几条云资产发现必须注意的「事故高发区」:
- 跨区域遗漏:AWS 有 30+ 区域,Azure 有 60+ 区域。很多团队只扫了 default 区域,结果数据泄漏发生在 ap-southeast-1。
- 非标准资源:比如 AWS 的
aws:elasticbeanstalk不是标准 EC2 资源,你用 DescribeInstances 扫不到。得额外调用 Elastic Beanstalk 的 API。 - 对象级别的权限:拉 S3 桶的 ACL 很容易,但桶内每个对象的 Bucket Policy 不一定能通过一次 API 拿到。你有时需要模拟访问。
- 频率限制:GCP 的有限配额是每 100 秒 1000 次 API 调用。如果项目很多,必须设计退避算法(exponential backoff)。
我曾经在 Azure 上遇到过:订阅本身没有关联任何资源组,但 Resource API 返回了空列表。我当时以为这个账号没问题,后来发现客户把生产资源藏在另一个订阅下。所以资产管理的第一原则永远是:全量发现,不要相信「默认」。
好了,云环境资产发现的框架和实操要点基本就是这些。你可以基于这个思路,在 DSPM 资产发现引擎 模块里搭一个统一的 Provider 层。代码不用多,关键是搞清楚每种云 API 的逻辑差异,然后设计好重试、去重和关联规则。