aws-rolesanywhere-config-add-trust-anchor
Registering an attacker-controlled CA as a trust anchor lets the attacker mint certs that federate into any role trusting the Roles Anywhere service principal.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'principal': None}
CanAdminister {'raConfig': None}
{'role': None} TrustsExternalIdentity {'ext': None}
where
node_type(?raConfig) == ManagementService # the Roles Anywhere config resource (trust-anchor surface)
?principal has EFFECTIVE rolesanywhere:CreateTrustAnchor OR rolesanywhere:UpdateTrustAnchor on ?raConfig (+ rolesanywhere:EnableTrustAnchor if disabled)
node_type(?role) ==
Role
the ?role -> ?ext TrustsExternalIdentity fact names Principal.Service == rolesanywhere.amazonaws.com with NO aws:SourceArn pin (so the newly-registered anchor qualifies) and a cert-attribute condition the attacker can satisfy with a self-minted cert
emit
| source type | Identity |
|---|---|
| target type | Role |
| source | ?principal |
| target | ?role |
| permissions | rolesanywhere:CreateTrustAnchor rolesanywhere:UpdateTrustAnchor rolesanywhere:EnableTrustAnchor? |
| conditions | trust_condition iam_permission |
| state logic | ACTIVE when a target role trusts the service principal with NO aws:SourceArn pin (any anchor qualifies) AND either no cert-subject condition or one the attacker can satisfy with a cert minted from its own CA (attacker chooses the subject/SAN). CONDITIONAL(trust_condition) when every candidate role pins aws:SourceArn to an EXISTING anchor (the new anchor won't match) or pins a cert subject/issuer the attacker cannot mint. BLOCKED if an SCP denies rolesanywhere:CreateTrustAnchor/UpdateTrustAnchor. Also needs a profile mapping the target role (see rule 3) unless one already exists — otherwise POTENTIAL(profile_required). |
Narrative
{principal.name} can register a certificate authority it controls as a Roles Anywhere trust anchor (rolesanywhere:CreateTrustAnchor); it can then mint a client certificate and federate into {role.name} (which trusts the Roles Anywhere service principal), self-granting access to {role.name}.
Raw rule rules/derived/aws/rolesanywhere.yaml
id: aws-rolesanywhere-config-add-trust-anchor
emits: CanModifyTrust
description: Registering an attacker-controlled CA as a trust anchor lets the attacker mint certs that
federate into any role trusting the Roles Anywhere service principal.
match:
- - principal: null
- CanAdminister
- raConfig: null
- - role: null
- TrustsExternalIdentity
- ext: null
where:
- 'node_type(?raConfig) == ManagementService # the Roles Anywhere config resource (trust-anchor surface)'
- ?principal has EFFECTIVE rolesanywhere:CreateTrustAnchor OR rolesanywhere:UpdateTrustAnchor on ?raConfig
(+ rolesanywhere:EnableTrustAnchor if disabled)
- node_type(?role) == Role
- the ?role -> ?ext TrustsExternalIdentity fact names Principal.Service == rolesanywhere.amazonaws.com
with NO aws:SourceArn pin (so the newly-registered anchor qualifies) and a cert-attribute condition
the attacker can satisfy with a self-minted cert
emit:
source_type: Identity
target_type: Role
source: ?principal
target: ?role
permissions:
- rolesanywhere:CreateTrustAnchor
- rolesanywhere:UpdateTrustAnchor
- rolesanywhere:EnableTrustAnchor?
conditions:
- trust_condition
- iam_permission
state_logic: "ACTIVE when a target role trusts the service principal with NO aws:SourceArn pin (any\
\ anchor qualifies) AND either no cert-subject condition or one the attacker can satisfy with a cert\
\ minted from its own CA (attacker chooses the subject/SAN). CONDITIONAL(trust_condition) when every\
\ candidate role pins aws:SourceArn to an EXISTING anchor (the new anchor won't match) or pins a cert\
\ subject/issuer the attacker cannot mint. BLOCKED if an SCP denies rolesanywhere:CreateTrustAnchor/UpdateTrustAnchor.\
\ Also needs a profile mapping the target role (see rule 3) unless one already exists \u2014 otherwise\
\ POTENTIAL(profile_required)."
confidence: min(contributing_confidences) * 0.9
derived_from:
- ?principal CanAdminister ?raConfig (effective rolesanywhere:CreateTrustAnchor|UpdateTrustAnchor decision)
- ?role TrustsExternalIdentity ?ext (role trusts rolesanywhere.amazonaws.com, no aws:SourceArn pin)
note: 'Registering the anchor is only half the takeover: the attacker also needs a PROFILE that lists
the target role (rule 3) and the role''s trust must admit the new anchor. Where a permissive profile
already lists the role, this alone completes the self-grant.'
false_positive_note: "Do NOT emit ACTIVE against roles that pin aws:SourceArn to a specific existing\
\ trust anchor \u2014 a newly registered anchor's ARN will not match, so a self-minted cert is rejected\
\ (keep CONDITIONAL(trust_condition)). An external-CA trust anchor requires the attacker to hold that\
\ CA's private key; an ACM PCA anchor requires CanSignAs on the PCA (Phase-5 aws:acmpca) \u2014 if\
\ the attacker cannot actually issue from the referenced CA, downgrade. Requires no iam:PassRole for\
\ the anchor itself, but the paired profile (rule 3) does. This models trust ADDITION, distinct from\
\ aws-update-assume-role-policy (which rewrites an existing role trust) \u2014 cite, do not double-count."
narrative: '{principal.name} can register a certificate authority it controls as a Roles Anywhere trust
anchor (rolesanywhere:CreateTrustAnchor); it can then mint a client certificate and federate into
{role.name} (which trusts the Roles Anywhere service principal), self-granting access to {role.name}.'