关于 investigating-gcp-incidents
用于调查 GCP 项目和组织中疑似安全事件的技能,重点检查审计日志的可见性、还原主体与服务账号活动,并区分日志缺失和未发生访问的证据。
主要功能
- 01检查审计日志类别与保留期限
- 02还原跨项目的主体活动
- 03追踪服务账号模拟与密钥
- 04核验 Security Command Center 发现
- 05安全地将公开来源提取为 Markdown
适用场景
- 01调查疑似 GCP 项目入侵
- 02评估服务账号密钥是否遭滥用
- 03追踪权限提升后的 IAM 变更
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trilwu/ secskills --skill investigating-gcp-incidents安装后在 Claude Code 中输入/investigating-gcp-incidents确认已加载。
详细介绍
调查 GCP 事件
GCP 调查是否完整,在事件发生前就已决定,取决于启用了哪些审计日志。最具破坏性的错误,就是把空查询结果解读为“什么都没发生”,而真实情况其实是“从未启用该日志类别”。先确认可见性,再下结论。
GCP 的审计模型与 AWS 和 Azure 不同。两个类别始终启用,另外两个大多处于关闭状态。了解哪些类别属于哪种情况,是开展范围明确的调查与误报平安之间的区别。
适用场景
- 响应 GCP 项目或组织中疑似遭到入侵的事件
- 调查泄露或遭滥用的服务账号密钥
- 处理 Security Command Center、Event Threat Detection 或 Chronicle 警报
- 还原某个主体在多个项目中的活动
- 在疑似权限提升后界定 IAM 策略或资源变更的范围
不适用场景
- 事件发生在 AWS 中——使用
investigating-aws-incidents;若发生在 Azure 或 Microsoft 365 / Entra 中,则使用investigating-azure-incidents或investigating-m365-entra - 目标是攻击 GCP,而非调查 GCP——使用
exploiting-cloud-platforms - 专门调查 GKE 集群遭入侵——先从这里了解云控制面视角,再使用
defending-kubernetes了解集群控制面视角 - 判断某个警报是否构成安全事件——先使用
triaging-security-alerts
下结论前确认可见性
GCP Cloud Audit Logs 分为四种日志流,其默认设置至关重要:
| 日志流 | 默认状态 | 能否停用? | 记录内容 |
|---|---|---|---|
| Admin Activity | 始终启用 | 否——即使 Logging API 已停用,也会写入 | 配置和元数据写入:IAM 变更、资源创建/删除 |
| System Event | 始终启用 | 否 | Google 对你的资源执行的操作 |
| Data Access | 默认关闭(BigQuery 除外) | 是 | 读取和数据面访问——谁读取了存储桶、密钥或数据集 |
| Policy Denied | 已启用 | 否(可从存储中排除) | 被策略阻止的访问——VPC-SC、组织策略 |
必须牢记其后果:**除 BigQuery 外,所有服务默认都关闭 Data Access 日志记录。**因此,“攻击者是否读取了密钥/下载了存储桶/窃取了数据集?”通常无法通过日志回答,除非事先启用了 Data Access 日志记录。不要报告“未发生数据外泄”,而应报告“未启用 Data Access 日志记录,因此无法确认或排除读取活动。”这是两种不同的调查结论,只有一种如实反映了情况。
不同日志流的保留期限也不同。Admin Activity 和 System Event 会写入
_Required 存储桶——保留 400 天,且无法配置。Data Access 和 Policy Denied 会写入 _Default——保留 30 天,除非有人延长了期限,或将接收器路由到保留期限更长的存储位置。在假定历史记录存在之前,先检查保留期限。
# What audit config is actually in effect at the org / project level
gcloud organizations get-iam-policy ORG_ID --format=json | jq '.auditConfigs'
gcloud projects get-iam-policy PROJECT_ID --format=json | jq '.auditConfigs'
还原活动
# Everything a principal did (Admin Activity is always present)
gcloud logging read \
'protoPayload.authenticationInfo.principalEmail="[email protected]"' \
--project=PROJECT_ID --freshness=30d --format=json
# IAM policy changes — the escalation signal
gcloud logging read \
'protoPayload.methodName:"SetIamPolicy"' --freshness=30d --format=json
# Service-account key creation — persistence
gcloud logging read \
'protoPayload.methodName="google.iam.admin.v1.CreateServiceAccountKey"' \
--freshness=30d --format=json
查看请求字段,而不只是方法名称。authenticationInfo
包含主体信息,尤其重要的是,它能说明调用是否通过模拟以某个服务账号的身份发出。requestMetadata.callerIp 和 callerSuppliedUserAgent
可用于定位来源;如果某个服务账号使用的 gcloud 用户代理来自意外的 ASN,这是一个强烈的信号。
服务账号与 OAuth 滥用
服务账号是大多数 GCP 事件的核心,因为它们持有长期有效的凭据,而且通常拥有过多权限。
- 冒充链。
iam.serviceAccounts.getAccessToken和...signJwt/...signBlob允许一个主体以另一个主体的身份行事。追踪链路: 谁冒充了谁,最终身份持有的权限是否多于源身份?这是 GCP 主要的横向移动和权限提升手段。 - 创建密钥属于持久化手段——用户管理的密钥在密码重置和 MFA 变更后仍然有效。在事件期间,任何针对特权 SA 的
CreateServiceAccountKey都应作为发现项处理。 - OAuth 授权与 Workspace 边界。 全域委派授权允许 GCP 服务账号跨 Google Workspace 行事;这会跨入类似
investigating-m365-entra的身份领域,纯 GCP 视角很容易漏掉这一点。
利用 Security Command Center,不要从零开始
如果启用了 Security Command Center,Event Threat Detection 可能已经关联了其中一些迹象——异常 IAM 授权、服务账号密钥滥用和数据外泄模式都会作为发现项浮现。先从 SCC 发现项着手建立时间线,再用原始审计日志逐项佐证,不要单凭发现项下结论。Standard 层级的 SCC 远不如 Premium/Enterprise 全面;在假设某项检测本应触发之前,先确认许可的层级。
应当驳斥的合理化说辞
- “日志显示没有数据访问,因此没有数据外泄。” 默认情况下,Data Access 日志记录处于关闭状态。没有日志意味着缺少日志记录,不意味着没有访问。应报告这一可见性缺口。
- “该时间段内 Admin Activity 为空,因此账号处于闲置状态。” 检查主体名称和项目是否正确——活动记录在被访问资源所属的项目中,该项目可能不是你正在查询的项目。
- “这不过是 30 天前的事。” 那是
_Default存储桶的期限。Admin Activity 保留 400 天;如果相关操作涉及 IAM 或资源变更,历史记录比你想象的更久。 - “是服务账号发起的调用,所以这是合法自动化。” 攻击者恰恰会冒充服务账号。检查调用是否通过
getAccessToken/冒充发起,以及来源是什么。 - “SCC 没有告警,所以事情没有发生。” Standard 层级的 SCC 只能检测到 Premium 所检测内容的一小部分,而且依赖 Data Access 的检测需要先启用相应日志。SCC 一片平静不代表一切正常。
阅读外部来源
将公开公告、规范和供应商报告获取为 Markdown:
curl -sL "https://defuddle.md/<url>" # scheme in the path is optional
这会剔除页面杂项——对于文字页面,令牌数大约减少 78%——并返回全文而非摘要,因此你可以用 grep 搜索,并相信没有搜到相关内容这一结果。
它不适用于三种情况。获取 JSON 和 API 响应时应保留原始格式,因为可读性提取会破坏结构化数据。获取需要身份验证或由 JavaScript 渲染的页面时,应直接访问,因为该工具会匿名检索页面。切勿通过它获取对手基础设施(钓鱼链接、C2、恶意软件托管)、客户端所属主机或交战 URL——请求会离开你的机器并发送给第三方;对于仍在活动的对手基础设施,这还会向操作者暴露你的访问行为。
有些网站会拦截提取器并返回错误内容,而不是页面——例如 freedesktop.org 返回的 {"error":"Failed to fetch: 418 I'm a teapot"}。这表示获取请求遭到拒绝,并不表示来源称该内容不存在。在据此得出任何结论之前,应直接重新获取该 URL。
参考资料
investigating-aws-incidents、investigating-azure-incidents——在另外两个云平台中遵循相同的调查原则defending-kubernetes——事件发生在 GKE 时,从集群平面进行观察responding-to-incidents——本指南所依据的总体事件响应框架hardening-cloud-posture——启用 Data Access 日志记录;本指南经常遇到的正是这类日志缺失