3.1. Bootstrap
In this lab you will provision the Azure prerequisites every participant needs before creating their Pulumi project: a Blob Storage backend for state and a Key Vault key for secret encryption.
Step 1 — Bootstrap the State Storage
The state backend must exist before Pulumi can use it, so it is created with the az CLI rather than
Pulumi itself. Run the following commands to create a dedicated Resource Group, Storage Account, and Blob
Container:
Explanation
$RANDOM is a shell built-in that returns a random integer, giving the storage account a unique suffix
without any extra tooling. Storage account names must be globally unique across all of Azure, so a random
suffix is the simplest solution for a workshop environment.
Storage Blob Data Contributor grants blob data-plane access via Azure AD. Even a subscription Owner
only has management-plane rights over storage accounts — blob read/write via --auth-mode login requires
this explicit data-plane role.
--public-access off --auth-mode login means the container is private and access is controlled via
Entra ID RBAC — no storage account keys are created or stored.
Troubleshooting: SubscriptionNotFound
If az storage account create fails with SubscriptionNotFound, there are two common causes:
1. Wrong tenant — your subscription may live in a different Azure AD tenant than your default login. Check which subscriptions are visible:
If the target subscription is missing, re-login with its tenant:
2. Storage provider not registered — new subscriptions don’t have all resource providers enabled by
default. Register Microsoft.Storage and wait for it to complete:
Re-run the az storage account create command once the state shows Registered.
Why not create the storage account with Pulumi?
Pulumi needs a state backend before it can manage any resources. Using Pulumi to create its own backend
is a chicken-and-egg problem — the az CLI bootstrap sidesteps it cleanly.
Step 2 — Bootstrap the Secret Provider
Pulumi encrypts secret config values at rest. The default is a passphrase, but for a team environment you
want a cloud-managed key so every team member can decrypt secrets without sharing a passphrase. Create an
Azure Key Vault and a key named pulumi that Pulumi will use as the encryption key:
Explanation
$RANDOM gives the vault a unique suffix — Key Vault names must be globally unique across Azure, just like
storage account names.
--enable-rbac-authorization disables the legacy access-policy model and enforces Entra ID RBAC for all
data-plane operations — consistent with the storage account setup in Step 1. Crucially, this separates
management-plane rights (create/configure the vault) from data-plane rights (use keys and secrets).
Even a subscription Owner needs an explicit data-plane role assignment — the Key Vault Crypto Officer
role grants the create/import/delete key operations Pulumi requires.
Pulumi uses the Azure Key Vault wrap/unwrap API to encrypt and decrypt secret values — it never stores the raw key material.
Troubleshooting: MissingSubscriptionRegistration
If az keyvault create fails with MissingSubscriptionRegistration, the Key Vault resource provider is
not yet enabled on the subscription. Register it and wait for completion:
Re-run the az keyvault create command once registration completes.
Why a dedicated key?
Using a Key Vault key instead of a passphrase means secrets are tied to your Azure identity. Access can be revoked per user via RBAC, rotated centrally, and audited through Key Vault diagnostic logs — none of which is possible with a shared passphrase.