forge-cert-yields-federation
Issuing a certificate from a CA that is the trust anchor of a federation lets the issuer mint a matching external identity and federate in.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'p': None}
CanSignAs {'ca': None}
{'anchor': None} TrustsExternalIdentity {'ext': None}
{'ext': None} ExternalIdentityMapsTo {'internal': None}
where
node_type(?ca) ==
SigningKey # a certificate-authority signer (acmpca CA / gcp CAS pool)
trust_anchor_of(?anchor -> ?ext) == ?ca # the trust validates certs issued by THIS CA, not merely present in the account
node_type(?ext) in [ExternalIdentity, FederatedIdentity]
node_type(?internal) in [Role, ServiceAccount, MachineIdentity]
emit
| source type | FederatedIdentity |
|---|---|
| target type | Role |
| source | ?ext |
| target | ?internal |
| permissions | <CA issue/sign action, e.g. acm-pca:IssueCertificate | privateca certificates.create> |
| conditions | trust_condition cert_subject_condition |
| state logic | CONDITIONAL(trust_condition) by default: even with CA-issuance, the trust's profile/role condition on the certificate SUBJECT/SAN (RolesAnywhere profile `x509Subject`/SAN mapping, or the role trust `sub` derived from cert fields) must admit a subject the attacker can put in the forged cert. ACTIVE only when that cert-subject condition is ABSENT or BROAD (no subject pin / attacker can choose the SAN) so a freshly-minted cert matches — the X.509 analogue of the unpinned-subject case in rule 1. Inherit weakest with CanSignAs: if the CA issuance is CONDITIONAL (acm-pca TemplateArn restriction, key-policy gate) or BLOCKED, the federation carries that state. Never ACTIVE when the profile pins the cert subject/SAN to a value the attacker cannot present. |
Narrative
{p.name} can issue certificates from {ca.name}, which is the trust anchor for {anchor.name}'s federation; it can mint a client certificate whose subject satisfies the trust, presenting an external identity it controls to federate in as {internal.name}.
Raw rule rules/derived/federation-chains.yaml
id: forge-cert-yields-federation
emits: CanFederateAs
description: Issuing a certificate from a CA that is the trust anchor of a federation lets the issuer
mint a matching external identity and federate in.
applies_to:
- '*'
match:
- - p: null
- CanSignAs
- ca: null
- - anchor: null
- TrustsExternalIdentity
- ext: null
- - ext: null
- ExternalIdentityMapsTo
- internal: null
where:
- 'node_type(?ca) == SigningKey # a certificate-authority signer (acmpca CA / gcp CAS pool)'
- 'trust_anchor_of(?anchor -> ?ext) == ?ca # the trust validates certs issued by THIS CA, not merely
present in the account'
- node_type(?ext) in [ExternalIdentity, FederatedIdentity]
- node_type(?internal) in [Role, ServiceAccount, MachineIdentity]
emit:
source_type: FederatedIdentity
target_type: Role
source: ?ext
target: ?internal
permissions:
- <CA issue/sign action, e.g. acm-pca:IssueCertificate | privateca certificates.create>
conditions:
- trust_condition
- cert_subject_condition
state_logic: "CONDITIONAL(trust_condition) by default: even with CA-issuance, the trust's profile/role\
\ condition on the certificate SUBJECT/SAN (RolesAnywhere profile `x509Subject`/SAN mapping, or the\
\ role trust `sub` derived from cert fields) must admit a subject the attacker can put in the forged\
\ cert. ACTIVE only when that cert-subject condition is ABSENT or BROAD (no subject pin / attacker\
\ can choose the SAN) so a freshly-minted cert matches \u2014 the X.509 analogue of the unpinned-subject\
\ case in rule 1. Inherit weakest with CanSignAs: if the CA issuance is CONDITIONAL (acm-pca TemplateArn\
\ restriction, key-policy gate) or BLOCKED, the federation carries that state. Never ACTIVE when the\
\ profile pins the cert subject/SAN to a value the attacker cannot present."
confidence: min(contributing_confidences) * 0.9
derived_from:
- ?p CanSignAs ?ca
- ?anchor TrustsExternalIdentity ?ext (anchored on ?ca)
- ?ext ExternalIdentityMapsTo ?internal
false_positive_note: "Conservative and tight, mirroring credential-chains sign-as-yields-impersonation:\
\ CA-issuance yields federation ONLY when ?ca is the ACTUAL trust anchor of the federation (trust_anchor_of\
\ == ?ca), not merely a CA that exists in the account. Honor the certificate-subject condition: AWS\
\ IAM Roles Anywhere profiles and role trust policies constrain on cert Subject/CN/SAN and issuer\
\ \u2014 if the profile/role pins a subject the attacker cannot mint (a specific CN, an acm-pca:TemplateArn\
\ restricting the issued cert), keep CONDITIONAL(trust_condition, cert_subject_condition). Respect\
\ the CA-issuance gate from Phase-5 acmpca (acm-pca:IssueCertificate scoped by TemplateArn) / gcp\
\ CAS (privateca.certificates.create on the CA pool with a permitted certificate template) \u2014\
\ a CanSignAs that is itself CONDITIONAL/BLOCKED does not yield an ACTIVE federation. This does NOT\
\ model generic cert issuance as compromise \u2014 without a federation consuming the cert it stays\
\ at CanSignAs (cite credential-chains: signing needs a consuming trust)."
narrative: '{p.name} can issue certificates from {ca.name}, which is the trust anchor for {anchor.name}''s
federation; it can mint a client certificate whose subject satisfies the trust, presenting an external
identity it controls to federate in as {internal.name}.'