gcp-pubsub-subscribe-can-read-data
pubsub.subscriptions.consume on a subscription is the data-plane pull action; if the subscription carries credential material, credential-chains derives CanImpersonate. Also an exfiltration path when cross-project.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'match_effective_permission': {'action': 'pubsub.subscriptions.consume', 'resource_type': 'google.pubsub.Subscription'}}
emit
| source type | Identity |
|---|---|
| target type | Queue |
| source | <principal> |
| target | <Pub/Sub subscription node> |
| permissions | pubsub.subscriptions.consume |
| conditions | iam_permission resource_policy |
| state logic | ACTIVE when effective pubsub.subscriptions.consume is granted (subscription IAM + project IAM; no deny policy blocks). CONDITIONAL(resource_policy) when a subscription IAM condition scopes the grant. BLOCKED by IAM deny policy. Pub/Sub does not support native encryption with customer-managed keys at the subscription delivery level (CMEK is at the topic storage level via pubsub.topics.create with a kmsKeyName); if the topic has a CMEK binding the Pub/Sub service decrypts transparently — no additional kms:Decrypt-like gate on the subscriber. Downgrade to CONDITIONAL(key_permission) only if explicit application-level encryption (separate from Pub/Sub service-level CMEK) is confirmed in the message payloads. |
Narrative
{principal.name} can pull messages from Pub/Sub subscription {subscription.name} (pubsub.subscriptions.consume); if {subscription.name} carries credential material, credential-chains derives the ability to authenticate as the embedded identity.
Raw rule rules/derived/gcp/pubsub.yaml
id: gcp-pubsub-subscribe-can-read-data
emits: CanReadData
description: pubsub.subscriptions.consume on a subscription is the data-plane pull action; if the subscription
carries credential material, credential-chains derives CanImpersonate. Also an exfiltration path when
cross-project.
match:
- match_effective_permission:
action: pubsub.subscriptions.consume
resource_type: google.pubsub.Subscription
emit:
source_type: Identity
target_type: Queue
source: <principal>
target: <Pub/Sub subscription node>
permissions:
- pubsub.subscriptions.consume
conditions:
- iam_permission
- resource_policy
state_logic: "ACTIVE when effective pubsub.subscriptions.consume is granted (subscription IAM + project\
\ IAM; no deny policy blocks). CONDITIONAL(resource_policy) when a subscription IAM condition scopes\
\ the grant. BLOCKED by IAM deny policy. Pub/Sub does not support native encryption with customer-managed\
\ keys at the subscription delivery level (CMEK is at the topic storage level via pubsub.topics.create\
\ with a kmsKeyName); if the topic has a CMEK binding the Pub/Sub service decrypts transparently \u2014\
\ no additional kms:Decrypt-like gate on the subscriber. Downgrade to CONDITIONAL(key_permission)\
\ only if explicit application-level encryption (separate from Pub/Sub service-level CMEK) is confirmed\
\ in the message payloads."
confidence: 0.95
derived_from:
- 'effective-permission: pubsub.subscriptions.consume on subscription'
false_positive_note: "pubsub.subscriptions.consume grants pull delivery; it does NOT grant read of a\
\ push subscription's messages (push delivery is unidirectional to the endpoint). Credential-chain\
\ value only materializes when the subscription is confirmed to carry sensitive data (ContainsSecret\
\ / ContainsCredential must be separately emitted by pipeline metadata analysis or analyst labeling\
\ \u2014 do not assume every subscription carries secrets). CanExfiltrate is rolled up by the data-plane\
\ linchpin when CanReadData on a cross-project subscription is confirmed."
narrative: '{principal.name} can pull messages from Pub/Sub subscription {subscription.name} (pubsub.subscriptions.consume);
if {subscription.name} carries credential material, credential-chains derives the ability to authenticate
as the embedded identity.'