aws-appflow-connector-cred-for-saas

An AppFlow connector profile's stored credential (OAuth token / API key) authenticates to the external SaaS system - reading the Secrets Manager secret yields a usable credential for that SaaS identity.

derived aws emits CredentialsFor

match

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

{'profile': None} ContainsSecret {'cred': None}

where

node_type(?profile) is a ConnectorProfile (Secret class) ?cred is the stored SaaS credential (OAuth token, API key, or password) ?cred is unexpired/active (connector profile is in a CREATED state, not DELETED or expired OAuth token)

emit

source typeSecret
target typeIdentity
source?cred
target<external SaaS identity / service account that ?cred authenticates (Salesforce user/org, Zendesk account, ServiceNow instance, etc.)>
state logicACTIVE when the stored credential is current (OAuth token unexpired or API key valid). CONDITIONAL when the token expiry or rotation state is unknown. BLOCKED when the connector profile is in an error state (OAuth revoked, API key invalidated). This is a structural fact — the edge's value is realized when combined with CanReadSecret via credential-chains read-secret-yields-identity.

Narrative

The credential stored in AppFlow connector profile {profile.name} ({cred.type}: OAuth token / API key) authenticates to the external SaaS system as {target.name}; an attacker who reads the Secrets Manager secret backing this profile (appflow!* prefix) obtains a working credential to access that SaaS directly, independent of AppFlow.

Raw rule rules/derived/aws/appflow.yaml

id: aws-appflow-connector-cred-for-saas
emits: CredentialsFor
description: "An AppFlow connector profile's stored credential (OAuth token / API key) authenticates to\
  \ the external SaaS system \u2014 reading the Secrets Manager secret yields a usable credential for\
  \ that SaaS identity."
applies_to:
- aws
match:
- - profile: null
  - ContainsSecret
  - cred: null
where:
- node_type(?profile) is a ConnectorProfile (Secret class)
- ?cred is the stored SaaS credential (OAuth token, API key, or password)
- ?cred is unexpired/active (connector profile is in a CREATED state, not DELETED or expired OAuth token)
emit:
  source_type: Secret
  target_type: Identity
  source: ?cred
  target: <external SaaS identity / service account that ?cred authenticates (Salesforce user/org, Zendesk
    account, ServiceNow instance, etc.)>
  permissions: []
  conditions: []
  state_logic: "ACTIVE when the stored credential is current (OAuth token unexpired or API key valid).\
    \ CONDITIONAL when the token expiry or rotation state is unknown. BLOCKED when the connector profile\
    \ is in an error state (OAuth revoked, API key invalidated). This is a structural fact \u2014 the\
    \ edge's value is realized when combined with CanReadSecret via credential-chains read-secret-yields-identity."
  confidence: 0.75
  derived_from:
  - ?profile ContainsSecret ?cred
  - 'credential-chains.yaml read-secret-yields-identity (cited: CanReadSecret + CredentialsFor -> CanImpersonate)'
  false_positive_note: "OAuth2 tokens expire and may be automatically refreshed by AppFlow. An expired\
    \ token that AppFlow has not refreshed (e.g. revoked by the SaaS admin) should NOT yield a CredentialsFor\
    \ edge \u2014 do not emit when the connector profile is in an error/auth-failure state. Limit the\
    \ SaaS identity target to what the stored credential scope permits (an OAuth token may be scoped to\
    \ read-only or a subset of objects in the SaaS). API keys and basic-auth credentials are long-lived\
    \ and yield ACTIVE unless the profile is in error. This edge does NOT model reading the credential\
    \ \u2014 that is CanReadSecret (aws-appflow-read-sm-saas-secret). The credential-chains roll-up (CanReadSecret\
    \ + CredentialsFor -> CanImpersonate) is OWNED by credential-chains.yaml; do not re-derive CanImpersonate\
    \ here."
  narrative: 'The credential stored in AppFlow connector profile {profile.name} ({cred.type}: OAuth token
    / API key) authenticates to the external SaaS system as {target.name}; an attacker who reads the Secrets
    Manager secret backing this profile (appflow!* prefix) obtains a working credential to access that
    SaaS directly, independent of AppFlow.'
move · open · esc close