gcp-bigtable-exfiltrate-via-backup
A principal with bigtable.backups.read on a source backup AND bigtable.backups.create + bigtable.backups.restore in a destination instance (any project) can copy the backup cross-project and restore the full table contents in the destination, exfiltrating all data outside the source project boundary.
match (effective permission)
{
"action": [
"bigtable.backups.read",
"bigtable.backups.create",
"bigtable.backups.restore"
],
"resource_type": [
"google.bigtable.admin.v2.Backup",
"google.bigtable.admin.v2.Instance"
]
}
where
principal HOLDS bigtable.backups.read ON source_backup
principal HOLDS bigtable.backups.create ON destination_instance
principal HOLDS bigtable.backups.restore ON destination_instance
destination_instance.project NOT_EQUALS source_backup.project
source_backup.instance.state EQUALS READY
destination_instance.state EQUALS READY
emit
| source type | Identity |
|---|---|
| target type | Backup |
| source | <principal> |
| target | <Bigtable Backup node> |
| permissions | bigtable.backups.read bigtable.backups.create bigtable.backups.restore |
| conditions | iam_permission resource_policy key_permission |
| state logic | ACTIVE when bigtable.backups.read is confirmed on the source backup AND bigtable.backups.create + bigtable.backups.restore are confirmed in a destination instance in a different project AND both the source and destination instances are in READY state AND the destination cluster's CMEK key (if present) is compatible with the restored backup (either the source and destination clusters share the same KMS key, or the destination cluster's service agent holds the source backup's CMEK key's decrypt grant) AND no VPC-SC perimeter blocks backup copy operations; CONDITIONAL(iam_permission) when destination create/restore rights are uncertain (e.g., only project-scope billing confirmed, destination project is unmodeled); CONDITIONAL(key_permission) when destination cluster uses a different CMEK key than the source cluster and the destination cluster's service agent's access to that key or the source key's accessibility is unconfirmed; POTENTIAL when a destination instance exists but its accessibility is unconfirmed; BLOCKED when a VPC-SC perimeter prevents the cross-project backup copy call (bigtable.googleapis.com in the perimeter restricts API access), OR when the destination cluster's CMEK key is in DISABLED/DESTROYED state, OR when the destination cluster's service agent lacks the decrypt grant for the key required by the restored backup. |
Narrative
{principal.name} holds bigtable.backups.read on backup {backup.name} (source of table {table.name}) and bigtable.backups.create + bigtable.backups.restore in a destination project; it can copy the backup cross-project and restore the full table contents in the destination, exfiltrating all of {table.name}'s data outside the source project boundary.
Raw rule rules/derived/gcp/bigtable.yaml
id: gcp-bigtable-exfiltrate-via-backup
emits: CanExfiltrate
description: A principal with bigtable.backups.read on a source backup AND bigtable.backups.create + bigtable.backups.restore
in a destination instance (any project) can copy the backup cross-project and restore the full table
contents in the destination, exfiltrating all data outside the source project boundary.
match_effective_permission:
action:
- bigtable.backups.read
- bigtable.backups.create
- bigtable.backups.restore
resource_type:
- google.bigtable.admin.v2.Backup
- google.bigtable.admin.v2.Instance
where:
- principal HOLDS bigtable.backups.read ON source_backup
- principal HOLDS bigtable.backups.create ON destination_instance
- principal HOLDS bigtable.backups.restore ON destination_instance
- destination_instance.project NOT_EQUALS source_backup.project
- source_backup.instance.state EQUALS READY
- destination_instance.state EQUALS READY
emit:
source_type: Identity
target_type: Backup
source: <principal>
target: <Bigtable Backup node>
permissions:
- bigtable.backups.read
- bigtable.backups.create
- bigtable.backups.restore
conditions:
- iam_permission
- resource_policy
- key_permission
state_logic: ACTIVE when bigtable.backups.read is confirmed on the source backup AND bigtable.backups.create
+ bigtable.backups.restore are confirmed in a destination instance in a different project AND both
the source and destination instances are in READY state AND the destination cluster's CMEK key (if
present) is compatible with the restored backup (either the source and destination clusters share
the same KMS key, or the destination cluster's service agent holds the source backup's CMEK key's
decrypt grant) AND no VPC-SC perimeter blocks backup copy operations; CONDITIONAL(iam_permission)
when destination create/restore rights are uncertain (e.g., only project-scope billing confirmed,
destination project is unmodeled); CONDITIONAL(key_permission) when destination cluster uses a different
CMEK key than the source cluster and the destination cluster's service agent's access to that key
or the source key's accessibility is unconfirmed; POTENTIAL when a destination instance exists but
its accessibility is unconfirmed; BLOCKED when a VPC-SC perimeter prevents the cross-project backup
copy call (bigtable.googleapis.com in the perimeter restricts API access), OR when the destination
cluster's CMEK key is in DISABLED/DESTROYED state, OR when the destination cluster's service agent
lacks the decrypt grant for the key required by the restored backup.
confidence: min(contributing_confidences) * 0.92
derived_from:
- bigtable.backups.read effective permission on source Backup
- bigtable.backups.create effective permission in destination project
- bigtable.backups.restore effective permission in destination project
false_positive_note: "ALL THREE permissions are required: bigtable.backups.read on the SOURCE backup\
\ (allows copy), bigtable.backups.create in the DESTINATION instance (creates the copied backup),\
\ and bigtable.backups.restore in the destination (restores the backup to a new table). Without source\
\ backups.read, the copy call fails. Without destination create+restore, the data cannot be materialized.\
\ bigtable.backups.get (read metadata) does NOT allow backup data copy \u2014 only bigtable.backups.read\
\ enables copy operations. The destination restore always creates a NEW table (cannot overwrite an\
\ existing table). For CMEK backups, the restored table in the destination cluster uses that cluster's\
\ CMEK key (or Google-managed key if the destination cluster is not CMEK). If the source CMEK key\
\ is not accessible to the destination cluster's service agent, the restore will fail -> emit as CONDITIONAL(key_permission)\
\ when the destination cluster uses a different CMEK key than the source."
narrative: '{principal.name} holds bigtable.backups.read on backup {backup.name} (source of table {table.name})
and bigtable.backups.create + bigtable.backups.restore in a destination project; it can copy the backup
cross-project and restore the full table contents in the destination, exfiltrating all of {table.name}''s
data outside the source project boundary.'