Skip to main content
emnode
Compliance

Encrypt Azure automation and configuration data

One capability for the secrets that hide inside your automation: make sure every Automation account variable that holds a credential, key or connection string is created as an encrypted secure asset, not a plain-text value anyone with read access can pull back.

12 min·10 sections·AZURE

Last reviewed

Remediates Microsoft Defender for Cloud: azure-automation-account-variables-encrypted

Encrypting automation data: the basics

What does an unencrypted Automation account variable actually expose?

Azure Automation runs the unglamorous plumbing of an estate: scheduled runbooks that patch servers, rotate keys, tag resources and tidy up storage. To do that work the runbooks need values, and those values live in Automation account variables. A variable can be created in one of two states. As an encrypted secure asset, the value is sealed with a per-account key and can never be read back, only used inside a runbook. Or as a plain-text variable, where the value is stored in the clear and anyone with read access to the account can retrieve it through the portal, the API or the CLI.

The problem is that variables are where secrets quietly accumulate. A webhook URL, an API key for a third-party service, a connection string, a service-account password: each starts life as a quick variable someone needed for a runbook, and unless they remembered to mark it encrypted, it sits there in plain text. Microsoft Defender for Cloud turns this into a single recommendation, 'Automation account variables should be encrypted', which flags every Automation account that holds at least one variable created without encryption. It is the data-protection control for the part of Azure most people forget holds secrets at all.

Most of this exposure is drift, not intent. A variable created in a hurry, a runbook ported from somewhere else, a value pasted in the portal where the encrypted toggle is easy to miss. The work is to find every plain-text variable across every Automation account, decide which ones actually hold sensitive data, recreate those as encrypted secure assets, and then assign a policy so no new plain-text secret can slip in unnoticed.

In this lesson you will learn how Azure Automation stores variables, why the encrypted-versus-plain-text choice is fixed at creation, how to find every unencrypted variable across your Automation accounts, and how to remediate the sensitive ones without breaking the runbooks that depend on them. The Controls this lesson covers section lists the Defender for Cloud recommendation in this capability, linking to a deep page with the exact check and a copy-and-paste fix.

Fun fact

The variable that outlived the runbook

Automation variables are deceptively sticky. A runbook gets retired, the schedule is deleted, the team that wrote it moves on, but the plain-text variable holding its service-account password stays in the account for years, still readable, still valid, still never rotated. Secret scanners and breach post-mortems repeatedly find that the most dangerous credentials are not the ones in active use but the forgotten ones left behind in places nobody thinks to check. An Automation account variable is exactly that kind of place, which is why the encrypted-by-default discipline matters even for plumbing nobody runs any more.

Finding unencrypted variables across an Automation account

Sam is the platform lead at a scale-up preparing for its first ISO 27001 audit. Defender for Cloud flags 'Automation account variables should be encrypted' on the operations Automation account, which has accumulated a dozen variables over two years of runbooks.

Rather than guess which variables are sensitive, Sam lists every variable in the account and its encryption state, so the plain-text values can be separated from the encrypted ones before anything is recreated.

List every variable in the Automation account with its encryption state. The encrypted ones are safe; the plain-text ones need review.

$ Get-AzAutomationVariable -ResourceGroupName rg-automation -AutomationAccountName aa-operations | Select-Object Name, Encrypted
Name Encrypted
---- ---------
PrimaryRegion True
SqlConnectionString False
SlackWebhookUrl False
# SqlConnectionString is a plain-text credential anyone with read access can pull back. Recreate it encrypted first.

A plain-text variable holding a connection string or key is the highest-value target. The value can be read back through the portal, the API or the CLI by anyone with read access to the account.

How Defender for Cloud decides an Automation variable is exposeddeep dive

Every Automation account variable carries an 'isEncrypted' property, set when the variable is created. When it is true, the value is stored as a secure asset: Azure Automation generates a unique key per Automation account, keeps it in a system-managed Key Vault, and uses it to encrypt the variable so it can be used inside a runbook but never read back through the portal or API. When 'isEncrypted' is false, the value is stored in the clear and any principal with read access to the account can retrieve it. The Defender for Cloud recommendation 'Automation account variables should be encrypted' flags any Automation account that holds at least one variable with 'isEncrypted' set to false.

The property is fixed at creation. There is no setting to flip an existing plain-text variable to encrypted: Azure does not let you change a variable's encryption state in place, because the value would have to be read and re-stored, defeating the point. Remediation therefore always means recreating the variable as an encrypted asset and deleting the plain-text original, which is why this control is a small but deliberate task rather than a one-click toggle.

Behind the recommendation is the Azure Policy 'Automation account variables should be encrypted' (definition 3657f5a0-770e-44a3-b44e-9431ba1e9735), which ships with an Audit effect by default and maps to Microsoft Cloud Security Benchmark control DP-4, enable data at rest encryption by default. Defender for Cloud evaluates it on a periodic cycle, so recreating a variable as encrypted clears the finding on the next assessment rather than instantly. Switching the policy to a Deny effect is what turns the control from 'we encrypted what was there' into 'no new plain-text variable can be created at all'.

What is the impact of leaving automation variables unencrypted?

The direct impact is a readable standing secret. A plain-text Automation variable holding a connection string, API key or service-account password can be retrieved by anyone with read access to the account, and unlike a runtime token it does not expire and is rarely rotated. That makes it one of the most valuable things an attacker can find after gaining even limited access: a working credential, in the clear, that often unlocks something far beyond Automation itself.

The second-order impact is blast radius. Automation runbooks frequently run with elevated rights to patch, configure and clean up across an estate, so the secrets they hold tend to be powerful ones. A leaked database connection string or service-account password is rarely scoped to one resource; it is a step toward lateral movement. Sealing the variables shrinks the standing-secret surface to nothing readable, which is the whole point of a secure asset.

On the compliance side, every modern framework, ISO 27001, SOC 2, HIPAA and PCI DSS, expects evidence that secrets and sensitive data at rest are encrypted, and that includes the secrets your automation depends on. PCI DSS in particular calls out stored credentials and connection strings directly. A passing 'Automation account variables should be encrypted' recommendation across every account is a cheap, specific artefact that this often-overlooked store of secrets is protected.

How do you encrypt automation variables safely?

Work the capability as one loop rather than fixing variables ad hoc. The order matters: identify which plain-text variables actually hold secrets before you recreate anything, and capture each value first, because recreating a variable means deleting the original.

1. Inventory every variable by encryption state

List every variable across every Automation account and whether it is encrypted. Treat this inventory as the source of truth, not the single Defender finding, because one account flags the recommendation regardless of how many plain-text variables it holds.

2. Separate real secrets from harmless values

Not every plain-text variable is a problem. A region name, a feature flag or a retention count carries no risk in the clear. Connection strings, API keys, webhook URLs, service-account passwords and tokens do. Decide which plain-text variables hold something an attacker could use, and prioritise those.

3. Recreate the sensitive variables as encrypted assets

Because encryption is fixed at creation, recreate each sensitive variable with the encrypted flag set and delete the plain-text original. Capture the current value first, since once encrypted it can never be read back, only used inside a runbook. For credentials that several runbooks share, consider moving them to Key Vault and referencing them instead, so they live in one managed, auditable place.

4. Ratchet it shut with Azure Policy

The built-in 'Automation account variables should be encrypted' policy ships as Audit. Assign it with a Deny effect so no new plain-text variable can be created, and the safe configuration is enforced rather than merely encouraged. Keep an audit assignment in scopes where a hard deny would be too disruptive while you clean up.

# Recreate a sensitive plain-text variable as an encrypted secure asset (PowerShell).
# Encryption is fixed at creation, so capture the value, then delete and recreate.
# az automation has no in-place toggle; the value can never be read back once encrypted.
pwsh -c '
  $rg   = "rg-automation"
  $acct = "aa-operations"
  $name = "SqlConnectionString"
  $val  = (Get-AzAutomationVariable -ResourceGroupName $rg `
             -AutomationAccountName $acct -Name $name).Value
  Remove-AzAutomationVariable -ResourceGroupName $rg `
    -AutomationAccountName $acct -Name $name -Force
  New-AzAutomationVariable -ResourceGroupName $rg `
    -AutomationAccountName $acct -Name $name -Value $val -Encrypted $true
'

# Ratchet it shut: assign the built-in policy with a Deny effect so no new
# plain-text variable can be created. Look the definition up by display name,
# never paste a guessed GUID.
pid=$(az policy definition list \
  --query "[?displayName=='Automation account variables should be encrypted'].name" -o tsv)

az policy assignment create \
  --name deny-unencrypted-automation-vars \
  --policy "$pid" \
  --params '{"effect":{"value":"Deny"}}' \
  --scope "/subscriptions/00000000-0000-0000-0000-000000000000"

Quick quiz

Question 1 of 5

Defender for Cloud flags 'Automation account variables should be encrypted' on one account. What does the finding tell you?

You can now treat the secrets inside your automation as one capability rather than a single red finding: inventory every variable by encryption state, separate the real secrets from harmless values, recreate the sensitive ones as encrypted secure assets, and ratchet the estate shut with the built-in deny policy. The Controls this lesson covers section below links the recommendation in this group to its deep page and fix.

Back to the library