aws-rolesanywhere-federate-in
A cert holder whose subject satisfies a Roles Anywhere role trust can CreateSession to obtain that role's temporary credentials.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
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 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 — 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.'