azure-appconfig-listkeys-exposes-connstring

A principal with listKeys/action obtains the store's access-key connection strings (unless local auth is disabled).

derived azure emits ExposesCredential

match

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

{'principal': None} HasPermission {'store': None} {'store': None} Contains {'dataplane': None} {'dataplane': None} ContainsCredential {'connstring': None}

where

node_class(?store) == ManagementService provider_type(?store) == 'Microsoft.AppConfiguration/configurationStores' node_class(?dataplane) == Data ?dataplane is the store's data plane (all key-values) node_type(?connstring) == Credential # ExposesCredential target set is [Credential, Identity]; ConnectionString (a Secret-class subtype) is NOT a valid target. The explicit rule azure-appconfig-access-keys-present materializes the access-key connection strings as Credential nodes. ?principal has EFFECTIVE Microsoft.AppConfiguration/configurationStores/listKeys/action at the store scope (Contributor / Owner / custom role)

emit

source?dataplane
target?connstring
permissionsMicrosoft.AppConfiguration/configurationStores/listKeys/action
conditionsiam_permission service_state
state logicACTIVE if disableLocalAuth == false (access keys enabled) AND the principal holds listKeys/action. BLOCKED if disableLocalAuth == true (listKeys returns an empty list — no credential to expose). If disableLocalAuth is unknown, POTENTIAL(service_state).

Narrative

The data plane of {store.name} exposes its access-key connection string(s) to any principal with listKeys (Contributor/Owner); access keys are enabled.

Raw rule rules/derived/azure/appconfig.yaml

id: azure-appconfig-listkeys-exposes-connstring
emits: ExposesCredential
description: A principal with listKeys/action obtains the store's access-key connection strings (unless
  local auth is disabled).
match:
- - principal: null
  - HasPermission
  - store: null
- - store: null
  - Contains
  - dataplane: null
- - dataplane: null
  - ContainsCredential
  - connstring: null
where:
- node_class(?store) == ManagementService
- provider_type(?store) == 'Microsoft.AppConfiguration/configurationStores'
- node_class(?dataplane) == Data
- ?dataplane is the store's data plane (all key-values)
- 'node_type(?connstring) == Credential  # ExposesCredential target set is [Credential, Identity]; ConnectionString
  (a Secret-class subtype) is NOT a valid target. The explicit rule azure-appconfig-access-keys-present
  materializes the access-key connection strings as Credential nodes.'
- ?principal has EFFECTIVE Microsoft.AppConfiguration/configurationStores/listKeys/action at the store
  scope (Contributor / Owner / custom role)
emit:
  source: ?dataplane
  target: ?connstring
  permissions:
  - Microsoft.AppConfiguration/configurationStores/listKeys/action
  conditions:
  - iam_permission
  - service_state
  state_logic: "ACTIVE if disableLocalAuth == false (access keys enabled) AND the principal holds listKeys/action.\
    \ BLOCKED if disableLocalAuth == true (listKeys returns an empty list \u2014 no credential to expose).\
    \ If disableLocalAuth is unknown, POTENTIAL(service_state)."
  confidence: '0.95'
  derived_from:
  - ?principal HasPermission ?store (listKeys/action)
  - ?store Contains ?dataplane
  - ?dataplane ContainsCredential ?connstring
  false_positive_note: "BLOCKED when disableLocalAuth=true \u2014 do not emit an exposed connection string\
    \ that does not exist. This is the credential-leak fact; the actual data read is modeled by azure-appconfig-connstring-reads-all-kv.\
    \ Do NOT invoke listKeys during collection to confirm \u2014 infer from role assignments + disableLocalAuth.\
    \ ExposesCredential source is the store's Data-plane node, not the ManagementService store object\
    \ (schema source-set conformance)."
  narrative: The data plane of {store.name} exposes its access-key connection string(s) to any principal
    with listKeys (Contributor/Owner); access keys are enabled.
move · open · esc close