azure-auto-runbook-write
Overwrite or create a runbook (PowerShell/Python) in an Automation Account; content executes as the account MI on next job.
match (effective permission)
{
"any_of": [
{
"action": "Microsoft.Automation/automationAccounts/runbooks/write",
"scope_type": "resource|resourceGroup|subscription"
},
{
"action": "Microsoft.Automation/automationAccounts/runbooks/draft/write",
"scope_type": "resource|resourceGroup|subscription"
}
]
}
where
principal effectively holds the runbook write action at the automationAccount scope
emit
| source type | Identity |
|---|---|
| target type | GenericCompute |
| source | <principal> |
| target | <runbook (BuildWorker) in the automationAccount> |
| permissions | Microsoft.Automation/automationAccounts/runbooks/write Microsoft.Automation/automationAccounts/runbooks/draft/write |
| conditions | service_state trigger_exists |
| state logic | ACTIVE when principal also holds automationAccounts/jobs/write (confirmed run path) AND the account is not suspended. CONDITIONAL(trigger_exists) when runbook-write is confirmed but jobs/write is absent — code is planted but requires an existing schedule, webhook, or a different principal to start a job. CONDITIONAL(service_state) if the account is suspended. Publishing a draft requires automationAccounts/runbooks/publish/action in addition to draft/write (full runbooks/write includes publish implicitly). BLOCKED if a deny assignment covers runbooks/write at the scope. |
Narrative
{principal.name} can overwrite or create runbook code in Automation Account {target.name} (automationAccounts/runbooks/write); the content is arbitrary PowerShell/Python that executes as the account's managed identity on the next job. cicd-chains cicd-modify-buildspec-executes-as collapses this with ExecutesAs to CanExecuteAs(managed identity) when a run path exists.
Raw rule rules/derived/azure/automation.yaml
id: azure-auto-runbook-write
emits: CanModifyCode
description: Overwrite or create a runbook (PowerShell/Python) in an Automation Account; content executes
as the account MI on next job.
match_effective_permission:
any_of:
- action: Microsoft.Automation/automationAccounts/runbooks/write
scope_type: resource|resourceGroup|subscription
- action: Microsoft.Automation/automationAccounts/runbooks/draft/write
scope_type: resource|resourceGroup|subscription
where:
- principal effectively holds the runbook write action at the automationAccount scope
emit:
source_type: Identity
target_type: GenericCompute
source: <principal>
target: <runbook (BuildWorker) in the automationAccount>
permissions:
- Microsoft.Automation/automationAccounts/runbooks/write
- Microsoft.Automation/automationAccounts/runbooks/draft/write
conditions:
- service_state
- trigger_exists
state_logic: "ACTIVE when principal also holds automationAccounts/jobs/write (confirmed run path) AND\
\ the account is not suspended. CONDITIONAL(trigger_exists) when runbook-write is confirmed but jobs/write\
\ is absent \u2014 code is planted but requires an existing schedule, webhook, or a different principal\
\ to start a job. CONDITIONAL(service_state) if the account is suspended. Publishing a draft requires\
\ automationAccounts/runbooks/publish/action in addition to draft/write (full runbooks/write includes\
\ publish implicitly). BLOCKED if a deny assignment covers runbooks/write at the scope."
confidence: 0.97
derived_from:
- 'effective permission: Microsoft.Automation/automationAccounts/runbooks/write OR runbooks/draft/write'
- 'cicd-chains.yaml: cicd-modify-buildspec-executes-as'
false_positive_note: runbooks/write alone does NOT start a job; publishing (runbooks/publish/action)
and job creation (jobs/write) are separate operations. Draft/write requires publish/action as an additional
step before the draft becomes the active runbook version. Without jobs/write or an existing trigger/schedule
that fires the modified runbook, this is CONDITIONAL(trigger_exists), not ACTIVE. Automation Operator
holds jobs/write but NOT runbooks/write; Automation Job Operator holds jobs/write but NOT runbooks/write.
The full code-execution chain requires both runbooks/write AND jobs/write (or an existing automated
trigger); confirm both before marking ACTIVE.
narrative: '{principal.name} can overwrite or create runbook code in Automation Account {target.name}
(automationAccounts/runbooks/write); the content is arbitrary PowerShell/Python that executes as the
account''s managed identity on the next job. cicd-chains cicd-modify-buildspec-executes-as collapses
this with ExecutesAs to CanExecuteAs(managed identity) when a run path exists.'