gcp-pd-snapshot-use-same-project
A principal within the same project with compute.snapshots.useReadOnly and compute.disks.create can restore any project snapshot as a disk and read all on-disk data, escalating access to disks they don't directly have read permissions on.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?snapshot) ==
Snapshot
?principal (in ?project) has EFFECTIVE compute.snapshots.useReadOnly on ?snapshot
?principal has EFFECTIVE compute.disks.create in ?project
?principal has EFFECTIVE compute.instances.attachDisk OR can create an instance to attach the new disk in ?project
emit
| source type | Identity |
|---|---|
| target type | Storage |
| source | <principal in same project> |
| target | <snapshot (disk data)> |
| permissions | compute.snapshots.useReadOnly compute.disks.create compute.instances.attachDisk |
| conditions | iam_permission resource_policy |
| state logic | ACTIVE if all three permissions confirmed within the same project and the principal can describe the snapshot. This is an intra-project escalation: a narrowly-scoped principal gains read access to encrypted-at-rest data or other team's data by restoring snapshots. CONDITIONAL(key_permission) if the source disk was CMEK-encrypted (snapshot inherits the kmsKeyName) — the principal must also hold cloudkms.cryptoKeyVersions.useToDecrypt on the wrapping key to read the plaintext data (cite decrypt-gates-secret-read in credential-chains.yaml); BLOCKED if the disk was CSEK-encrypted. |
Narrative
{principal.name} in {project.name} can create a disk from {snapshot.name} (compute.snapshots.useReadOnly + compute.disks.create) and attach it to an instance within the same project (compute.instances.attachDisk), gaining read access to on-disk data they would not otherwise be able to access directly.
Raw rule rules/derived/gcp/pd.yaml
id: gcp-pd-snapshot-use-same-project
emits: CanReadData
description: A principal within the same project with compute.snapshots.useReadOnly and compute.disks.create
can restore any project snapshot as a disk and read all on-disk data, escalating access to disks they
don't directly have read permissions on.
applies_to:
- gcp
match:
- - snapshot: null
- LocatedIn
- project: null
where:
- node_type(?snapshot) == Snapshot
- ?principal (in ?project) has EFFECTIVE compute.snapshots.useReadOnly on ?snapshot
- ?principal has EFFECTIVE compute.disks.create in ?project
- ?principal has EFFECTIVE compute.instances.attachDisk OR can create an instance to attach the new disk
in ?project
emit:
source_type: Identity
target_type: Storage
source: <principal in same project>
target: <snapshot (disk data)>
permissions:
- compute.snapshots.useReadOnly
- compute.disks.create
- compute.instances.attachDisk
conditions:
- iam_permission
- resource_policy
state_logic: "ACTIVE if all three permissions confirmed within the same project and the principal can\
\ describe the snapshot. This is an intra-project escalation: a narrowly-scoped principal gains read\
\ access to encrypted-at-rest data or other team's data by restoring snapshots. CONDITIONAL(key_permission)\
\ if the source disk was CMEK-encrypted (snapshot inherits the kmsKeyName) \u2014 the principal must\
\ also hold cloudkms.cryptoKeyVersions.useToDecrypt on the wrapping key to read the plaintext data\
\ (cite decrypt-gates-secret-read in credential-chains.yaml); BLOCKED if the disk was CSEK-encrypted."
false_positive_note: 'Emit only when all three permissions are confirmed in the same project. This rule
covers intra-project snapshot restore escalation. Cross-project scenarios are covered by gcp-pd-snapshot-use-cross-project.
CMEK gate: diskEncryptionKey.kmsKeyName on the source disk propagates to the snapshot; without KMS
decrypt on that key the raw snapshot data cannot be decrypted -> downgrade to CONDITIONAL(key_permission).
CSEK: immediately BLOCKED.'
derived_from:
- '<LocatedIn edge: snapshot -> project>'
- <compute.snapshots.useReadOnly effective permission on ?snapshot>
- <compute.disks.create + compute.instances.attachDisk effective permissions>
narrative: '{principal.name} in {project.name} can create a disk from {snapshot.name} (compute.snapshots.useReadOnly
+ compute.disks.create) and attach it to an instance within the same project (compute.instances.attachDisk),
gaining read access to on-disk data they would not otherwise be able to access directly.'