monitoring.organization_audit_logsink — version 1.8
Source: presets
Purpose
Organization-wide audit log sink into a GCS bucket — the compliance archive.
Params are overridable defaults: define the same param in the estate to override one. Claims are read from this source by the compliance plane.
Use it
params {
// the pack's own defaults — copy only the lines you change
logsink_name = "{customer_shortname}-organization-audit-gcs"
logsink_project_id = "{customer_shortname}-log-infra-001"
logsink_project_folder = ""
logsink_project_display_name = logsink_project_id
logsink_bucket_name = "{customer_shortname}-organization-audit-logs"
logsink_bucket_location = default_region
logsink_retention_days = 400
logsink_filter = "log_id("cloudaudit.googleapis.com/activity") OR log_id("cloudaudit.googleapis.com/data_access") OR log_id("cloudaudit.googleapis.com/system_event") OR log_id("cloudaudit.googleapis.com/policy")"
}
use "presets/monitoring/organization-audit-logsink.satz"
Needs from outside the pack:
billing_account_infra— declared byestate_core; use one of them alongside, or declare it in the estate.customer_organization_id— declared byestate_core; use one of them alongside, or declare it in the estate.customer_shortname— declared byestate_core; use one of them alongside, or declare it in the estate.default_region— declared byestate_core; use one of them alongside, or declare it in the estate.
Params
| param | default |
|---|---|
logsink_name |
"{customer |
logsink_project_id |
"{customer |
logsink_project_folder |
"" |
logsink |
logsink_project_id |
logsink_bucket_name |
"{customer |
logsink_bucket_location |
default_region |
logsink_retention_days |
400 |
logsink_filter |
"log |
Questions
What to ask before this pack is configured, and what changing the answer costs.
| asks about | prompt | reversal | blast | recommends |
|---|---|---|---|---|
logsink_project_id |
The project that holds the audit-log archive | recreate | high | — |
logsink_project_folder |
The folder the audit-archive project is created in — a folder the estate declares as google_folder.<label>.name, an existing one by its numeric id, or empty for the organisation |
edit | low | — |
logsink_bucket_name |
The archive bucket's name (globally unique) | recreate | high | — |
logsink_bucket_location |
Where the archive bucket lives (a region or multi-region) | recreate | high | — |
logsink_retention_days |
How many days the archive keeps audit logs before the lifecycle deletes them | edit | high | — |
logsink_project_id — A project id is immutable. Changing it later creates a second project and abandons the first, with the archive bucket inside it — and every pack that points at the logging project by reference moves with it.
logsink_project_folder — It is the only thing that decides where the project lands. Left empty, the project is created directly under the organisation and inherits the organisation's policies and IAM alone; an estate satz init wrote has its infrastructure folder as google. Changing it afterwards moves a live project between parents, which changes the policies and the grants it inherits.
An empty answer, "", is an answer: the organisation itself; the project is created directly under it.
logsink_bucket_name — The bucket holds the organisation's audit history. Renaming it means a new bucket and copying the archive by hand, or losing continuity of the evidence.
logsink_bucket_location — A bucket's location cannot change. Audit logs are the record a regulator asks for, so where they are stored is the customer's data-residency decision, not the pack's; the default follows the estate's default region.
logsink_retention_days — Shortening it later deletes everything already archived past the new age at the next lifecycle run, and there is no undo. 400 days covers a year plus the audit that follows it.
Contributes
| resource type | labels |
|---|---|
google |
organization_audit_gcs |
google |
org_all_services |
google_project |
logsink_project |
google_storage_bucket |
org_audit_logs |
google |
org_audit_sink_writer |
Claims
| framework | control | title | kind | witnesses | interpretation |
|---|---|---|---|---|---|
| cis-gcp 4.0 | 2.1 | Cloud Audit Logging on all services | implements | google |
ADMIN_READ/DATA_READ/DATA_WRITE on allServices at organization scope; exemptions via exempted_members keep the category enabled and visible. |
| cis-gcp 5.0 | 2.1 | Cloud Audit Logging on all services | implements | google |
As for 4.0 §2.1 (5.0 §2.1, unchanged). |
| cis-gcp 4.0 | 2.2 | Sinks for all log entries | implements | googlegooglegoogle |
Aggregated org sink (include_children) routes all Cloud Audit Logs to a central GCS bucket project owners cannot bypass; writer identity holds objectCreator only. |
| cis-gcp 5.0 | 2.3 | Sinks for all log entries | implements | googlegooglegoogle |
As for 4.0 §2.2 — 5.0 §2.3 (5.0 inserted a new 2.2 for Workspace data sharing). |
| cis-gcp 4.0 | 2.3 | Retention on the log bucket | contributes | google |
Lifecycle retention (logsink_retention_days) is automated; the bucket LOCK is a deliberate human decision, so coverage is honestly partial. |
| cis-gcp 5.0 | 2.4 | Retention on the log bucket | contributes | google |
As for 4.0 §2.3 — 5.0 §2.4. |
What the controls ask (this project's paraphrase from the catalog — never the framework's own text):
- Cloud Audit Logging on all services (cis-gcp 4.0 §2.1, cis-gcp 5.0 §2.1) — Data Access audit logs (ADMIN_READ/DATA_READ/DATA_WRITE) enabled org-wide for all services.
- Retention on the log bucket (cis-gcp 4.0 §2.3, cis-gcp 5.0 §2.4) — The central log destination retains entries per policy; bucket-lock retention once the pipeline is validated.
- Sinks for all log entries (cis-gcp 4.0 §2.2, cis-gcp 5.0 §2.3) — An aggregated org-level sink routes audit log entries to a central destination project owners cannot bypass.
Manual duties (a control stays partial until each is attested):
validate-then-lock(cis-gcp 4.0 §2.3, cis-gcp 5.0 §2.4) — After validating the pipeline, set retention_policy and is_locked on the audit bucket (one-way door; deliberately not preset-default).
Not every resource this pack contributes is a witness:
google— contributed, but no claim names it._project .logsink _project
History
| version | date | change |
|---|---|---|
| 1.8 | 2026-10-14 | logsink_project_folder says what an empty answer means — the organisation itself — so an estate that binds "" has answered the question; before, "" counted as unanswered although the prompt offered it. Nothing emitted changes |
| 1.7 | 2026-09-30 | every claim states its measure without satz: gcloud (the commands that meet the control the way the claim's resources do), gcloud_check (the commands that show whether it is met) and risk (what goes wrong without it); require and report-compliance carry them in each control's measures. Nothing emitted changes |
| 1.6 | 2026-09-21 | a question for logsink_project_folder: the folder the audit-archive project is created in. The param is now the only thing that decides — a use line no longer stands in a folder's body — so the interview asks for it. Answering it empty creates the project under the organisation; an estate satz init wrote answers "google, which init binds itself. Nothing emitted changes for an estate that already binds the param |
| 1.5 | 2026-09-21 | logsink_project_folder: the folder the audit-archive project is created in, said by the estate instead of read from the node the use line stands in. The default is empty, which says nothing — the enclosing node decides, exactly as before — so no estate's plan moves. An estate whose use "presets stands inside a folder's body writes logsink_project_folder = "google for that folder (satz init writes the line into google_folder.infra_folder, so "google) and may then move the use line to the top level: the emitted HCL is byte-identical either way. A folder that already exists rather than being declared here is named by its id, "123456789012" |
| 1.4 | 2026-09-12 | logsink_project_name becomes logsink_project_id, because that is what it is — it feeds project_id, and a project id is immutable while a name is not. The project's display name is its own optional param, logsink, defaulting to the id exactly as Google does, so nothing changes in the emitted HCL. An estate still binding the old name is REFUSED by name with the new one: nothing refuses a param no pack reads, so leaving it would have silently taken this pack's default project instead — a second logging project and an orphaned archive |
| 1.3 | 2026-09-10 | four question blocks — the archive project, the bucket, its location, the retention — each with what changing it later costs (the first three are recreates; shortening the retention deletes what is already archived). Sink name and filter stay technical defaults, unasked. Nothing emitted changes |
| 1.2 | 2026-09-03 | CIS 5.0 claim ids corrected: sinks are 5.0 §2.3 and retention §2.4 (5.0 inserted a new §2.2 for Workspace data sharing); 4.0 ids unchanged; "provisional" notes removed — numbering verified against Prowler + Tenable |
| 1.1 | 2026-08-21 | claims for CIS 2.1/2.2 (both 4.0 and 5.0), the writer-identity bucket grant, retention lifecycle rules |
| 1.0 | 2026-08-21 | org audit log sink → bucket |
The whole library's history: the changelog in presets/CHANGELOG.md.
Notes
The project lands in the scope this pack is used in: at the top level it belongs to the organisation, inside a google_folder block to that folder. Moving it afterwards is a project move, so decide the scope before the first apply.
monitoring takes this pack's project by reference, so an estate using both wires nothing. The bucket, its location and the project id cannot change once created, and shortening the retention deletes everything already past the new age at the next lifecycle run.