aws-keyspaces-select-read-data

IAM-effective cassandra:Select on a Keyspaces table allows full data-plane read (CQL SELECT), yielding all row data including any secret material.

derived aws emits CanReadData

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} HasPermission {'table': None}

where

node_type(?table) == NoSQLDatabase ?table.provider_type == 'AWS::Cassandra::Table' effective_action(?principal, ?table) includes 'cassandra:Select'

emit

source typeIdentity
target typeNoSQLDatabase
source?principal
target?table
permissionscassandra:Select
state logicif ?table.encryptionSpecification.kmsKeyIdentifier is a customer-managed key (not alias/aws/cassandra or AWS-managed): CONDITIONAL(key_permission) — the caller needs kms:Decrypt on the CMK for AWS Keyspaces to return decrypted data. When the principal is confirmed to hold CanDecrypt on that exact CMK, a provider-agnostic linchpin rule (TBD) should upgrade this to ACTIVE. Otherwise (SSE uses the AWS-managed key alias/aws/cassandra): ACTIVE.

Narrative

{principal.name} can run CQL SELECT statements against {table.name} (cassandra:Select), reading all application data stored in the table. If {table.name} contains credentials or secrets, this yields further pivots via credential-chains:read-secret-yields-identity.

Raw rule rules/derived/aws/keyspaces.yaml

id: aws-keyspaces-select-read-data
emits: CanReadData
description: IAM-effective cassandra:Select on a Keyspaces table allows full data-plane read (CQL SELECT),
  yielding all row data including any secret material.
match:
- - principal: null
  - HasPermission
  - table: null
where:
- node_type(?table) == NoSQLDatabase
- ?table.provider_type == 'AWS::Cassandra::Table'
- effective_action(?principal, ?table) includes 'cassandra:Select'
emit:
  source_type: Identity
  target_type: NoSQLDatabase
  source: ?principal
  target: ?table
  permissions:
  - cassandra:Select
  conditions_dynamic: 'if ?table.encryptionSpecification.kmsKeyIdentifier is a customer-managed key (not
    alias/aws/cassandra or AWS-managed key): [iam_permission, key_permission]; else: [iam_permission]'
  state_logic: "if ?table.encryptionSpecification.kmsKeyIdentifier is a customer-managed key (not alias/aws/cassandra\
    \ or AWS-managed): CONDITIONAL(key_permission) \u2014 the caller needs kms:Decrypt on the CMK for\
    \ AWS Keyspaces to return decrypted data. When the principal is confirmed to hold CanDecrypt on that\
    \ exact CMK, a provider-agnostic linchpin rule (TBD) should upgrade this to ACTIVE. Otherwise (SSE\
    \ uses the AWS-managed key alias/aws/cassandra): ACTIVE."
  confidence: contributing_confidence * 0.95
  derived_from:
  - <HasPermission edge for cassandra:Select on ?table>
  false_positive_note: "Honor the exact resource scope of the cassandra:Select permission \u2014 a grant\
    \ scoped to system keyspace ARNs (system_schema, system_schema_mcs) does not confer access to application-data\
    \ tables. Verify the effective resource ARN includes the application table ARN. cassandra:Select at\
    \ the keyspace ARN (arn:aws:cassandra:<region>:<account>:/keyspace/<keyspace-name>) grants read on\
    \ all tables in that keyspace; apply the same CMK check per table's encryptionSpecification.kmsKeyIdentifier.\
    \ Do not emit ACTIVE when the table uses a customer-managed KMS key and the principal's kms:Decrypt\
    \ on that key has not been confirmed; emit CONDITIONAL(key_permission) instead."
  narrative: '{principal.name} can run CQL SELECT statements against {table.name} (cassandra:Select),
    reading all application data stored in the table. If {table.name} contains credentials or secrets,
    this yields further pivots via credential-chains:read-secret-yields-identity.'
move · open · esc close