aws-rolesanywhere-federate-in

A cert holder whose subject satisfies a Roles Anywhere role trust can CreateSession to obtain that role's temporary credentials.

derived aws emits CanFederateAs

match

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

{'ext': None} ExternalIdentityMapsTo {'role': None}

where

node_type(?ext) in [ExternalIdentity, FederatedIdentity] # the client-cert subject node_type(?role) == Role exists TrustsExternalIdentity(?role -> ?ext) with condition C # role trust trusts rolesanywhere.amazonaws.com, anchored on the trust-anchor CA

optional

Present → upgrade the emitted state; absent → downgrade (not a hard requirement).

condition: trust_condition_is_broad(TrustsExternalIdentity(?role -> ?ext)) # attacker_controllable(?ext) == true

emit

source typeFederatedIdentity
target typeRole
source?ext
target?role
permissionssts:AssumeRole sts:TagSession sts:SetSourceIdentity
conditionstrust_condition
state logicif the role trust condition is BROAD/UNPINNED so an attacker-obtainable cert matches — NO aws:PrincipalTag/x509Subject/CN (or /x509SAN/* or /x509Issuer/CN) condition, OR a wildcard one, AND/OR no aws:SourceArn pin (docs: any trust anchor in the account can then drive any such role) — OR the attacker demonstrably holds a matching cert: ACTIVE. If the trust PINS a specific cert subject/SAN/issuer the attacker cannot present: CONDITIONAL(trust_condition) — realizable only once the attacker obtains a matching cert (e.g. via the forge-cert path in federation-chains.yaml forge-cert-yields-federation, or a leaked private key). Inherit weakest with the backing TrustsExternalIdentity / ExternalIdentityMapsTo: a disabled trust anchor / disabled profile / revoked cert (on an imported CRL) => the adapter drops the trust => this rule does not fire; an explicit STS deny/SCP => BLOCKED.

Narrative

{ext.name} holds an X.509 certificate accepted by {role.name}'s Roles Anywhere trust (validated by trust anchor {anchor.name}); because that trust's condition is {trust_condition_summary}, it can call rolesanywhere:CreateSession and obtain {role.name}'s temporary credentials with no static AWS key.

Raw rule rules/derived/aws/rolesanywhere.yaml

id: aws-rolesanywhere-federate-in
emits: CanFederateAs
description: A cert holder whose subject satisfies a Roles Anywhere role trust can CreateSession to obtain
  that role's temporary credentials.
match:
- - ext: null
  - ExternalIdentityMapsTo
  - role: null
where:
- 'node_type(?ext) in [ExternalIdentity, FederatedIdentity]  # the client-cert subject'
- node_type(?role) == Role
- 'exists TrustsExternalIdentity(?role -> ?ext) with condition C  # role trust trusts rolesanywhere.amazonaws.com,
  anchored on the trust-anchor CA'
optional:
- 'condition: trust_condition_is_broad(TrustsExternalIdentity(?role -> ?ext))  # attacker_controllable(?ext)
  == true'
emit:
  source_type: FederatedIdentity
  target_type: Role
  source: ?ext
  target: ?role
  permissions:
  - sts:AssumeRole
  - sts:TagSession
  - sts:SetSourceIdentity
  conditions:
  - trust_condition
  state_logic: "if the role trust condition is BROAD/UNPINNED so an attacker-obtainable cert matches \u2014\
    \ NO aws:PrincipalTag/x509Subject/CN (or /x509SAN/* or /x509Issuer/CN) condition, OR a wildcard one,\
    \ AND/OR no aws:SourceArn pin (docs: any trust anchor in the account can then drive any such role)\
    \ \u2014 OR the attacker demonstrably holds a matching cert: ACTIVE. If the trust PINS a specific\
    \ cert subject/SAN/issuer the attacker cannot present: CONDITIONAL(trust_condition) \u2014 realizable\
    \ only once the attacker obtains a matching cert (e.g. via the forge-cert path in federation-chains.yaml\
    \ forge-cert-yields-federation, or a leaked private key). Inherit weakest with the backing TrustsExternalIdentity\
    \ / ExternalIdentityMapsTo: a disabled trust anchor / disabled profile / revoked cert (on an imported\
    \ CRL) => the adapter drops the trust => this rule does not fire; an explicit STS deny/SCP => BLOCKED."
  confidence: min(contributing_confidences)
  derived_from:
  - ?ext ExternalIdentityMapsTo ?role
  - ?role TrustsExternalIdentity ?ext (backing Roles Anywhere trust, condition C)
  false_positive_note: "The entire judgment is in the trust CONDITION \u2014 do NOT emit ACTIVE for a\
    \ well-pinned role trust. A trust policy conditioning on a specific aws:PrincipalTag/x509Subject/CN,\
    \ a specific x509SAN/URI (e.g. a SPIFFE ID), or a specific x509Issuer/CN the attacker cannot mint\
    \ is a legitimate control => CONDITIONAL(trust_condition). ACTIVE only when the cert-attribute condition\
    \ is ABSENT/broad OR the aws:SourceArn pin is missing so any registered anchor's certs qualify (per\
    \ the account-level trust boundary in the docs), OR the attacker controls a matching cert. Do NOT\
    \ treat the mere existence of a Roles Anywhere federation as compromise. If ?role is not actually\
    \ reachable via an ENABLED profile + ENABLED trust anchor, the mapping should not exist. A revoked\
    \ cert (imported CRL) never federates. Defers the CanFederateAs -> CanEnterAccount foothold and the\
    \ CanImpersonate/inheritance roll-up to federation-chains.yaml (federate-then-enter-account / federate-inherits-capabilities)\
    \ \u2014 not re-emitted here."
  narrative: '{ext.name} holds an X.509 certificate accepted by {role.name}''s Roles Anywhere trust (validated
    by trust anchor {anchor.name}); because that trust''s condition is {trust_condition_summary}, it can
    call rolesanywhere:CreateSession and obtain {role.name}''s temporary credentials with no static AWS
    key.'
move · open · esc close