messaging-schedule-persists-executes-as
Creating a schedule/rule that invokes a target as a passed execution identity is persistence and yields execution as that identity.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'principal': None}
CanSchedule {'schedule': None}
{'principal': None} CanPassIdentity {'identity': None}
where
emit
| source type | Identity |
|---|---|
| target type | Identity |
| source | ?principal |
| target | ?identity |
| conditions | role_compatibility iam_permission |
| state logic | ACTIVE when the principal can create/configure the schedule AND can pass ?identity to the schedule's invocation service (iam:PassRole scoped to the scheduler/target service, or actAs on the SA) AND the target the schedule invokes runs the passed identity — the schedule then fires on its cadence executing as ?identity with no further attacker action (persistence). POTENTIAL(role_compatibility) when the identity's trust / PassedToService is unknown/unresolved. Never stronger than the contributing CanSchedule / CanPassIdentity; a deny on PutTargets/ CreateSchedule or a PassRole condition excluding the scheduler service blocks it. |
Narrative
{principal.name} can create a schedule/rule ({schedule.name}) that invokes a target as {identity.name} ({perm:CanPassIdentity} to the scheduler's service); the schedule fires on its cadence executing as {identity.name}, giving persistent execution as that identity.
Raw rule rules/derived/messaging-chains.yaml
id: messaging-schedule-persists-executes-as
emits: CanExecuteAs
description: Creating a schedule/rule that invokes a target as a passed execution identity is persistence
and yields execution as that identity.
applies_to:
- '*'
match:
- - principal: null
- CanSchedule
- schedule: null
- - principal: null
- CanPassIdentity
- identity: null
where:
- node_type(?schedule) in [Scheduler, EventRule, Workflow]
- role_compatible(?identity, ?schedule)
emit:
source_type: Identity
target_type: Identity
source: ?principal
target: ?identity
permissions: []
conditions:
- role_compatibility
- iam_permission
state_logic: "ACTIVE when the principal can create/configure the schedule AND can pass ?identity to\
\ the schedule's invocation service (iam:PassRole scoped to the scheduler/target service, or actAs\
\ on the SA) AND the target the schedule invokes runs the passed identity \u2014 the schedule then\
\ fires on its cadence executing as ?identity with no further attacker action (persistence). POTENTIAL(role_compatibility)\
\ when the identity's trust / PassedToService is unknown/unresolved. Never stronger than the contributing\
\ CanSchedule / CanPassIdentity; a deny on PutTargets/ CreateSchedule or a PassRole condition excluding\
\ the scheduler service blocks it."
confidence: min(contributing_confidences) * 0.95
derived_from:
- ?principal CanSchedule ?schedule
- ?principal CanPassIdentity ?identity
false_positive_note: "Honor the pass constraint: a role passable only to (say) ec2/ecs does NOT yield\
\ execution via a scheduler that needs scheduler.amazonaws.com in iam:PassedToService \u2014 downgrade\
\ to POTENTIAL(role_compatibility) when the trust / PassedToService is unknown, BLOCKED when it explicitly\
\ excludes the scheduler's service. The identity must be one the SCHEDULE runs its target as (a scheduler\
\ execution role, a Cloud Scheduler OIDC SA, an Automation run-as account), not an unrelated identity.\
\ This is the persistence framing of can-execute-as's config-identity-swap / create-workload-as (a\
\ schedule is a workload the attacker binds an identity to) \u2014 dedupes with those on (CanExecuteAs,\
\ ?principal, ?identity); emit once. The escalation roll-up is can-execute-as / can-control's, not\
\ re-derived."
narrative: '{principal.name} can create a schedule/rule ({schedule.name}) that invokes a target as {identity.name}
({perm:CanPassIdentity} to the scheduler''s service); the schedule fires on its cadence executing
as {identity.name}, giving persistent execution as that identity.'