Google Cloud Asset Inventory 提供基于时序数据库的库存服务。此数据库会将 Google Cloud 资产元数据保留五周时间。借助 Cloud Asset Inventory,您可以:

  • 使用自定义查询语言搜索资产元数据

  • 导出特定时间戳的所有资产元数据,或导出特定时间范围内的活动更改历史记录

  • 通过订阅实时通知来监控资产变化

  • 分析 IAM 政策以了解谁能够访问什么

用户可以操作 Asset Inventory 将某一时刻的选中的云资源的属性状态到处到 BigQuery,进行查看分析,相当于一个资源快照。但是快照之间的状态变更无法获知。

为了更全面地了解各种资源的变更情况,我们可以为 Asset Inventory 配置一个 Feed 流,将这个 Feed 流导入到消息队列 Pub/Sub,然后利用 Pub/Sub 的 BigQuery 类型 Subscription,将 Feed 流实时导入到 BigQuery 表格。这样就可以在 BigQuery 里实时查看和分析变更情况了。

同时我们还可以结合将审计日志等数据也输出到 BigQuery,综合查询资源变更和用户操作的时序和因果关系。如下图所示。

下面的步骤介绍如何配置这一数据实时流转和导出。加量的代码都是在 Terminal 或者 Cloud Shell执行的 Google Cloud SDK CLI 命令。

首先,将需要用到的 Asset Inventory, Pub/Sub, BigQuery 等服务在当前项目里打开。

PROJECT_ID=$(gcloud config get-value project)

PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(project_number)")

gcloud services enable cloudasset.googleapis.com pubsub.googleapis.com bigquery.googleapis.com --project ${PROJECT_ID}

创建一个 Pub/Sub Topic 来用于接收 Asset Inventory 的 Feed。

TOPIC_NAME="asset-changes"

gcloud pubsub topics create "${TOPIC_NAME}" --project ${PROJECT_ID}

为 Asset Inventory 打开服务身份功能,这样会创建一个专用的服务账号,用于为 Asset Inventory 配置需要的权限来将数据写入其它服务,比如 Pub/Sub。

gcloud beta services identity create --service=cloudasset.googleapis.com --project=${PROJECT_ID}

gcloud pubsub topics add-iam-policy-binding "${TOPIC_NAME}" --member "serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-cloudasset.iam.gserviceaccount.com" --role roles/pubsub.publisher --project ${PROJECT_ID}

创建一个 Asset Inventory 的变更流 Feed,用于导出 GCE、GKE 和 GCS 的资源变更,写入到刚刚创建的 Pub/Sub 的 Topic。并在创建完后验证 Feed 创建成功。

ASSET_TYPES="compute.googleapis.com/Instance,container.googleapis.com/Cluster,storage.googleapis.com/Bucket"

gcloud asset feeds create "feed-resources-${PROJECT_ID}" --project="${PROJECT_ID}" --content-type=resource --asset-types="${ASSET_TYPES}" --pubsub-topic="projects/${PROJECT_ID}/topics/${TOPIC_NAME}" --billing-project ${PROJECT_ID}

gcloud asset feeds list --project ${PROJECT_ID} --format="flattened(feeds[].name)" --billing-project ${PROJECT_ID}

创建一个新的 BigQuery 表,用于接收 Pub/Sub 转交的 Asset Inventory 的变更流。注意 Feed 数据的 Schema 比较复杂,而且可能会有变化。因此我们创建表时不为表设置与 Pub/Sub 消息格式一一对应的 Schema,而是给表一个 JSON 类型的 data 字段,用于接收消息的完整正文。

bq mk --table youzhi_lab.asset-changes \\
subscription_name:STRING,message_id:STRING,publish_time:TIMESTAMP,data:JSON,attributes:JSON

为 Pub/Sub对应的服务账号添加 IAM 角色,让其可以查看 BigQuery 的元数据,并往 BigQuery 里写数据。

gcloud projects add-iam-policy-binding ${PROJECT_ID} --member="serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com" --role="roles/bigquery.dataEditor"

gcloud projects add-iam-policy-binding ${PROJECT_ID} --member="serviceAccount:service-${PROJECT_NUMBER}@gcp-sa-pubsub.iam.gserviceaccount.com" --role="roles/bigquery.metadataViewer"

为上面接收 Asset Inventory 变更流的 Pub/Sub 的 Topic 创建一个直接导出到 BigQuery 的 Subscription。这个 Subscription 会自动把所有的 Asset Inventory 通知消息实时并流式地插入到上面创建的 BigQuery 表中。

SUBSCRIPTION_NAME="asset-changes-subscription-to-bq"

DATASET_ID="youzhi-lab"

TABLE_ID="asset-changes"

gcloud pubsub subscriptions create "${SUBSCRIPTION_NAME}" \\
  --topic="projects/${PROJECT_ID}/topics/${TOPIC_NAME}" \\
  --bigquery-table="${PROJECT_ID}:${DATASET_ID}.${TABLE_ID}" \\
  --write-metadata

现在我们做一些 GCE 虚机相关的操作,比如创建一台虚机,然后删除它。这个操作可以在控制台或者命令行里执行,这里略过。

之后我们可以在 Pub/Sub 的监控中看到队列收到了通知消息。另外在 BigQuery 表中也可以看到新插入的数据。

我们可以用下面的查询,来列表虚机资源的状态变化。因为 data 列是 JSON 类型,可以比较方便地实用点操作符来引用相应的 JSON 字段。另外也可以将其转换成 STRING 或者 TIMESTAMP 类型来使用更多的函数操作。

SELECT

REGEXP_EXTRACT(STRING(data.asset.name), r'/([a-zA-Z0-9-_.]+$)') AS asset_name,

TIMESTAMP(STRING(data.asset.updateTime)) as update_time,

data.asset.resource.data.status as status,

data.asset.resource.data.fingerprint as fingerprint

FROM `youzhi-lab.youzhi_lab.asset-changes` ORDER BY update_time DESC LIMIT 1000

输出结果如下。

上面是针对资源变更通知信息这个单一数据做的简单分析。下面我们可结合 GCE 虚机操作的审计日志做综合分析。首先要配置审计日志导出到 BigQuery。在日志服务的路由规则里配置创建一个新的 Sink。

Sink 的配置如下所示。为了查询方便可以将目的表设置为与 Asset Inventory 消息表所在的同一个数据集下面。

导出的日志项包含以下日志内容。

LOG_ID("cloudaudit.googleapis.com/activity") OR LOG_ID("externalaudit.googleapis.com/activity") OR LOG_ID("cloudaudit.googleapis.com/system_event") OR LOG_ID("externalaudit.googleapis.com/system_event") OR LOG_ID("cloudaudit.googleapis.com/access_transparency") OR LOG_ID("externalaudit.googleapis.com/access_transparency")

创建完成后,可以看到在指定数据集下面生成了一个审计日志表。这是一个按天拆分的表。

我们可以用下面的 SQL 命令关于某台虚机的操作日志以及资源变更日志,并按其时间戳进行排序,来分析资源变更与管理员操作的先后顺序和因果关系。WITH raw AS (

 SELECT

 REGEXP_EXTRACT(STRING(data.asset.name), r'/([a-zA-Z0-9-_.]+$)') AS asset_name,

 TIMESTAMP(STRING(data.asset.updateTime)) AS update_time,

 data.asset.resource.data.status AS status,

 data.asset.resource.data.fingerprint AS fingerprint,

 NULL AS principalEmail,

 NULL AS methodName

 FROM `youzhi-lab.youzhi_lab.asset-changes`

 WHERE JSON_VALUE(data.asset.name) LIKE '%instance-44444'

 UNION ALL

 SELECT REGEXP_EXTRACT(t_audit.protopayload_auditlog.resourceName, r'/([a-zA-Z0-9-_.]+$)') AS asset_name,

 t_audit.timestamp AS update_time,

 NULL AS status,

 NULL AS fingerprint,

 t_audit.protopayload_auditlog.authenticationInfo.principalEmail AS principalEmail,

 t_audit.protopayload_auditlog.methodName AS methodName

 FROM `youzhi-lab.youzhi_lab.cloudaudit_googleapis_com_activity_*` AS t_audit

 WHERE t_audit.protopayload_auditlog.resourceName LIKE '%instance-44444')

SELECT * FROM raw ORDER BY update_time

输出的结果如下

可以从结果里看到,虚机资源的 Provisioning, Staging, Running 等状态变化是在虚机创建的insert操作之后,而 Stopping 状态变更是在 delete 操作之后。同时我们也可以看到每个操作的执行人员账号。

附件

  1. 基于 Asset Inventory 的实时通知为新建资源创建标签的方案

  2. Asset Inventory 中 GCE 资源变更消息含有的 JSON 字段列表

  • asset.ancestors[0]

  • asset.ancestors[1]

  • asset.assetType

  • asset.name

  • asset.resource.data.allocationAffinity.consumeAllocationType

  • asset.resource.data.canIpForward

  • asset.resource.data.confidentialInstanceConfig.enableConfidentialCompute

  • asset.resource.data.cpuPlatform

  • asset.resource.data.creationTimestamp

  • asset.resource.data.deletionProtection

  • asset.resource.data.description

  • asset.resource.data.disks[0].architecture

  • asset.resource.data.disks[0].autoDelete

  • asset.resource.data.disks[0].boot

  • asset.resource.data.disks[0].deviceName

  • asset.resource.data.disks[0].diskSizeGb

  • asset.resource.data.disks[0].guestOsFeatures[0].type

  • asset.resource.data.disks[0].guestOsFeatures[1].type

  • asset.resource.data.disks[0].guestOsFeatures[2].type

  • asset.resource.data.disks[0].index

  • asset.resource.data.disks[0].interface

  • asset.resource.data.disks[0].licenses[0]

  • asset.resource.data.disks[0].mode

  • asset.resource.data.disks[0].source

  • asset.resource.data.disks[0].type

  • asset.resource.data.displayDevice.enableDisplay

  • asset.resource.data.fingerprint

  • asset.resource.data.id

  • asset.resource.data.keyRevocationActionType

  • asset.resource.data.labelFingerprint

  • asset.resource.data.lastStartTimestamp

  • asset.resource.data.machineType

  • asset.resource.data.name

  • asset.resource.data.networkInterfaces[0].accessConfigs[0].name

  • asset.resource.data.networkInterfaces[0].accessConfigs[0].natIP

  • asset.resource.data.networkInterfaces[0].accessConfigs[0].networkTier

  • asset.resource.data.networkInterfaces[0].accessConfigs[0].type

  • asset.resource.data.networkInterfaces[0].fingerprint

  • asset.resource.data.networkInterfaces[0].name

  • asset.resource.data.networkInterfaces[0].network

  • asset.resource.data.networkInterfaces[0].networkIP

  • asset.resource.data.networkInterfaces[0].stackType

  • asset.resource.data.networkInterfaces[0].subnetwork

  • asset.resource.data.reservationAffinity.consumeReservationType

  • asset.resource.data.scheduling.automaticRestart

  • asset.resource.data.scheduling.onHostMaintenance

  • asset.resource.data.scheduling.preemptible

  • asset.resource.data.scheduling.provisioningModel

  • asset.resource.data.selfLink

  • asset.resource.data.serviceAccounts[0].email

  • asset.resource.data.serviceAccounts[0].scopes[0]

  • asset.resource.data.serviceAccounts[0].scopes[1]

  • asset.resource.data.serviceAccounts[0].scopes[2]

  • asset.resource.data.serviceAccounts[0].scopes[3]

  • asset.resource.data.serviceAccounts[0].scopes[4]

  • asset.resource.data.serviceAccounts[0].scopes[5]

  • asset.resource.data.shieldedInstanceConfig.enableIntegrityMonitoring

  • asset.resource.data.shieldedInstanceConfig.enableSecureBoot

  • asset.resource.data.shieldedInstanceConfig.enableVtpm

  • asset.resource.data.shieldedInstanceIntegrityPolicy.updateAutoLearnPolicy

  • asset.resource.data.startRestricted

  • asset.resource.data.status

  • asset.resource.data.tags.fingerprint

  • asset.resource.data.zone

  • asset.resource.discoveryDocumentUri

  • asset.resource.discoveryName

  • asset.resource.location

  • asset.resource.parent

  • asset.resource.version

  • asset.updateTime

  • priorAsset.ancestors[0]

  • priorAsset.ancestors[1]

  • priorAsset.assetType

  • priorAsset.name

  • priorAsset.resource.data.allocationAffinity.consumeAllocationType

  • priorAsset.resource.data.canIpForward

  • priorAsset.resource.data.confidentialInstanceConfig.enableConfidentialCompute

  • priorAsset.resource.data.cpuPlatform

  • priorAsset.resource.data.creationTimestamp

  • priorAsset.resource.data.deletionProtection

  • priorAsset.resource.data.description

  • priorAsset.resource.data.disks[0].architecture

  • priorAsset.resource.data.disks[0].autoDelete

  • priorAsset.resource.data.disks[0].boot

  • priorAsset.resource.data.disks[0].deviceName

  • priorAsset.resource.data.disks[0].diskSizeGb

  • priorAsset.resource.data.disks[0].guestOsFeatures[0].type

  • priorAsset.resource.data.disks[0].guestOsFeatures[1].type

  • priorAsset.resource.data.disks[0].guestOsFeatures[2].type

  • priorAsset.resource.data.disks[0].index

  • priorAsset.resource.data.disks[0].interface

  • priorAsset.resource.data.disks[0].licenses[0]

  • priorAsset.resource.data.disks[0].mode

  • priorAsset.resource.data.disks[0].source

  • priorAsset.resource.data.disks[0].type

  • priorAsset.resource.data.displayDevice.enableDisplay

  • priorAsset.resource.data.fingerprint

  • priorAsset.resource.data.id

  • priorAsset.resource.data.keyRevocationActionType

  • priorAsset.resource.data.labelFingerprint

  • priorAsset.resource.data.lastStartTimestamp

  • priorAsset.resource.data.machineType

  • priorAsset.resource.data.name

  • priorAsset.resource.data.networkInterfaces[0].accessConfigs[0].name

  • priorAsset.resource.data.networkInterfaces[0].accessConfigs[0].natIP

  • priorAsset.resource.data.networkInterfaces[0].accessConfigs[0].networkTier

  • priorAsset.resource.data.networkInterfaces[0].accessConfigs[0].type

  • priorAsset.resource.data.networkInterfaces[0].fingerprint

  • priorAsset.resource.data.networkInterfaces[0].name

  • priorAsset.resource.data.networkInterfaces[0].network

  • priorAsset.resource.data.networkInterfaces[0].networkIP

  • priorAsset.resource.data.networkInterfaces[0].stackType

  • priorAsset.resource.data.networkInterfaces[0].subnetwork

  • priorAsset.resource.data.reservationAffinity.consumeReservationType

  • priorAsset.resource.data.scheduling.automaticRestart

  • priorAsset.resource.data.scheduling.onHostMaintenance

  • priorAsset.resource.data.scheduling.preemptible

  • priorAsset.resource.data.scheduling.provisioningModel

  • priorAsset.resource.data.selfLink

  • priorAsset.resource.data.serviceAccounts[0].email

  • priorAsset.resource.data.serviceAccounts[0].scopes[0]

  • priorAsset.resource.data.serviceAccounts[0].scopes[1]

  • priorAsset.resource.data.serviceAccounts[0].scopes[2]

  • priorAsset.resource.data.serviceAccounts[0].scopes[3]

  • priorAsset.resource.data.serviceAccounts[0].scopes[4]

  • priorAsset.resource.data.serviceAccounts[0].scopes[5]

  • priorAsset.resource.data.shieldedInstanceConfig.enableIntegrityMonitoring

  • priorAsset.resource.data.shieldedInstanceConfig.enableSecureBoot

  • priorAsset.resource.data.shieldedInstanceConfig.enableVtpm

  • priorAsset.resource.data.shieldedInstanceIntegrityPolicy.updateAutoLearnPolicy

  • priorAsset.resource.data.startRestricted

  • priorAsset.resource.data.status

  • priorAsset.resource.data.tags.fingerprint

  • priorAsset.resource.data.zone

  • priorAsset.resource.discoveryDocumentUri

  • priorAsset.resource.discoveryName

  • priorAsset.resource.location

  • priorAsset.resource.parent

  • priorAsset.resource.version

  • priorAsset.updateTime

  • priorAssetState

  • window.startTime


相关推荐