3、数据资产发现:云上数据源自动发现
做DSPM第一步是什么?我个人习惯先搞定“资产清单”。连自己有多少数据桶、数据库、集群都不知道,后续的安全策略就是盲打。这一节我们就聊聊怎么在混合云里自动摸清家底,而且不装Agent——也就是所谓的无代理扫描。
核心一句话: 无代理扫描 = 通过云厂商API + 网络探测 + 元数据解析,拿到数据源的“身份证”。
3.1 云上数据源有哪些?
混合云环境里,数据源通常分三类:
- 对象存储 —— AWS S3、阿里云OSS、华为OBS、腾讯COS,还有MinIO这种私有化部署的。
- 关系型/非关系型数据库 —— RDS(MySQL、PostgreSQL)、自建数据库、Redis、MongoDB、DynamoDB等。
- 大数据平台 —— EMR、Hive、Spark、ClickHouse、Snowflake……还有云原生数据湖(如AWS Lake Formation)。
你想想看,如果每个云账号下有几十个桶、上百个DB实例,手工点一遍根本不可能。我在一个金融客户项目里遇到过,对方有8个AWS账号、3个阿里云账号,对象存储总数超过2000个桶。没有自动发现,光资产登记就做了两个月。
3.2 无代理扫描是怎么工作的?
说白了,无代理扫描就是“只看不碰”。它不会在你的虚拟机或容器里装任何agent,而是换个思路:用云平台的API把元数据拉回来。
- 身份与权限对接 —— 用只读角色或服务账号对接云厂商的IAM/STS。
- 调用列举接口 —— 例如ListBuckets、DescribeDBInstances、ListClusters。
- 解析返回的元数据 —— 获取名称、区域、大小、ACL、标签、创建时间等。
- 补充网络探测 —— 有些自建实例没有暴露API,可以通过端口扫描、DNS解析、云VPC流日志来发现。
- 归一化资产指纹 —— 把不同云的字段统一成标准资产模型。
曾经踩过的坑: 我曾以为只要API权限够就行,结果在某个客户环境里,AWS S3的ListBuckets只能列出桶名,但桶内对象的ACL和加密信息需要额外调用GetBucketPolicy。后来我改成递归调用Describe*接口,才补全了敏感字段。
3.3 对象存储自动发现实操
不同云的对象存储API长得像,但细节不同。我们拿AWS S3和阿里云OSS做个对比。
| 能力 | AWS S3 | 阿里云 OSS |
|---|---|---|
| 列举所有桶 | s3.list_buckets() |
oss.list_buckets() |
| 获取桶ACL | s3.get_bucket_acl(Bucket=...) |
oss.get_bucket_acl(bucket_name=...) |
| 桶内对象列表 | s3.list_objects_v2(Bucket=...) |
oss.list_objects(bucket_name=...) |
| 版本控制状态 | s3.get_bucket_versioning(Bucket=...) |
通过BucketPolicy判断 |
小技巧: 我习惯把不同云厂商的API调用封装成统一接口类,输出一个标准的“资产记录”:
{cloud_provider, region, name, type, created_at, owner, access_level, encryption_status}。这样后续分析策略就不用关心底层云了。
3.4 数据库与大数据平台发现
数据库的发现稍微复杂些,因为有些是云托管实例(RDS),有些是自己部署在ECS上的。无代理扫描没法连进数据库执行SQL,而是靠以下方式:
- RDS类实例 —— 调用DescribeDBInstances,拿VPC、端口、引擎类型、存储大小、备份状态。
- 自建数据库 —— 先通过云VPC的ip scan探测端口开放(3306, 5432, 6379等),再用DNS反向解析或标签推测归属。
- 大数据组件 —— EMR调用ListClusters,Hive通过MetaStore API获取Table列表,Spark通过History Server暴露的REST接口。
# 伪代码示例:统一资产发现引擎
def discover_all(cloud_accounts):
assets = []
for account in cloud_accounts:
# 对象存储
for bucket in account.s3.list_buckets():
assets.append(Asset(
type='object_storage',
name=bucket.name,
region=account.region,
tags=bucket.tags
))
# RDS
for instance in account.rds.describe_instances():
assets.append(Asset(
type='rds',
engine=instance.engine,
endpoint=instance.endpoint,
...
))
# EMR集群
for cluster in account.emr.list_clusters():
assets.append(Asset(
type='emr',
cluster_id=cluster.id,
applications=cluster.applications
))
return assets
3.5 资产指纹的归一与去重
你会发现,同一个资产可能在不同API里重复出现。比如RDS实例既有EC2标签,又有RDS标签。我记得有一次调试时,一个MySQL实例被扫出两份记录,因为从EC2和RDS两个维度都发现了它。解决办法是用ARN或抽象资源ID作为唯一键。
- 对象存储:
arn:aws:s3:::bucket-name或oss://bucket-name - 数据库实例:
arn:aws:rds:region:account:db:instance-name - EMR集群:
arn:aws:elasticmapreduce:region:account:cluster/j-xxxx
曾经踩过的坑: 有个客户用多个云账号,不同region的资产名恰巧一样。我用
名称+Region作为主键,后来发现跨region复制会生成同名对象。最终改用云账号ID + Region + 内部ID才搞定去重。
3.6 扫描频率与增量更新
全量扫描很费时(尤其是上千个桶),所以我建议这样:
- 首次部署先全量扫一次,生成基线资产库。
- 之后用事件驱动增量更新 —— 监听CloudTrail/ActionTrail日志,发现CreateBucket、CreateDBInstance就自动触发扫。
- 如果没有event支持,那就每天1~2次增量扫描(只扫最近24小时内创建或修改过的资源)。
避坑: 别把全量扫描直接放生产业务高峰期。我曾经让定时任务在每天凌晨1点跑,结果某个客户刚好在那个时间做备份,API限流了。后来改成错峰执行。
3.7 无代理扫描的权限最小化
你给的只读角色应该只包含必要的权限。下面是一个最小权限示例(AWS IAM):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation",
"s3:GetBucketAcl",
"s3:GetBucketVersioning",
"rds:DescribeDBInstances",
"rds:DescribeDBClusters",
"elasticmapreduce:ListClusters",
"elasticmapreduce:DescribeCluster"
],
"Resource": "*"
}
]
}
嗯,这里要注意ListAllMyBuckets必须放*,其他可以通过条件限制region。我在交付时都会跟客户过一遍这个json,确保不会误给写权限。
核心观点: 资产发现不是一次性工作,它是一个持续不断地“拉” + “听” + “查”的闭环。无代理扫描是起点,但后面的分级、标记、风险分析全靠这张资产地图。
有了准确的数据资产清单,后面我们才能做敏感数据分类、权限分析和风险评级。别着急,一步步来。