You click the Cloud Shell icon to run one quick az command, and instead of a prompt you get a spinner that never resolves, or a red banner: “Error: 400 — could not create storage”, or “Mounting your Azure file share has failed.” Sometimes it worked yesterday and fails today; sometimes it provisions fine for you but blocks every colleague in the subscription. Cloud Shell feels like it should be the simplest surface in Azure — a browser terminal with the CLI pre-installed — which is exactly why a failure here is so disorienting: there’s no VM you own, no NIC to inspect, no obvious knob. The machinery is hidden, the error text is short, and the cause is somewhere you can’t see.
This is the playbook for that machinery. Azure Cloud Shell is a managed, browser-based shell (Bash or PowerShell) Microsoft runs for you in an ephemeral container, and the part that breaks is almost never the container — it’s the persistent storage mounted into it. To give you a ~/clouddrive that survives between sessions, Cloud Shell creates (or reuses) an Azure Files share on a storage account in your subscription and mounts a 5 GB disk image from it. Three things go wrong with that arrangement, and they account for nearly every Cloud Shell incident: the storage mount won’t provision (region mismatch, wrong account kind, RBAC, Azure Policy denial); the network blocks the storage account (a firewall or VNet rule the security team added); and the session times out or drops (the 20-minute idle limit, the ~24-hour cap, or a lost mount). We treat these as three symptom classes, each with a fan-out of causes you confirm with a specific command or portal path.
By the end you’ll stop guessing. When the shell won’t start you’ll know whether you face an unsupported storage region, a general-purpose v1 account Cloud Shell can’t use, an Azure Policy denying the create, a storage firewall that locked out the service, a deleted file share you can recover from soft-delete, or just an idle session that needs a clean remount. You’ll know mounted mode (persistent, needs storage) from ephemeral mode (no storage, files vanish on exit), and when each is right. And you’ll fix Cloud Shell for the whole subscription, not just paper over it for yourself — the difference between a five-minute fix and a recurring ticket.
What problem this solves
Cloud Shell hides a lot of infrastructure so you can type az group list in a browser. That abstraction is a gift until the mount fails, then it’s an opaque wall: the terminal that’s supposed to be your diagnostic tool is the thing that won’t start. The banner is deliberately terse — Cloud Shell can’t dump storage internals to an anonymous browser session — so the information you need is real and captured, but it lives in the storage account’s blades, the activity log, and the policy assignments, not the shell.
What breaks without this knowledge: an engineer who needs one command burns twenty minutes, gives up, and falls back to a local CLI that drifts out of date and behaves differently from everyone else’s. Worse, a security team enables a storage firewall or a “deny public storage accounts” policy across the subscription, not realising it just bricked Cloud Shell for the whole tenant — the help desk fills with “terminal won’t open” tickets that look like a platform outage but are self-inflicted. Or someone deletes the cloud-shell-storage-* resource group during a cleanup, not knowing it backs every session in that region.
Who hits this: anyone running Cloud Shell in a governed subscription, anyone in an unsupported storage region, teams that lock accounts behind private endpoints without configuring VNet-isolated Cloud Shell, and users whose long script dies at the 20-minute idle mark or whose ~/clouddrive files “randomly disappear” (they were ephemeral, or the mount dropped). The fix is rarely “wait and retry” — it’s “find the layer blocking the storage account and either fix it or tell Cloud Shell to go around it.”
To frame the whole field before the deep dive, here is every symptom class this article covers, the question it forces, and the one place to look first:
| Symptom class | What is actually failing | First question to ask | First place to look | Most common single cause |
|---|---|---|---|---|
| Mount won’t provision | Cloud Shell can’t create/use the file share | Did the storage-account create itself fail, or just the mount? | Activity log on cloud-shell-storage-<region> |
Azure Policy denying the create, or no write RBAC |
| Network blocks the storage | Firewall/VNet rule cuts the share off | Did storage networking change recently? | Storage account → Networking blade | Storage firewall set to “selected networks” |
| Session timeout / drop | Session ended or the mount fell away | Was it idle ~20 min, or near the 24 h cap? | The banner text + reconnect behaviour | 20-minute idle timeout |
| Files disappeared | Work isn’t persisting between sessions | Mounted or ephemeral session? | df -h / presence of ~/clouddrive |
Ephemeral (no-storage) session chosen |
| Wrong account kind/region | Storage exists but Cloud Shell rejects it | Is it GPv2 in a supported region? | az storage account show kind/sku |
GPv1 account, or unsupported region |
Learning objectives
By the end of this article you can:
- Explain exactly what Cloud Shell provisions on first launch — a resource group, a general-purpose v2 storage account, and an Azure Files share holding a 5 GB image mounted at
~/clouddrive— and why each piece can fail. - Diagnose a mount-provisioning failure as a region-support gap, a wrong account kind (GPv1 vs GPv2), an RBAC shortfall, or an Azure Policy denial — and confirm which with exact commands and portal paths.
- Diagnose a network block as a storage firewall (“selected networks”), a private-endpoint-only configuration, or a missing VNet-isolated Cloud Shell setup — and either allow-list correctly or stand up the isolated topology.
- Recover a deleted or corrupted file share from soft delete, and re-point Cloud Shell at the right storage account when the original is gone.
- Distinguish mounted from ephemeral (no-storage / transient) sessions, predict which one loses your files, and choose deliberately.
- Tame session timeouts: explain the 20-minute idle unmount and the maximum session length, keep long tasks alive, and recover a dropped session without losing work.
- Drive the core diagnostics fluently: the getStorageInfo REST path,
clouddrive mount/unmount, the storage Networking and File shares blades, the activity log, andaz policy state listto find the offending assignment.
Prerequisites & where this fits
You should understand the Azure basics Cloud Shell sits on: a storage account is the container for blobs, files, queues and tables, and Azure Files is its SMB/NFS file-share service; a resource group is a lifecycle boundary; RBAC grants rights at a scope; and Azure Policy can deny operations regardless of RBAC. Comfort with az JSON output and the portal blade layout helps. If storage accounts are new, read Azure Storage Account Fundamentals: Blobs, Files, Queues and Tables first; for the file-share half, Mount an Azure Files SMB Share on Windows and Linux: A Step-by-Step Quickstart covers the same mount mechanics Cloud Shell automates.
This sits in the Observability & Troubleshooting track but is upstream of almost everything else, because Cloud Shell is the tool many of those playbooks tell you to use. It pairs with Fixing Azure Storage 403 Errors: Firewalls, Private Endpoints, RBAC & SAS — the same firewall and RBAC traps that 403 your blobs also block Cloud Shell’s share — and with Managed Identities Demystified: System vs User-Assigned and When to Use Each when you use Cloud Shell’s identity for scripts.
A quick map of who owns each layer, so you call the right person fast during an incident:
| Layer | What lives here | Who usually owns it | Failure classes it can cause |
|---|---|---|---|
| Cloud Shell service | The container, the shell image, the mount logic | Microsoft (platform) | Transient provisioning errors; rare |
| Your identity / RBAC | Right to create + write the storage account | IT / subscription admin | Mount won’t provision (access denied) |
| Azure Policy | Deny/audit rules on storage create + config | Governance / platform team | Mount won’t provision (policy deny) |
| Storage account | The file share backing ~/clouddrive |
Storage / platform team | Mount fails; files lost if deleted |
| Storage networking | Firewall, VNet rules, private endpoints | Network / security team | Network block; share unreachable |
| Region availability | Whether Cloud Shell storage exists here | Microsoft (per region) | Mount won’t provision (unsupported region) |
| The user’s session | Idle state, session length, browser tab | The user | Timeout, drop, perceived data loss |
Core concepts
Five mental models make every later diagnosis obvious.
Cloud Shell is two halves: a throwaway compute container and a persistent file share. The compute half is an ephemeral Linux container discarded on disconnect — you own none of it and it’s almost never the cause. The persistent half survives: an Azure Files share, on a storage account in your subscription, holding a 5 GB image mounted at ~/clouddrive where your $HOME lives. Almost every failure is a failure to create, reach, or mount that file share — so “the shell is broken” is usually wrong; the storage is the suspect.
First launch silently creates real, billable resources. The first time anyone uses mounted Cloud Shell in a region, it creates a resource group cloud-shell-storage-<region>, a general-purpose v2 account (cs<hash>), and a file share (cs-<user>-<hash>) — normal resources, billed, subject to your Azure Policy, deletable by anyone with rights. If a policy blocks the create, or you lack write RBAC at the scope, first launch fails with a storage error and the shell never gets its clouddrive.
Mounted vs ephemeral is the fork that decides whether your files survive. Mounted (the default, “with storage”) attaches the file share so files persist across sessions — but requires a usable storage account. Ephemeral (surfaced as “no storage account required” / transient / the “No storage” path) skips the share entirely: an instant shell with no storage dependency, but everything in $HOME is destroyed when the session ends. It’s the right escape hatch when storage is blocked and you just need a command — but git clone into an ephemeral session, close the tab, and it’s gone. “My files disappeared” is almost always “I was ephemeral.”
The storage account has hard requirements, and a firewall can lock the service out. Cloud Shell only uses an account meeting its contract: general-purpose v2 (StorageV2) (v1 rejected), in a supported region, and reachable over the network. That last point is the silent killer: a firewall set to “selected virtual networks and IP addresses” or private-endpoints-only refuses the Cloud Shell service (which connects from Microsoft’s network, not your VNet), and the mount fails. Hardening the account breaks the shell unless you also set up VNet-isolated Cloud Shell.
The session is finite in two dimensions: idle and total. A session is unmounted after about 20 minutes of inactivity and the connection drops; independently it has a maximum lifetime (~24 hours). Neither destroys ~/clouddrive (that’s on the share), but both end the running container — a silent long script dies at the idle mark, a walked-away session drops. “It times out mid-work” is the idle limit doing its job.
The vocabulary in one table
Before the deep sections, pin down every moving part. The glossary at the end repeats these for lookup; this table is the mental model side by side:
| Concept | One-line definition | Where it lives | Why it matters to a failure |
|---|---|---|---|
| Cloud Shell | Browser-based managed Bash/PowerShell shell | Azure portal / shell.azure.com | The surface that won’t start |
| Compute container | The ephemeral VM/container running the shell | Microsoft-managed | Almost never the cause |
~/clouddrive |
Your persistent home, backed by a file share | Mounted from Azure Files | Lost mount → work seems gone |
| Backing storage account | GPv2 account holding the file share | cloud-shell-storage-<region> RG |
Must be GPv2, supported region, reachable |
| Azure Files share | The SMB share holding the 5 GB image | On the storage account | Deleted/blocked → mount fails |
| Mounted session | Session with the file share attached | Default experience | Needs working storage |
| Ephemeral session | No-storage session; $HOME is transient |
“No storage required” path | Files destroyed on exit |
| Storage firewall | “Selected networks” access rule | Storage → Networking | Blocks the service → mount fails |
| VNet-isolated Cloud Shell | Cloud Shell deployed into your VNet via Relay | Container + relay subnets | The supported way to use private storage |
| getStorageInfo | The REST call that returns/sets the mount target | ARM providers/Microsoft.Portal |
Where the configured account is recorded |
| Idle timeout | ~20 min of inactivity ends the session | Session lifecycle | Long no-output task dies |
clouddrive |
In-shell command to mount/unmount the drive | Inside the shell | Manual remount / re-point |
What Cloud Shell provisions, end to end
To fix the mount you have to know what it is. On first launch in the mounted experience, Cloud Shell walks a fixed sequence, and a failure at any step surfaces as the same terse banner — so knowing the steps tells you where to look.
| Step | What Cloud Shell does | Resource created / used | What can break it |
|---|---|---|---|
| 1 | Pick (or be told) a region | — | No supported region offered |
| 2 | Create the resource group | cloud-shell-storage-<region> |
RBAC: no create rights; policy deny |
| 3 | Create the storage account | cs<hash> (StorageV2, Standard LRS) |
Policy deny (kind/SKU/public access); quota |
| 4 | Create the file share | cs-<user>-<hash> (quota ~6 GB) |
Storage firewall; account not reachable |
| 5 | Create + mount the disk image | acc_<user>.img (5 GB) inside the share |
Share unreachable; soft-deleted; corrupted |
| 6 | Mount it at ~/clouddrive |
SMB mount into the container | Network path blocked mid-mount |
The names matter when hunting in the portal: the RG is always cloud-shell-storage-<region>; the account is cs + hash; the share is cs-<username>-<hash>; inside it sits acc_<user>.img, the 5 GB image that is your home directory. Delete the RG and you delete everyone’s Cloud Shell storage for that region; delete just the share and the next launch recreates it (recovering from soft delete if enabled). Crucially, Cloud Shell creates no networking — by default the account is a plain public-endpoint account the service reaches over the backbone. The moment someone adds networking restrictions (to that account or all accounts via policy), the arrangement breaks — the source of most “it worked, then it stopped” incidents.
Mounted vs ephemeral, precisely
The two experiences differ in every way that matters during a failure:
| Dimension | Mounted (persistent) | Ephemeral (no storage / transient) |
|---|---|---|
| Storage account required | Yes (GPv2, supported region, reachable) | No |
~/clouddrive present |
Yes | No |
| Files survive session end | Yes (on the file share) | No — destroyed on disconnect |
| First-launch dependency | Resource group + account + share | None |
| Starts when storage is blocked | No (that’s the failure) | Yes — the escape hatch |
| Good for | Real work, saved scripts, persistent tools | One-off commands, blocked-storage workaround |
| Billing | Small monthly file-share cost | None |
$HOME size |
5 GB image | Container-local, transient |
The practical rule: mounted for anything you keep, ephemeral only when storage is blocked and you need a command right now. If you keep “losing files,” check whether you’ve been defaulting into ephemeral — the portal offers it as the fast path when mounting fails, and people click through without reading.
Diagnosing a mount that won’t provision
This is the failure that stops you cold on a fresh subscription or after a governance change: the shell churns and returns a storage error instead of a prompt. Four distinct causes — scan the matrix, then read the detail for the row that matches your evidence.
| # | Cause | Tell-tale signal | Confirm with | Real fix |
|---|---|---|---|---|
| 1 | Unsupported region for Cloud Shell storage | No region offered, or create silently fails in that region | Try a different region from the dropdown; check supported-region list | Choose a supported region; let it create storage there |
| 2 | Wrong account kind (GPv1) being reused | “Storage account is not supported” when pointing at an existing account | az storage account show --query kind returns Storage |
Use/let it create a StorageV2 account |
| 3 | RBAC shortfall (no write at the scope) | “could not create storage” / access-denied flavour | az role assignment list for your principal at the RG/sub |
Get Contributor (or storage-create rights) at the scope |
| 4 | Azure Policy denial on the create | Banner mentions a policy / disallowed; create blocked despite RBAC | az policy state list filtered to deny; activity log “PolicyViolation” |
Exempt Cloud Shell storage, or fix the policy |
Cause 1 — The region doesn’t support Cloud Shell storage
Cloud Shell’s backing storage is only available in a subset of Azure regions. If your subscription is pinned to a region not on that list, the mounted experience can’t place storage there — the portal may not offer the region, or the create fails.
Confirm. In the first-run storage dialog, open the region dropdown — if your usual region isn’t listed, that’s the answer. Cloud Shell compute and storage regions are independent: the shell runs near you, but storage must live in a supported region, and only the storage region is constrained by the list.
Fix. Pick a supported region and let Cloud Shell create storage there — latency to your resources is unaffected by which region holds the image. If an allowedLocations Azure Policy is the real constraint, add a Cloud Shell storage region to the allowed list or grant an exemption (Cause 4).
Cause 2 — An existing storage account is the wrong kind
If you point Cloud Shell at a specific pre-existing account (for cost or governance), it must be general-purpose v2 (StorageV2). A legacy v1 (kind = Storage) or a BlobStorage account is rejected with a “storage account is not supported” error even though you clearly own it.
Confirm. Check the kind and SKU:
az storage account show --name csmystorage --resource-group rg-cloudshell \
--query "{kind:kind, sku:sku.name, region:location, access:allowBlobPublicAccess}" -o table
kind must be StorageV2. If it returns Storage (GPv1) or BlobStorage, that account can’t back Cloud Shell.
Fix. Either let Cloud Shell create its own StorageV2 account (the simplest path), or create a conformant one and point the shell at it:
az storage account create --name csteamshell --resource-group cloud-shell-storage-southeastasia \
--location southeastasia --sku Standard_LRS --kind StorageV2
az storage share-rm create --storage-account csteamshell --name cs-team-share --quota 6
A GPv1 account can also be upgraded in place (az storage account update --set kind=StorageV2) — irreversible, but data-preserving. The account-kind contract at a glance:
| Account kind | kind value |
Cloud Shell can use it? | Notes |
|---|---|---|---|
| General-purpose v2 | StorageV2 |
Yes | The required and recommended kind |
| General-purpose v1 | Storage |
No | Legacy; upgrade to v2 to use |
| BlobStorage | BlobStorage |
No | No file-share service for the mount |
| Premium FileStorage | FileStorage |
Not for the default mount | Cloud Shell provisions Standard; don’t force this |
| Premium BlockBlob/Page | BlockBlobStorage / others |
No | Wrong service shape |
Cause 3 — Your identity lacks rights to create the storage
First launch creates a resource group and a storage account. If you have only Reader at the subscription, or your write rights are scoped away from where Cloud Shell creates, the create fails with an access-denied error — common for least-privilege users in enterprise tenants.
Confirm. Check what your principal can do at the scope:
# Your role assignments at the subscription (and inherited down)
az role assignment list --assignee "$(az ad signed-in-user show --query id -o tsv)" \
--query "[].{role:roleDefinitionName, scope:scope}" -o table
If you see only Reader (or nothing implying write at the subscription / a Cloud Shell RG), you can’t create the backing storage; the RG’s activity log, if one exists, shows the failed Microsoft.Storage/storageAccounts/write with an authorization error.
Fix. Get Contributor (or a custom role with Microsoft.Storage/storageAccounts/write plus RG-create) at the subscription or a pre-created cloud-shell-storage-* RG. The clean enterprise pattern: an admin pre-creates the RG and a StorageV2 account, grants users Storage Account Contributor (or Contributor on that RG), and users point Cloud Shell at it — no one needs broad subscription write. For an immediate unblock, switch to the ephemeral experience and chase the RBAC fix separately.
Cause 4 — Azure Policy is denying the storage create
The subtle one in governed environments. RBAC is fine, but an Azure Policy with a Deny effect blocks the create — denying public-network-access accounts, enforcing a naming convention the autogenerated name violates, forbidding LRS, requiring a specific kind/SKU, or restricting locations. The policy engine rejects it, not RBAC — so “I’m Owner and it still won’t create” points straight here.
Confirm. In the subscription activity log, a failed operation with status PolicyViolation names the assignment. Via CLI:
# Recent denied/non-compliant policy states mentioning storage
az policy state list --filter "complianceState eq 'NonCompliant'" \
--query "[?contains(resourceType,'storageAccounts')].{policy:policyDefinitionName, assignment:policyAssignmentName, resource:resourceId}" \
-o table
# The deny that fired shows in the activity log as PolicyViolation
az monitor activity-log list --offset 1h \
--query "[?status.value=='Failed' && contains(operationName.value,'storageAccounts/write')].{op:operationName.value, sub:substatus.value, reason:properties.statusMessage}" \
-o json
The statusMessage typically contains RequestDisallowedByPolicy and the offending policy’s display name.
Fix. Three options, in order of preference: (a) a policy exemption scoped to the cloud-shell-storage-* RG; (b) pre-create a compliant account by hand (correct name, kind, SKU, public-access setting) and point Cloud Shell at it so the autogenerated create never runs; © adjust the policy to exclude Cloud Shell’s RGs (often a not condition). The exemption:
az policy exemption create --name exempt-cloudshell-storage \
--policy-assignment "<assignment-id>" --exemption-category Waiver \
--resource-group cloud-shell-storage-southeastasia \
--description "Cloud Shell backing storage; service-managed"
The deny-policies that most often bite Cloud Shell:
| Policy intent | Effect on Cloud Shell | Typical statusMessage clue |
Cleanest fix |
|---|---|---|---|
| Deny public network access on storage | Create blocked (Cloud Shell account is public by default) | RequestDisallowedByPolicy + public-access rule |
VNet-isolated Cloud Shell, or exempt the RG |
| Enforce naming convention | Autogenerated cs<hash> name rejected |
naming pattern in message | Pre-create a compliant-named account |
| Allowed locations only | Create blocked in the chosen region | allowedLocations |
Add a supported region or exempt |
| Require ZRS/GRS (deny LRS) | Cloud Shell creates Standard_LRS → denied | SKU constraint in message | Pre-create with allowed SKU; point shell at it |
| Require specific tags | Untagged create denied | tag-requirement in message | Pre-create the account with tags |
| Deny GPv2 / require specific kind | Rare, but blocks the create | kind constraint | Align policy with StorageV2 |
Diagnosing a network block on the backing storage
This is the “it worked yesterday” failure, almost always a storage-networking change. The account exists and is the right kind, but a firewall or VNet rule now blocks the Cloud Shell service, so the mount fails. The trap: you can still open the account in the portal (allow-listed by your own IP), while the Cloud Shell service — coming from Microsoft’s network — is refused.
| # | Cause | Tell-tale signal | Confirm with | Real fix |
|---|---|---|---|---|
| 1 | Storage firewall set to “selected networks” | Mount fails after a networking change; account reachable from portal | Storage → Networking shows “Selected networks” | Allow trusted services / use VNet-isolated Cloud Shell |
| 2 | Private-endpoint-only (public access disabled) | Public path off; only private endpoints allowed | publicNetworkAccess = Disabled |
Deploy VNet-isolated Cloud Shell into that VNet |
| 3 | “Deny public access” applied account-wide | Whole subscription’s shells break at once | Policy + allowBlobPublicAccess/network rules |
VNet isolation, or scoped exemption |
| 4 | VNet-isolated Cloud Shell misconfigured | Isolated setup chosen but mount still fails | Relay/subnet/delegation checks | Fix relay, subnets, ACI delegation, RBAC |
Cause 1 — The storage firewall is set to “selected networks”
When an account’s Networking is switched from “all networks” to “selected virtual networks and IP addresses”, only listed networks/IPs reach it. Cloud Shell’s service traffic isn’t on that list, so the mount is refused and the shell fails to start — even though the account is healthy and you can browse it from your own machine.
Confirm. Inspect the network rules:
az storage account show --name csmystorage --resource-group cloud-shell-storage-southeastasia \
--query "{default:networkRuleSet.defaultAction, bypass:networkRuleSet.bypass, public:publicNetworkAccess}" -o table
defaultAction = Deny with a bypass that excludes the service path is the smoking gun. In the portal: Storage account → Networking → the radio is on “Selected networks.”
Fix. When you genuinely need network restrictions, the supported answer is VNet-isolated Cloud Shell (Cause 4) — deploy Cloud Shell into the VNet allow-listed on the account. If you only need the default experience back and can accept a public account, set networking to “all networks” or move Cloud Shell to an unrestricted account. Don’t assume “Allow trusted Microsoft services” alone restores it — for a locked-down account the reliable path is isolation. The same firewall mechanics that 403 your blobs apply here; Fixing Azure Storage 403 Errors: Firewalls, Private Endpoints, RBAC & SAS maps every network rule to the error it produces.
Cause 2 — The account is private-endpoint-only
A hardened account may have publicNetworkAccess = Disabled, reachable only through a private endpoint inside a VNet. Default Cloud Shell has no route into that VNet, so the mount can’t complete — correct security for sensitive storage, but the default shell can’t use the account.
Confirm.
az storage account show --name cssecure --resource-group rg-secure \
--query "{public:publicNetworkAccess, pe:privateEndpointConnections[].privateEndpoint.id}" -o json
public: "Disabled" with private-endpoint connections present means only in-VNet callers reach it.
Fix. Deploy VNet-isolated Cloud Shell into the VNet hosting the private endpoint (or peered to it), so the container connects from inside the allowed network — isolation is the mechanism Microsoft provides for exactly this. Azure Private Endpoint vs Service Endpoint: Secure PaaS Access explains why the public path goes dark when you add a private endpoint.
Cause 3 — A subscription-wide “lock down storage” change broke everyone’s shell
The incident that fills the help desk: a security initiative applies “deny public network access on all storage accounts” (as policy or by bulk-editing networking), and every Cloud Shell in the subscription stops at once. It looks like a platform outage; it’s a self-inflicted network block on the backing accounts.
Confirm. Correlate timing — did Cloud Shell break for multiple users simultaneously, right after a governance change? Check whether the policy assignment or bulk networking edit landed then (activity log), and confirm the accounts now show restricted networking (Cause 1’s query across the cloud-shell-storage-* accounts).
Fix. Standardise on VNet-isolated Cloud Shell for the tenant, or carve a scoped exemption for the cloud-shell-storage-* RGs so they stay reachable while the rest of storage is locked down. The governance lesson: treat Cloud Shell’s backing storage as a known, named exception — enumerate those RGs before you flip the switch, not after the tickets arrive.
Cause 4 — VNet-isolated Cloud Shell is set up but still failing
Isolation is the right answer but has its own moving parts, and a misconfiguration fails the mount just as surely. Isolated Cloud Shell deploys the container into your VNet, reaching storage privately, and uses an Azure Relay to broker the terminal — needing specific subnets, a delegation, and RBAC wiring.
Confirm and fix — the checklist. All of these must be correct; any one missing fails it:
| Requirement | What it is | How to confirm | Fix if wrong |
|---|---|---|---|
| Container subnet | Dedicated subnet for the Cloud Shell container | Subnet exists, sized (e.g. /26+), unused by others | Create/resize a dedicated subnet |
| ACI delegation | Container subnet delegated to Microsoft.ContainerInstance/containerGroups |
az network vnet subnet show --query delegations |
Add the delegation to the subnet |
| Relay namespace | The Azure Relay brokering the connection | Relay resource exists and is referenced | Create the Relay; grant access |
| Relay subnet + private endpoint | Private endpoint for the Relay in its own subnet | PE present, DNS resolves | Create the relay PE and private DNS |
| Storage reachable from the VNet | The backing account allow-lists this VNet | Storage networking lists the container subnet | Add the VNet/subnet to storage rules |
| RBAC on relay + storage | Your identity can use the relay and account | Role assignments present | Grant the documented roles |
The common misses, in order: the container subnet isn’t delegated to Azure Container Instances; the storage account doesn’t allow-list the container subnet (so even in-VNet, the firewall says no); and the Relay private endpoint / DNS isn’t resolvable. Isolation failures are always one of these rows. Azure Virtual Network, Subnets and NSGs: Networking Fundamentals is the primer for subnets and delegation, and Azure Private Link and Private DNS: Keeping PaaS Off the Public Internet covers the private-endpoint-plus-DNS pattern the relay uses.
Recovering a deleted, corrupted, or wrong-pointed file share
Sometimes the account is fine and reachable, but the file share or its image is gone or broken — deleted during cleanup, reaped by a policy, or Cloud Shell points at an account that no longer exists. Three recovery paths.
| Situation | What you see | Recovery path |
|---|---|---|
| File share soft-deleted | Mount fails; share missing but within retention | Restore the share from soft delete |
| Whole RG / account deleted | Mount fails; cloud-shell-storage-* gone |
Recreate storage; re-point Cloud Shell |
Image (acc_*.img) corrupted |
Shell starts but ~/clouddrive errors |
Unmount, delete the image, let it recreate |
Restore the file share from soft delete
If the account has file-share soft delete enabled (it often is by default or policy), a deleted Cloud Shell share is recoverable within the retention window (commonly 7 days, up to 365).
Confirm soft delete is on, list the deleted share, then restore it:
# Retention policy, then the soft-deleted shares with their version
az storage account file-service-properties show --account-name csmystorage \
-g cloud-shell-storage-southeastasia --query "shareDeleteRetentionPolicy" -o json
az storage share-rm list --storage-account csmystorage -g cloud-shell-storage-southeastasia \
--include-deleted --query "[?deleted].{name:name, version:version}" -o table
az storage share-rm restore --storage-account csmystorage \
-g cloud-shell-storage-southeastasia --name cs-vinod-1a2b3c --deleted-version <version>
Once restored, the next launch remounts it with your files intact. The recovery surface, by what’s still recoverable:
| Asset | Recoverable if… | Mechanism | Window |
|---|---|---|---|
| File share | Share soft delete enabled | az storage share-rm restore |
1–365 days (default 7) |
| Storage account | Account not yet purged | Recreate; data only if backed up | n/a — recreate fresh |
acc_*.img inside a live share |
Share exists | Delete corrupt image, let Cloud Shell recreate | Immediate (loses $HOME contents) |
| Files inside the image | You backed them up | Restore from your own backup | Your policy |
Re-point Cloud Shell at a different account
If the original account is genuinely gone (RG deleted and purged), reset Cloud Shell’s storage association (settings gear → “Reset user settings”), which clears the stored mount target — recorded by the getStorageInfo association in the portal provider — so the next launch reprovisions. Pick a supported region and a conformant account and it rebuilds the share. You lose whatever was only in the deleted image: the persistent home is exactly as durable as the storage account behind it, the argument for backing up anything precious in ~/clouddrive.
Fix a corrupted clouddrive image
Rarely the shell starts but ~/clouddrive throws I/O errors (an interrupted write left the image inconsistent). clouddrive unmount detaches the drive and a fresh session remounts it cleanly; if the image file itself is corrupt, delete acc_<user>.img from the share (you lose its contents) to force a new 5 GB image on next launch:
clouddrive unmount # then reconnect to remount; or delete acc_<user>.img to fully recreate
Taming session timeouts and dropped sessions
The last symptom class isn’t about storage — it’s the session lifecycle. Cloud Shell is not a persistent VM; it’s a session that ends, and people lose work to that without understanding why.
| Limit | Value (approx) | What triggers it | What survives |
|---|---|---|---|
| Idle timeout | ~20 minutes of inactivity | No input/output for the window | ~/clouddrive (the container ends) |
| Maximum session length | ~24 hours | Wall-clock, regardless of activity | ~/clouddrive |
| Tab closed / network drop | Immediate | Browser/connection lost | ~/clouddrive; running process is killed |
The 20-minute idle timeout
A session with no activity for about 20 minutes is reclaimed and disconnected. “Activity” means input or output — a script running silently for 25 minutes with no console writes can be treated as idle and killed; a walked-away prompt drops. Your files are safe (on the share), but the running process dies and you reconnect to a fresh container.
Confirm. The behaviour is the confirmation: you return to “Your session has expired” or a disconnected terminal after no interaction. There’s no metric — it’s a documented platform limit.
Fix / work around it. A quick keep-alive emits output so the session isn’t seen as idle:
while true; do date; sleep 120; done & # background heartbeat during a long task
But the honest fix is architectural: Cloud Shell is for interactive, short-lived work, not multi-hour unattended jobs. A terraform apply that runs 40 minutes silently belongs in a pipeline or on a VM, not a browser tab that idles out. If you must run it interactively, make it stream progress (-v/no-quiet) so output keeps the session alive.
The maximum session length and dropped connections
Independently of idleness, a session ends after its maximum lifetime (~24 hours), and any tab close, laptop sleep, or network blip drops it immediately. In all cases ~/clouddrive persists, so recovery is just relaunch and resume — the whole reason to save to ~/clouddrive as you go (and git push often), not hold work in a running editor buffer. Files outside ~/clouddrive — in /tmp or an ephemeral $HOME — don’t persist; only the mounted clouddrive survives, so “I saved it in my home directory and it’s gone” usually means an ephemeral session or a path outside the mounted image.
Architecture at a glance
Hold one mental model and every diagnosis falls into place: three stacked layers. Top — your browser session, the terminal tab, subject to the idle and 24-hour limits; it owns no durable state, so closing or idling out just resets it. Middle — the compute container, Microsoft’s ephemeral Linux box, created per session and discarded, almost never the thing that’s broken. Bottom, in your subscription — the persistent storage: a StorageV2 account in a cloud-shell-storage-<region> resource group, holding an Azure Files share, holding the 5 GB acc_*.img image mounted as ~/clouddrive. That bottom layer is where the money, the policy, the firewall, and the failures all live.
Trace a launch as a path through those layers and you see where each failure bites. A mount-provisioning failure bites where the bottom layer is created — region support, account kind, RBAC, and policy all gate the create. A network block bites where the middle layer tries to reach the bottom — a firewall or private-only account refuses the connection, and VNet-isolated Cloud Shell is the bridge that puts the container inside the allowed network. A timeout bites at the top — the session ends and the container is reclaimed, but the bottom layer (your files) is untouched, which is why “it timed out” never means “I lost my clouddrive.” The one question that routes every incident: is the failure in creating the storage, reaching the storage, or just the session ending? Answer that and you know which blade to open first.
Real-world scenario
Northwind Logistics runs a 60-person engineering org on a single heavily-governed Azure subscription. No one has local admin to install the CLI, so Cloud Shell is the tooling. Backing storage sits in cloud-shell-storage-southeastasia on a StorageV2 account the platform team pre-created; monthly cost is a few hundred rupees across all users.
The incident began on a Tuesday at 09:40, right after the security team rolled out a new Azure Policy initiative. Within minutes the help desk lit up: “Cloud Shell won’t open”, “Error: 400 could not create storage”, “stuck on the spinner.” It hit everyone at once. The on-call engineer’s first instinct was a platform outage — but the Azure status page was green and new subscriptions could still launch Cloud Shell. So it wasn’t Microsoft; it was them.
The reflex fix made it worse: someone “reset Cloud Shell user settings” for an affected user, which tried to create a fresh account, hit the new policy, and failed — this time with a clearer banner about a disallowed operation. That was the breakthrough. The engineer ran az monitor activity-log list filtered to failed storageAccounts/write and saw status PolicyViolation, RequestDisallowedByPolicy, naming a new assignment: “Deny storage accounts with public network access.” The initiative had — correctly, from its own point of view — forbidden any public-network storage account, and Cloud Shell’s backing accounts are public-endpoint accounts. Two coupled problems: existing accounts flagged non-compliant (some auto-remediated to “selected networks”, cutting off the service), and any new create denied outright. This was governance, not capacity.
The fix landed in two phases. That morning: a tightly-scoped policy exemption for the cloud-shell-storage-* RGs (category Waiver, “service-managed Cloud Shell storage”) plus reverting the auto-remediated networking on those accounts. Shells recovered within the hour. The following week, rather than leave a standing exemption, they stood up VNet-isolated Cloud Shell: the container in a dedicated subnet (delegated to Azure Container Instances), the storage locked to that VNet and reached privately, an Azure Relay brokering the terminal. The deny policy could then apply to all storage, Cloud Shell included, with no exemption. The lesson on the wall: “Cloud Shell stores its files in your subscription. Any storage hardening you ship applies to it too — enumerate the cloud-shell-storage groups before you flip the switch.”
The incident as a timeline, because the order of moves is the lesson:
| Time | Symptom | Action taken | Effect | What it should have been |
|---|---|---|---|---|
| 09:40 | All shells fail to open | (alerts + help desk) | — | Ask: did a governance change just land? |
| 09:50 | “could not create storage” everywhere | Assume platform outage, check status page | Green — so it’s self-inflicted | Correct instinct to rule out Microsoft |
| 10:05 | Still down | Reset a user’s Cloud Shell settings | Re-create attempt fails with a clearer policy banner | The accidental breakthrough |
| 10:15 | Root cause found | Activity log → PolicyViolation, RequestDisallowedByPolicy |
New “deny public storage” policy identified | — |
| 10:40 | Mitigated | Scoped exemption for cloud-shell-storage-*; revert networking |
Shells recover | Correct morning-of fix |
| +1 week | Fixed | VNet-isolated Cloud Shell; drop the exemption | Policy applies to all storage; shell still works | The durable fix is isolation |
Advantages and disadvantages
The managed-container-plus-your-storage model is what makes Cloud Shell both effortless and occasionally baffling. Weigh it honestly:
| Advantages (why this model helps you) | Disadvantages (why it bites) |
|---|---|
Zero install — a current az/Az/tooling set in any browser, identical for everyone |
The shell that’s meant to be your diagnostic tool is the thing that won’t start when storage fails |
Persistent ~/clouddrive survives sessions, so scripts and tools stick around |
That persistence is a real storage account in your subscription — billable, policy-governed, deletable |
Authenticated as you automatically — no az login, identity flows just work |
Storage hardening (firewall, deny-public policy) silently breaks the shell for everyone |
| Ephemeral mode gives an instant escape hatch when storage is blocked | People default into ephemeral and lose files without realising why |
| VNet isolation lets it work inside locked-down networks | Isolation has many moving parts (subnets, delegation, relay, DNS) that each fail the mount |
| The compute is disposable, so a crashed session never corrupts your environment | Idle/24 h limits kill long unattended jobs that don’t belong here anyway |
| No servers to patch or scale | The cause of a failure is somewhere you can’t see from the terminal — you work through portal blades |
The model is right for interactive, short-lived administration with a consistent, authenticated CLI and no local setup. It bites hardest in governed tenants (policy/firewall blocks), private-network-only estates (needs isolation), and for anyone treating a browser tab as a job host. Every disadvantage is manageable — but only if you know the storage exists and that hardening reaches it, which is the whole point of this article.
Hands-on lab
Stand up Cloud Shell deliberately, see what it provisions, then reproduce a network block and fix it — all cheap (the file share is a few rupees; we delete it at the end). Run the az parts in Cloud Shell or any authenticated shell.
Step 1 — Launch Cloud Shell and let it provision (mounted). Click the Cloud Shell icon, choose Bash, pick a supported region in the storage dialog, and let it create storage. When the prompt appears, confirm what it built (expect a cloud-shell-storage-<region> row):
az group list --query "[?starts_with(name,'cloud-shell-storage')].{name:name, location:location}" -o table
Step 2 — Inspect the backing account. Expect kind = StorageV2, sku = Standard_LRS, public = Enabled — the contract Cloud Shell requires:
RG=$(az group list --query "[?starts_with(name,'cloud-shell-storage')].name | [0]" -o tsv)
ACCT=$(az storage account list -g "$RG" --query "[0].name" -o tsv)
az storage account show -n "$ACCT" -g "$RG" \
--query "{kind:kind, sku:sku.name, region:location, public:publicNetworkAccess}" -o table
Step 3 — See the clouddrive mount from inside the shell. ~/clouddrive is a mounted Azure Files filesystem — the thing every failure is about:
df -h ~/clouddrive # the mounted Azure Files share
ls -la ~/clouddrive # your persistent home contents
Step 4 — Reproduce a network block. Lock the account to “selected networks” to simulate the firewall failure, then close the Cloud Shell tab and relaunch — the mount fails because the service can’t reach the now-firewalled account (the “it worked yesterday” incident):
az storage account update -n "$ACCT" -g "$RG" --default-action Deny
Step 5 — Fix it (restore reachability). Relaunch and the mount succeeds again. (In production the secure fix is VNet-isolated Cloud Shell, not leaving the account open; this just proves the firewall was the cause.)
az storage account update -n "$ACCT" -g "$RG" --default-action Allow
Step 6 — Note the ephemeral escape hatch. In Cloud Shell settings, find the “no storage” / ephemeral option. An ephemeral session has no ~/clouddrive and warns that files won’t persist — the deliberate trade-off for an instant, storage-free shell.
Validation checklist. You saw the real resources Cloud Shell creates, confirmed the StorageV2/supported-region/reachable contract, reproduced the most common “stopped working” failure by firewalling the account, and fixed it. The steps mapped to what each proves:
| Step | What you did | What it proves | Real-world analogue |
|---|---|---|---|
| 1–2 | Inspect cloud-shell-storage-* + account |
The backing storage is real and in your sub | “Where does Cloud Shell keep my files?” |
| 3 | df -h ~/clouddrive |
The mount is an Azure Files share | The thing every failure is about |
| 4 | Firewall the account | A network rule blocks the service | The “it worked yesterday” incident |
| 5 | Restore reachability | Reachability was the cause | The morning-of mitigation |
| 6 | Ephemeral session | No-storage mode loses files by design | The escape hatch people misuse |
Cleanup (avoid lingering charges). If you created storage solely for this lab and don’t use Cloud Shell otherwise, delete the resource group. Do not delete it if your team relies on Cloud Shell in that region — you’d remove everyone’s clouddrive:
# ONLY if this storage is yours alone and disposable:
az group delete -n "$RG" --yes --no-wait
Cost note. A Cloud Shell file share is a few rupees a month (it stores a 5 GB image plus your files). The lab’s only cost is that share for the hour you run it — negligible — and deleting the resource group stops it.
Common mistakes & troubleshooting
This is the playbook — the part you bookmark. First as a scannable table you can read mid-incident, then the same entries with the full confirm-command detail underneath. It spans the basic failures (region, kind, files-disappeared) and the advanced ones (policy deny, VNet isolation, soft-delete recovery).
| # | Symptom | Root cause | Confirm (exact cmd / portal path) | Fix |
|---|---|---|---|---|
| 1 | “could not create storage” on first launch, you’re Owner | Azure Policy denies the storage create | Activity log → status PolicyViolation; az policy state list (NonCompliant, storageAccounts) |
Scoped exemption for cloud-shell-storage-*, or pre-create a compliant account |
| 2 | “could not create storage”, you’re Reader-only | RBAC: no write at the scope | az role assignment list --assignee <you> shows only Reader |
Get Contributor at the sub / a Cloud Shell RG; or use ephemeral to unblock now |
| 3 | Region not offered in the storage dialog | Region doesn’t support Cloud Shell storage | Region dropdown lacks your region | Pick a supported region for storage (compute region is independent) |
| 4 | “Storage account is not supported” pointing at an existing account | Account is GPv1 / BlobStorage, not StorageV2 | az storage account show --query kind returns Storage/BlobStorage |
Use/create a StorageV2 account, or upgrade GPv1 in place |
| 5 | Shell worked yesterday, now mount fails | Storage firewall set to “selected networks” | az storage account show --query networkRuleSet.defaultAction = Deny |
VNet-isolated Cloud Shell, or restore reachability on that account |
| 6 | Mount fails; account is private-endpoint-only | publicNetworkAccess = Disabled |
az storage account show --query publicNetworkAccess = Disabled |
Deploy VNet-isolated Cloud Shell into the VNet |
| 7 | Every user’s shell broke at once after a security change | Subscription-wide “deny public storage” / bulk networking edit | Multiple users + activity-log timing on the policy/edit | VNet isolation for the tenant, or scoped exemption for Cloud Shell RGs |
| 8 | VNet-isolated setup chosen but mount still fails | Subnet not delegated / storage not allow-listed / relay DNS | Check subnet delegation, storage VNet rules, relay PE/DNS | Work the isolation checklist (delegation, storage rule, relay) |
| 9 | “My files disappeared between sessions” | Ephemeral session (no storage) chosen | ~/clouddrive absent; df -h shows no Files mount |
Use the mounted experience; restore from backup if needed |
| 10 | Files saved in $HOME//tmp are gone, clouddrive is fine |
Saved outside ~/clouddrive (transient paths) |
The lost files weren’t under ~/clouddrive |
Always save under ~/clouddrive; git push often |
| 11 | Mount fails; the file share is missing | Share deleted (cleanup/policy), within retention | az storage share-rm list --include-deleted shows it deleted |
Restore from soft delete (share-rm restore) |
| 12 | Shell starts but ~/clouddrive throws I/O errors |
acc_*.img image corrupted |
I/O errors on clouddrive; image present but bad | clouddrive unmount, relaunch; delete the image to recreate |
| 13 | Session dies ~20 min into a silent long task | Idle timeout (no output) | Returned to “session expired” after no interaction | Stream output / heartbeat; run long jobs off Cloud Shell |
| 14 | Session ends after a long day regardless of use | Max session length (~24 h) | Ended on wall-clock, not idleness | Save to clouddrive; relaunch and resume |
| 15 | cloud-shell-storage-* RG vanished; no one’s shell mounts |
Resource group deleted during cleanup | RG absent in az group list |
Recreate storage; reset Cloud Shell to re-point and reprovision |
| 16 | Reset settings, now create fails with a policy banner | Reset forces a fresh create that policy denies | Same as #1, surfaced by the reset | Fix the policy/exemption then reprovision |
The expanded form, with the full reasoning for the entries that bite hardest:
1. “Could not create storage” on first launch even though you’re Owner. The cause is an Azure Policy Deny blocking the create (public-access, naming, SKU, location, or tag rule) — RBAC is fine, the policy engine refuses it. Confirm: the subscription activity log shows a failed storageAccounts/write with status PolicyViolation and RequestDisallowedByPolicy; az policy state list names the assignment. Fix: a policy exemption scoped to the cloud-shell-storage-* RG, a compliant account you pre-create and point Cloud Shell at, or amend the policy to exclude Cloud Shell’s RGs.
2. “Could not create storage” and you only have Reader. First launch must create a resource group and a storage account; Reader can’t. Confirm: az role assignment list --assignee "$(az ad signed-in-user show --query id -o tsv)" shows no write-bearing role at the subscription or a Cloud Shell RG. Fix: obtain Contributor at the subscription or a pre-created cloud-shell-storage-* RG (or Storage Account Contributor on a shared account). To run a command right now, use the ephemeral experience.
8. VNet-isolated Cloud Shell is configured but the mount still fails. A missing piece of the topology — container subnet not delegated to Azure Container Instances, the storage account not allow-listing the container subnet, or the Relay private endpoint / DNS unresolved. Confirm: az network vnet subnet show --query delegations (must include Microsoft.ContainerInstance); storage networkRuleSet.virtualNetworkRules must list the container subnet; relay PE and DNS must resolve. Fix: add the ACI delegation and the container subnet to the storage VNet rules, and fix the relay private endpoint and DNS — work the checklist top to bottom.
9. “My files disappeared between sessions.” You used an ephemeral (no-storage) session whose $HOME is destroyed on disconnect — or you saved outside ~/clouddrive (in /tmp or a non-mounted path), equally transient. Confirm: ~/clouddrive is absent (df -h shows no Azure Files mount), or the lost files simply weren’t under it. Fix: use the mounted experience and save everything under ~/clouddrive; git in clouddrive and push often. Ephemeral data is unrecoverable.
11. The mount fails and the file share is simply missing. The share was deleted (cleanup or a reaping policy) but is within the soft-delete window. Confirm: az storage share-rm list --storage-account <acct> --include-deleted shows it with deleted: true and a version. Fix: restore it (az storage share-rm restore --name <share> --deleted-version <version>); the next launch remounts your files.
15. The cloud-shell-storage-* resource group is gone and no one can mount. Someone deleted the resource group during a cleanup, removing the region’s backing storage. Confirm: az group list shows no cloud-shell-storage-<region> for the region in use. Fix: recreate a StorageV2 account (and RG), then reset Cloud Shell user settings so the next launch reprovisions and re-points. A reset forces a fresh create, so a still-active deny policy (#1) fails it again with RequestDisallowedByPolicy — resolve the policy before reprovisioning. Files in the deleted image are lost unless backed up.
Best practices
- Treat Cloud Shell storage as known infrastructure. Enumerate and document every
cloud-shell-storage-*RG in the tenant, so a storage-hardening rollout never silently breaks the shell. It’s real, billable, policy-governed storage — not magic. - Standardise the backing account. Pre-create one conformant StorageV2 account per region and point users at it (grant Storage Account Contributor), instead of dozens of autogenerated accounts — easier to govern and exempt.
- Choose VNet-isolated Cloud Shell wherever storage is locked down. If policy forbids public storage, isolation is the supported way to keep Cloud Shell working — not an exemption you’ll forget to remove.
- Carve policy exemptions narrowly and document them. Scope any Cloud Shell exemption to the
cloud-shell-storage-*RG only, with a clear description, and revisit it. - Keep everything precious under
~/clouddrive, and in git. Only the mounted clouddrive persists;/tmpand non-clouddrive$HOMEare transient. Push often so a dropped session never loses committed work. - Use ephemeral mode deliberately, never accidentally. It’s the right escape hatch when storage is blocked, but it destroys
$HOMEon exit — don’t drift into it and then “lose files.” - Don’t run multi-hour unattended jobs in Cloud Shell. The 20-minute idle and ~24-hour caps make it the wrong host for a long
terraform apply— use a pipeline, VM, or ACI. - Enable file-share soft delete on the backing account. It turns an accidental share deletion from a disaster into a one-command restore.
- Never delete a
cloud-shell-storage-*RG casually. It backs every Cloud Shell user in that region; deleting it is a tenant-wide shell outage. - Confirm the contract when pointing at an existing account: StorageV2, a supported region, reachable from the service (or via isolation). Most “unsupported storage” errors are a violated contract.
- Diagnose from the storage side, not the terminal. When the shell won’t start, the answers are in the account’s Networking blade, the activity log, and policy state — not a terminal you can’t open.
Security notes
- The backing storage holds your home directory — protect it. Scripts, the
.azuretoken cache, SSH keys, downloaded data all live in a share in your subscription. Restrict data-plane and management access to that account, and prefer VNet-isolated Cloud Shell so the share is reachable only from a private network. - Public-access-disabled storage is good security — pair it with isolation, not exemptions. Rather than exempt Cloud Shell from a “no public storage” policy, deploy VNet isolation so the policy applies universally. An exemption is a standing hole; isolation closes it.
- Lock the share’s network rules to the Cloud Shell VNet when isolated, and use private endpoints so the mount never traverses the public internet — see Azure Private Endpoint vs Service Endpoint: Secure PaaS Access.
- Least privilege for the storage create. Don’t hand users broad subscription Contributor just to launch Cloud Shell; pre-create the account and grant Storage Account Contributor on it, or Contributor on the one Cloud Shell RG.
- Mind the identity Cloud Shell runs as. It authenticates as you — every command runs with your full RBAC. Don’t leave a privileged session open and unattended (the idle timeout is a weak backstop, not a control), and apply Conditional Access to the portal as you would any privileged surface.
- Don’t store long-lived secrets in
~/clouddrive. Use managed identity and Key Vault from scripts instead of pasting credentials into files on the share; see Managed Identities Demystified: System vs User-Assigned and When to Use Each. - Audit the backing accounts. Enable storage logging / Defender for Storage so access to your home-directory share is monitored like any other sensitive store.
The security knobs that also keep Cloud Shell working — secure and functional pull the same way when you isolate rather than exempt:
| Control | Mechanism | Secures against | Cloud Shell impact |
|---|---|---|---|
| VNet-isolated Cloud Shell | Container in your VNet + Relay | Public reachability of the shell’s storage | Required to use private/locked storage |
| Private endpoint on the account | privateEndpoint + private DNS |
Mount traversing the public internet | Works only with isolation |
| Scoped policy exemption | az policy exemption on the RG |
(a hole — minimise) | Restores default shell under a deny policy |
| Storage Account Contributor (not sub Contributor) | RBAC scoped to the account | Over-broad write rights | Users can still provision/point the share |
| File-share soft delete | shareDeleteRetentionPolicy |
Accidental/ malicious deletion | One-command recovery of the share |
| Conditional Access on the portal | Entra ID CA policy | Unauthorised privileged sessions | Governs who can open a shell at all |
Cost & sizing
Cloud Shell itself is free — you don’t pay for the compute container or the session. The only cost is the backing storage, and it’s small:
- The file share stores a 5 GB image plus your files. At Standard Azure Files pricing, a few GB is a few to low tens of rupees a month — negligible.
- Per-account sprawl is the real “cost”. If every user autogenerates an account, you get many tiny accounts to govern and secure. One shared StorageV2 account per region costs the same in rupees but far less in operational overhead.
- VNet isolation adds networking cost: the Azure Relay (small hourly + per-message) and any private endpoints (hourly + per-GB). For a team, low hundreds to low thousands of rupees a month — the price of running Cloud Shell safely inside a locked-down network.
- No sizing to do. Unlike a VM there’s nothing to right-size. The only decisions are how much you store in
~/clouddrive(keep it lean; it’s a working drive, not a data lake) and whether you need isolation.
A rough monthly picture: default Cloud Shell for a whole team is a handful of shares costing single-digit to low-tens of rupees total — effectively free. VNet-isolated Cloud Shell is the relay plus private endpoints, perhaps ₹1,000–3,000/month — the cost of compliance, not of the shell. The drivers and what each buys:
| Cost driver | What you pay for | Rough INR / month | What it’s for | Watch-out |
|---|---|---|---|---|
| Cloud Shell compute/session | Nothing | ₹0 | The shell itself | Truly free |
| Backing file share (per account) | 5 GB image + your files + transactions | a few–low tens | Persistent ~/clouddrive |
Per-account sprawl if autogenerated |
| Consolidated shared account | One StorageV2 account for the team | a few–low tens | Easier governance | Plan RBAC + region |
| Azure Relay (isolation) | Hourly + per-listener/message | low hundreds+ | Brokering the isolated terminal | Only with VNet isolation |
| Private endpoints (isolation) | Hourly + per-GB processed | low hundreds+ each | Private mount path | One per service you privatise |
Interview & exam questions
1. What does Azure Cloud Shell provision in your subscription on first launch? A resource group cloud-shell-storage-<region>, a general-purpose v2 storage account, and an Azure Files share holding a 5 GB image (acc_<user>.img) mounted at ~/clouddrive. The compute container is ephemeral and Microsoft-managed; the storage is real, billable, and yours.
2. A user is Owner but Cloud Shell still fails with “could not create storage.” Most likely cause and how to confirm? An Azure Policy Deny is blocking the create (public-access, naming, SKU, or location) — RBAC is fine, the policy engine refuses it. Confirm in the activity log (failed storageAccounts/write, status PolicyViolation, RequestDisallowedByPolicy) or az policy state list. Fix with a scoped exemption or a compliant pre-created account.
3. Cloud Shell worked yesterday and now the mount fails for everyone. What changed? Almost certainly a storage-networking change — firewall set to “selected networks”, publicNetworkAccess = Disabled, or a subscription-wide “deny public storage” policy — cutting the service off from its backing accounts. Confirm by correlating timing with a governance change and checking networkRuleSet.defaultAction/publicNetworkAccess.
4. How do you make Cloud Shell work when policy forbids public-network storage? Deploy VNet-isolated Cloud Shell: the container runs in your VNet (subnet delegated to Azure Container Instances), reaches storage privately, and uses an Azure Relay for the terminal — so the policy applies universally while the shell reaches storage from inside the allowed network.
5. Mounted vs ephemeral Cloud Shell session? Mounted attaches the file share so ~/clouddrive persists, but requires a usable account. Ephemeral (“no storage required”) gives an instant shell with no storage dependency but destroys $HOME on disconnect. Ephemeral is the escape hatch when storage is blocked; mounted is for anything you keep.
6. A user’s Cloud Shell files “keep disappearing.” Two likely explanations? Either an ephemeral session (no storage, transient $HOME), or saving outside ~/clouddrive (in /tmp or a non-mounted path) — neither persists. Confirm with df -h (is ~/clouddrive mounted?) and where files were saved. Fix: mounted experience, save under ~/clouddrive.
7. The Cloud Shell file share was deleted. Can you recover it? Yes, if file-share soft delete is enabled and you’re within retention: list with az storage share-rm list --include-deleted, restore with az storage share-rm restore --deleted-version <v>, and the next launch remounts your files. If hard-deleted/purged, only your own backups recover the contents.
8. Why does a long script die about 20 minutes into a session? The idle timeout: ~20 minutes with no input/output reclaims the session. A silent command is seen as idle; ~/clouddrive survives but the running process is killed. Stream output to keep it alive, or run long unattended jobs off Cloud Shell.
9. What storage-account requirements must be met for Cloud Shell? General-purpose v2 (StorageV2), a supported region, and reachable by the service (or via VNet isolation). A GPv1/BlobStorage account, an unsupported region, or a firewalled/private-only account each break the mount.
10. Does “resetting” Cloud Shell fix a provisioning failure? Resetting clears the stored mount target (the getStorageInfo association under Microsoft.Portal) and re-runs first-time setup — which re-attempts a create. If the cause is a policy deny or network block, it fails again (often with a clearer banner). Fix the policy/RBAC/network first, then reprovision. There’s nothing to “scale” — the compute is fixed and free.
These map to AZ-104 (Administrator) — manage identities and governance, storage accounts and their networking, and Azure Policy — and AZ-500 (Security Engineer) for the network-isolation and policy-hardening angle; storage-account fundamentals touch AZ-204. A compact cert-mapping for revision:
| Question theme | Primary cert | Exam objective area |
|---|---|---|
| What Cloud Shell provisions; storage requirements | AZ-104 | Configure & manage storage accounts |
| Azure Policy deny on the storage create | AZ-104 / AZ-500 | Implement & manage governance |
| Storage firewall / private endpoint / VNet isolation | AZ-500 / AZ-104 | Secure storage; network security |
| RBAC for the storage create (least privilege) | AZ-104 / AZ-500 | Manage Azure identities & access |
| Soft-delete recovery of the file share | AZ-104 | Manage data protection / backup |
| Session limits, mounted vs ephemeral | AZ-104 | Manage Azure resources (operate tooling) |
Quick check
- On first launch, what three Azure resources does mounted Cloud Shell create in your subscription, and what’s the name pattern of the resource group?
- You’re Owner on the subscription but Cloud Shell still says “could not create storage.” Where do you look first, and what status confirms the cause?
- Your team’s shells all broke at once right after a security rollout. What’s the single most likely cause, and what’s the durable (not exemption-based) fix?
- A colleague’s Cloud Shell files keep vanishing between sessions. Name the two most likely reasons.
- A long
terraform applydies about 20 minutes in with no error. Why, and where should that job really run?
Answers
- A resource group named
cloud-shell-storage-<region>, a general-purpose v2 (StorageV2) storage account inside it, and an Azure Files share holding a 5 GB image mounted at~/clouddrive. The compute container is separate and ephemeral. - The activity log on the subscription/resource group — a failed
Microsoft.Storage/storageAccounts/writewith status PolicyViolation (RequestDisallowedByPolicy) confirms an Azure Policy deny is the cause, not RBAC. Fix with a scoped exemption or a compliant pre-created account. - A storage-hardening change (a “deny public storage” policy or a firewall edit) cut the Cloud Shell backing accounts off from the service. The durable fix is VNet-isolated Cloud Shell so the policy can apply universally while the shell reaches its storage privately — rather than a standing public-access exemption.
- Either they’re using an ephemeral (no-storage) session whose
$HOMEis destroyed on exit, or they’re saving outside~/clouddrive(e.g./tmpor a non-mounted home path), which doesn’t persist. Use the mounted experience and save under~/clouddrive. - The idle timeout (~20 minutes with no input/output) reclaimed the session; a silent
applylooks idle. Long, unattended jobs belong on a pipeline, VM, or Azure Container Instance, not in a Cloud Shell browser tab — or at minimum stream progress so output keeps the session alive.
Glossary
- Azure Cloud Shell — a managed, browser-based shell (Bash or PowerShell), tooling pre-installed, authenticated as the signed-in user; runs in an ephemeral, Microsoft-managed container discarded on disconnect.
~/clouddrive— your persistent home directory inside Cloud Shell, backed by a mounted 5 GB disk image (acc_<user>.img) on an Azure Files share.- Backing storage account — the general-purpose v2 account, in a
cloud-shell-storage-<region>resource group, holding the file share for~/clouddrive. - Azure Files share — the SMB share on that account holding the image Cloud Shell mounts.
- Mounted (persistent) session — the default experience; attaches the file share so files persist across sessions. Requires a usable storage account.
- Ephemeral (no-storage / transient) session — a session with no file share;
$HOMEis destroyed on disconnect. The escape hatch when storage is blocked. cloud-shell-storage-<region>— the resource group Cloud Shell creates for its backing storage; deleting it removes every user’s storage for that region.clouddrive— the in-shell command to mount/unmount the persistent drive (clouddrive mount,clouddrive unmount).- getStorageInfo — the portal/ARM association (under
Microsoft.Portal) recording which account/share a user’s Cloud Shell mounts; cleared by resetting Cloud Shell user settings. - VNet-isolated Cloud Shell — Cloud Shell deployed into your VNet (a subnet delegated to Azure Container Instances) via an Azure Relay, so it reaches network-restricted/private storage.
- Storage firewall (“selected networks”) — a network rule (
defaultAction = Deny) limiting an account to listed networks/IPs; blocks the Cloud Shell service unless isolation is used. publicNetworkAccess = Disabled— disables a storage account’s public endpoint entirely, leaving only private-endpoint access; incompatible with non-isolated Cloud Shell.- Azure Policy (Deny effect) — a governance rule that refuses a resource operation (like the Cloud Shell storage create) regardless of RBAC; a policy exemption is a scoped waiver from it.
- File-share soft delete — a retention setting that lets a deleted Azure Files share be restored within a window (1–365 days, default 7).
- Idle timeout / maximum session length — Cloud Shell reclaims a session after ~20 minutes of inactivity, and ends it after ~24 hours of wall-clock regardless of activity.
- General-purpose v2 (StorageV2) — the required storage-account kind for Cloud Shell; GPv1 (
Storage) and BlobStorage are not supported.
Next steps
You can now tell apart a provisioning failure, a network block, and a session timeout — and fix Cloud Shell for the whole subscription, not just yourself. Build outward:
- Next: Fixing Azure Storage 403 Errors: Firewalls, Private Endpoints, RBAC & SAS — the same firewall/RBAC/private-endpoint traps that block Cloud Shell’s share, mapped to every storage error they produce.
- Related: Azure Storage Account Fundamentals: Blobs, Files, Queues and Tables — the account model and the account kinds that decide whether Cloud Shell can use one.
- Related: Mount an Azure Files SMB Share on Windows and Linux: A Step-by-Step Quickstart — the file-share mount mechanics Cloud Shell automates, done by hand.
- Related: Azure Private Link and Private DNS: Keeping PaaS Off the Public Internet — the private-endpoint-plus-DNS pattern behind VNet-isolated Cloud Shell.
- Related: Managed Identities Demystified: System vs User-Assigned and When to Use Each — use Cloud Shell’s identity (and managed identity in your scripts) instead of storing secrets on the share.