gcp-logging-delete-log-bucket
Delete a custom or _Default log bucket (logging.buckets.delete), permanently destroying all retained log history stored in it.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?bucket) ==
LoggingService
?bucket.provider_type == 'google.logging.v2.LogBucket'
effective_action(?principal, ?bucket) includes 'logging.buckets.delete'
?bucket is NOT _Required (system-immutable)
?bucket.locked == false — a locked bucket cannot be deleted
emit
| source type | Identity |
|---|---|
| target type | LoggingService |
| source | ?principal |
| target | ?bucket |
| permissions | logging.buckets.delete |
| conditions | iam_permission service_state |
| state logic | ACTIVE if the principal holds EFFECTIVE logging.buckets.delete on the target bucket AND the bucket is not locked (locked: false) AND the bucket is not _Required; CONDITIONAL(service_state) if bucket lock status is unknown; BLOCKED if the bucket is locked (locked: true), is _Required, or an IAM deny / org policy denies logging.buckets.delete at the effective scope. |
Narrative
{principal.name} can delete log bucket {bucket.name} (logging.buckets.delete), permanently destroying all retained log entries stored in it - eliminating forensic evidence of prior API activity across the project's retained log history.
Raw rule rules/derived/gcp/logging.yaml
id: gcp-logging-delete-log-bucket
emits: CanDelete
description: Delete a custom or _Default log bucket (logging.buckets.delete), permanently destroying all
retained log history stored in it.
match:
- - principal: null
- HasPermission
- bucket: null
where:
- node_type(?bucket) == LoggingService
- ?bucket.provider_type == 'google.logging.v2.LogBucket'
- effective_action(?principal, ?bucket) includes 'logging.buckets.delete'
- ?bucket is NOT _Required (system-immutable)
- "?bucket.locked == false \u2014 a locked bucket cannot be deleted"
emit:
source_type: Identity
target_type: LoggingService
source: ?principal
target: ?bucket
permissions:
- logging.buckets.delete
conditions:
- iam_permission
- service_state
state_logic: 'ACTIVE if the principal holds EFFECTIVE logging.buckets.delete on the target bucket AND
the bucket is not locked (locked: false) AND the bucket is not _Required; CONDITIONAL(service_state)
if bucket lock status is unknown; BLOCKED if the bucket is locked (locked: true), is _Required, or
an IAM deny / org policy denies logging.buckets.delete at the effective scope.'
confidence: 0.93
derived_from:
- HasPermission(?principal, logging.buckets.delete, ?bucket)
false_positive_note: "_Required bucket is always BLOCKED \u2014 the API enforces immutability server-side\
\ regardless of IAM grants. A bucket with locked: true cannot be deleted \u2014 BLOCKED. Deleting\
\ a log bucket removes ALL stored log entries in it permanently (no soft delete or recycle bin); high-impact\
\ destructive action. Note: deleting the _Default bucket is distinct from deleting the _Default sink\
\ \u2014 bucket deletion removes stored entries while sink deletion stops future delivery. An attacker\
\ wanting total coverage needs both. This is evidence destruction, not privilege escalation; CanDelete\
\ is non-walkable by default (schema traversal: false) \u2014 surfaced for impact analysis."
narrative: "{principal.name} can delete log bucket {bucket.name} (logging.buckets.delete), permanently\
\ destroying all retained log entries stored in it \u2014 eliminating forensic evidence of prior API\
\ activity across the project's retained log history."