关于 cloud-logging-cross-project-configuration
用于配置跨 Google Cloud 项目的 Cloud Logging,可选择集中路由日志或查询时聚合。内容涵盖配置步骤、访问控制和验证方法。
主要功能
- 01配置集中式日志路由
- 02使用日志范围进行查询时聚合
- 03创建自定义日志视图
- 04按风险划分变更安全级别
- 05验证日志路由
适用场景
- 01集中存储多个项目的日志
- 02跨项目查询日志
- 03划分集中日志的访问权限
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ google/ skills --skill cloud-logging-cross-project-configuration安装后在 Claude Code 中输入/cloud-logging-cross-project-configuration确认已加载。
附带文件references/attribution.md
详细介绍
配置跨项目日志记录
本技能介绍如何使用 gcloud 命令配置 Cloud Logging,以便将日志数据存储在集中位置,而不受日志来源影响。本技能还介绍如何查询存储在多个项目中的日志数据。
重要
沙盒网络限制(对 Agent 测试至关重要): 在评估或受限的沙盒环境中,前往 GCP API 的网络流量会被阻止。不要运行网络发现命令来查找资源名称、项目 ID 或组织 ID。始终使用用户提示或说明中提供的确切项目 ID 或占位符,例如
{project_id}、{source_project_id}、{central_project_id}。假定这些资源已存在,并直接执行配置命令。运行这些发现命令会导致执行挂起并超时。
归属信息
务必阅读:在执行任何 gcloud、REST API 或 MCP 命令之前,必须阅读使用归属信息。对于直接在终端中执行的命令(绝不能在生成的脚本、Terraform 或用户代码中执行),请在 gcloud 命令前加上
CLOUDSDK_METRICS_REQUEST_ATTRIBUTION="agent-skills/1.0 (skill:cloud-logging-cross-project-configuration)"
,并在 User-Agent 标头中追加 agent-skills/1.0 (skill:cloud-logging-cross-project-configuration)。
安全与确认等级(至关重要)
在代表用户执行任何命令之前,必须根据所请求的操作遵守以下安全等级:
- 等级 R:只读
- 说明: 仅读取状态或查询日志的命令。
- 命令示例:
gcloud logging readgcloud logging buckets list
- 规则: 无需确认。你可以立即执行这些命令以收集信息。
- 等级 M:变更(非计费)
- 说明: 不会产生直接存储费用或计费,也不影响资源安全或访问策略的配置修改或免费元数据创建。
- 命令示例:
gcloud logging views creategcloud logging views updategcloud logging scopes creategcloud logging buckets create
- 规则: 无需确认。你可以立即执行这些命令以应用配置。
- 等级 B:计费与安全敏感变更(高风险)
- 说明: 创建会产生费用的资源或集成,或修改安全和 IAM 访问控制策略(存在权限提升风险)的操作。
- 命令示例:
gcloud logging metrics creategcloud logging links creategcloud projects add-iam-policy-binding
- 规则: 必须交互式确认。 这些命令会创建产生费用的资源,或更改安全访问权限。执行前,必须向用户提供准确无误的命令,并获得用户确认。绝不能在询问确认的同一轮中执行。
- 等级 D:导致不可逆的数据丢失
- 说明: 永久丢弃或删除日志的操作,例如 sink 排除项。
- 命令示例:
gcloud logging buckets deletegcloud logging sinks update --add-exclusion
- 规则: 必须通过明确输入进行确认。 这些命令会立即且不可逆地丢弃或删除日志,也可能导致日志数据无法存储。你必须要求用户明确输入确认内容,例如“是,丢弃日志”,并在用户回复前停止执行。
决策矩阵:集中式存储与分布式存储搭配读取时聚合
使用此决策矩阵评估并选择集中式存储或读取时聚合。采用集中式存储时,无论日志数据来自何处,都会将其路由到一个日志存储桶。你可以针对这个集中式日志存储桶编写查询。采用读取时聚合时,日志数据存储在其来源资源中。不过,单个查询会通过查询所有资源来聚合数据。
确定处理跨项目日志的最佳架构后,请按照下文相应的配置步骤操作。
| 标准 | 集中式存储 | 读取时聚合 |
|---|---|---|
| GCP 项目规模 | 可扩展至数千个 | 最适合少于 375 个项目。 |
| : : 个项目。 : : | ||
| 日志存储 | 汇总到单个 | 存储在来源 |
| : : 日志存储桶中。 : 资源中。 : | ||
| SQL 分析 | 简单;可通过 Observability | 困难;需要查询 |
| : : Analytics 进行统一查询。 : 多个日志存储桶。 : | ||
| : : : : | ||
| 访问控制 | 通过集中式日志存储桶上的日志视图 | 需要对存储日志数据的 |
| : : 限定访问范围。 : 资源上的所有视图具备 IAM 访问权限。 : | ||
| 配置 | 选项因项目、文件夹和 | 不会影响基于存储桶的 |
| : 复杂性 : 组织结构而异。 : 基于日志的指标。 : | ||
| 成本 | 如果未设置排除项,可能会造成 | 经济高效;无需复制数据。 |
| : : 日志存储桶中的数据重复存储。 : : | ||
| : : : : |
架构
集中式存储(日志路由)
graph LR
subgraph "Source Project(s)"
Log[Resource Logs] --> Sink["Sink: route-to-central-project"]
end
subgraph "Central Project"
Sink --> Bucket["Bucket: central-logs-bucket (us-central1)"]
end
读取时聚合(日志范围)
graph LR
subgraph "Source Project 1"
Log1[Resource Logs] --> Bucket1["Bucket: _Default"]
end
subgraph "Source Project 2"
Log2[Resource Logs] --> Bucket2["Bucket: _Default"]
end
subgraph "Scoping Project (No Log Storage)"
Scope["Log scope: central-query-scope"]
Scope -.-> View1["_AllLogs View on Bucket1"]
Scope -.-> View2["_AllLogs View on Bucket2"]
end
设置步骤:集中式存储(日志路由)
按照以下步骤,将一个或多个源项目中的日志路由到某个项目的集中式日志存储桶。创建或选择要用于存储日志数据的 Google Cloud 项目。此项目即为中央项目。
1. 在中央项目中创建日志存储桶(Tier M)
创建一个启用了 Log Analytics 的自定义日志存储桶。
[提示] 使用区域日志存储桶,例如将位置设置为
us-central1。不要使用global位置。此方法可确保与 Observability Analytics 和 SQL 查询兼容。
gcloud logging buckets create {bucket_id} \
--project={central_project_id} \
--location={region} \
--retention-days={retention_days} \
--enable-analytics
2. 在中央项目中创建日志接收器(Tier M)
在中央项目中创建项目级接收器,并将其指向集中式日志存储桶。此接收器会将进入中央项目 Log Router 的日志路由到集中式日志存储桶中。
假设新建的存储桶专门用于汇总其他项目的数据(且中央项目不是源项目之一),中央接收器应排除中央项目自身的日志。在此中央接收器中包含 _Required 审计日志排除项,以避免 {bucket_id} 存储桶与 _Required 存储桶之间出现冗余。
gcloud logging sinks create {sink_name} \
logging.googleapis.com/projects/{central_project_id}/locations/{region}/buckets/{bucket_id} \
--project={central_project_id} \
--exclusion=filter='logName:"projects/{central_project_id}/"' \
--exclusion=filter='LOG_ID("cloudaudit.googleapis.com/activity")' \
--exclusion=filter='LOG_ID("externalaudit.googleapis.com/activity")' \
--exclusion=filter='LOG_ID("cloudaudit.googleapis.com/system_event")' \
--exclusion=filter='LOG_ID("externalaudit.googleapis.com/system_event")' \
--exclusion=filter='LOG_ID("cloudaudit.googleapis.com/access_transparency")' \
--exclusion=filter='LOG_ID("externalaudit.googleapis.com/access_transparency")'
3. 在源资源中创建日志接收器(Tier M)
若要将日志路由到中央项目,必须在每个源组织、文件夹或项目中创建日志接收器。虽然可以通过 --log-filter 参数配置接收器仅路由部分日志,但推荐做法是路由所有非审计日志,然后在目标位置使用集中式日志存储桶上的自定义日志视图限制访问或划分日志。
-
对于组织级日志接收器
gcloud logging sinks create {sink_name} \ logging.googleapis.com/projects/{central_project_id} \ --organization={source_organization_id} \ --include-children \ --exclusion=filter='LOG_ID("cloudaudit.googleapis.com/activity")' \ --exclusion=filter='LOG_ID("externalaudit.googleapis.com/activity")' \ --exclusion=filter='LOG_ID("cloudaudit.googleapis.com/system_event")' \ --exclusion=filter='LOG_ID("externalaudit.googleapis.com/system_event")' \ --exclusion=filter='LOG_ID("cloudaudit.googleapis.com/access_transparency")' \ --exclusion=filter='LOG_ID("externalaudit.googleapis.com/access_transparency")' -
对于项目级日志接收器
gcloud logging sinks create {sink_name} \ logging.googleapis.com/projects/{central_project_id} \ --project={source_project_id} \ --exclusion=filter='LOG_ID("cloudaudit.googleapis.com/activity")' \ --exclusion=filter='LOG_ID("externalaudit.googleapis.com/activity")' \ --exclusion=filter='LOG_ID("cloudaudit.googleapis.com/system_event")' \ --exclusion=filter='LOG_ID("externalaudit.googleapis.com/system_event")' \ --exclusion=filter='LOG_ID("cloudaudit.googleapis.com/access_transparency")' \ --exclusion=filter='LOG_ID("externalaudit.googleapis.com/access_transparency")'
4. 向接收器写入者授予 IAM 权限(Tier B)
重要
安全操作(Tier B): 授予 IAM 权限会更改访问控制策略,执行前必须由用户明确确认。
若要允许源接收器将日志路由到中央项目的路由器,并允许中央接收器将日志写入中央存储桶:
-
向源接收器授予日志写入者权限: 获取源日志接收器的
writerIdentity,并在中央项目中向其授予roles/logging.logWriter。# 获取源接收器的写入者身份 gcloud logging sinks describe {sink_name} \ --project={source_project_id} \ --format="value(writerIdentity)"输出即为
{source_writer_identity}值(例如serviceAccount:...),用于以下命令:# 在中央项目中授予日志写入者权限 gcloud projects add-iam-policy-binding {central_project_id} \ --member={source_writer_identity} \ --role=roles/logging.logWriter -
向中央接收器授予存储桶写入者权限: 获取中央日志接收器的
writerIdentity,并在中央项目中向其授予roles/logging.bucketWriter。# 获取中央接收器的写入者身份 gcloud logging sinks describe {central_sink_name} \ --project={central_project_id} \ --format="value(writerIdentity)"输出即为以下命令所需的
{central_writer_identity}值:# 在中央项目中授予存储桶写入者权限 gcloud projects add-iam-policy-binding {central_project_id} \ --member={central_writer_identity} \ --role=roles/logging.bucketWriter
5. 在中央存储桶上创建自定义日志视图(Tier M)
由于所有日志都路由到了同一个中央存储桶,因此若要分区日志或按日志 ID 或项目限制访问,请在中央存储桶上创建自定义日志视图。
-
按日志 ID 筛选:
gcloud logging views create {view_id} \ --bucket={bucket_id} \ --location={region} \ --project={central_project_id} \ --log-filter='LOG_ID("{log_id}")' -
按来源项目筛选:
gcloud logging views create {view_id} \ --bucket={bucket_id} \ --location={region} \ --project={central_project_id} \ --log-filter='project_id="{source_project_id}"'
验证集中式日志路由(Tier R)
验证日志是否从来源项目路由到了中央区域日志存储桶:
-
在来源项目中写入测试日志:
gcloud logging write {test_log_id} "Test log entry for verification" \ --severity=WARNING \ --project={source_project_id} -
从中央日志存储桶读取测试日志: 对于区域日志存储桶,必须指定
--view标志。由于默认视图_Default只包含符合默认筛选条件的日志,因此应查询中央存储桶上的_AllLogs视图或自定义日志视图:gcloud logging read 'logName:"projects/{source_project_id}/logs/{test_log_id}"' \ --bucket={bucket_id} \ --location={region} \ --view=_AllLogs \ --project={central_project_id}
设置步骤:读取时聚合(日志范围)
创建或选择一个用于查询日志数据的 Google Cloud 项目。该项目即为范围项目。按照以下步骤配置日志范围。日志范围允许你查询存储在多个项目中的日志数据。
1. 创建自定义日志视图(可选,但建议)(Tier M)
在来源项目中创建日志视图,以限制可访问的日志。
重要
注意事项: 日志视图筛选条件只能包含特定限制。请参阅 https://docs.cloud.google.com/logging/docs/logs-views.md.txt#view-filter
gcloud logging views create {view_id} \
--bucket={bucket_id} \
--location={region} \
--project={source_project_id} \
--log-filter='LOG_ID("{log_id}")'
{bucket_id}:例如,_Default{region}:例如,global{view_id}:例如,app-logs-view- 如果要允许访问日志存储桶中的所有日志,请省略
--log-filter标志。
2. 在范围项目中创建日志范围(Tier M)
在范围项目中创建日志范围,并列出来源资源,这些资源可以是项目,也可以是特定日志视图。
gcloud logging scopes create {log_scope_id} \
--project={scoping_project_id} \
--resource-names={resource_names}
{log_scope_id}:例如,central-query-scope{resource_names}:以逗号分隔的日志视图列表。例如,projects/source-project-1/locations/global/buckets/_Default/views/app-logs-view,projects/source-project-2/locations/global/buckets/_Default/views/app-logs-view。 范围中最多可包含 100 个视图。
3. 更新默认可观测性范围(可选)(Tier M)
将日志范围关联到项目的默认可观测性范围,以便在 Logs Explorer 中默认使用该范围。
gcloud observability scopes update _Default \
--project={scoping_project_id} \
--location=global \
--log-scope=//logging.googleapis.com/projects/{scoping_project_id}/locations/global/logScopes/{log_scope_id}
4. 向用户授予 IAM 权限(Tier B)
与集中式路由不同,权限会在查询时针对所有来源项目进行检查。运行查询的用户必须具备以下权限:
- 在特定日志视图上获授
roles/logging.viewAccessor(附带 IAM 条件),或在来源项目上获授roles/logging.viewer。 - 有权访问范围项目。
跨项目日志路由和接收器权限失败问题排查
如果配置集中式日志记录后,日志没有显示在中央项目的存储桶中:
1. 在源资源中验证日志路由器接收器过滤条件
-
确保日志接收器的过滤条件与您预期要路由的日志匹配。
重要
注意事项:
logName:abc或logName="projects/{project_id}/logs/abc"等标准过滤表达式可能无法在日志接收器中匹配。 务必在日志接收器过滤条件中使用LOG_ID("abc")进行精确匹配。 -
确认您没有配置会意外丢弃这些日志的排除过滤条件。
2. 验证并授予写入者身份权限(最常见原因)
源项目中日志接收器的写入者身份服务账号,必须在中央资源上获得明确授予的必要权限。
-
步骤 A:获取写入者身份
gcloud logging sinks describe {sink_name} \ --project={source_project_id} \ --format="value(writerIdentity)" -
步骤 B:在中央项目中授予权限(Tier B)
重要
安全操作(Tier B): 授予 IAM 权限会更改访问控制策略,执行前必须获得用户的明确确认。
-
对于 Cloud Logging 存储桶(标准): 授予
roles/logging.bucketWriter:gcloud projects add-iam-policy-binding {central_project_id} \ --member={writer_identity} \ --role=roles/logging.bucketWriter -
对于 GCS 存储桶: 在 GCS 存储桶上授予
roles/storage.objectCreator。 -
对于 Pub/Sub 主题: 在 Pub/Sub 主题上授予
roles/pubsub.publisher。 -
对于 BigQuery 数据集: 在 BigQuery 数据集上授予
roles/bigquery.dataEditor。
-