Spin up a storage account in the portal, click through the defaults, and in about ninety seconds you have somewhere to put data that is reachable from the public internet. Do the same for most of the platform — databases, key stores, container registries — and you get the same shape: it works almost instantly, and almost nothing about it is locked down. Azure is insecure by default.
That’s not a scoop, and it’s not a scandal. AWS and GCP are no different. What I want to argue is that it’s deliberate — a design choice that follows directly from what the platform is optimising for — and that once you see the choice clearly, the job of securing your cloud stops being a vague anxiety and becomes a concrete, finite piece of work: close the gap between the default and the appropriate, and know why each control is there.
The five-minute quickstart is the whole problem
Every cloud vendor is optimising the first five minutes. The demo, the free-tier trial, the “deploy to Azure” button, the tutorial that ends with something working — that’s the funnel, and friction anywhere in it costs customers. So the defaults are tuned relentlessly for “it works in five minutes.”
The trouble is that “it works in five minutes” and “it’s safe in five minutes” pull in opposite directions. Safe means private, scoped, logged, least-privileged — and every one of those is friction on the happy path. A private endpoint you have to configure. A network rule you have to write. A role you have to scope down from the one that just worked. Turn all of that on by default and the quickstart stops being quick, the tutorial sprouts a networking chapter, and the button that deployed in ninety seconds now wants a VNet. So the vendor doesn’t. The frictionless default wins, and the frictionless default is the insecure one.
The gap has a shape
The useful move is to stop treating “cloud security” as an ocean and start treating it as a specific, recurring list of defaults that optimise for onboarding and against safety:
- Public network access is usually on. Storage accounts, databases, key vaults — a freshly created resource is typically reachable over a public endpoint, protected by credentials rather than by network isolation. It works from your laptop immediately, which is exactly the problem.
- Access is broader than you scoped it. The path of least resistance for permissions is to grant the role that definitely works — Contributor on the resource group — rather than the three actions the workload actually needs. Over-broad RBAC and over-privileged managed identities are the norm, because narrowing them is work you do after the thing already runs.
- The key store has two permission models and it’s easy to pick the loose one. Key Vault’s older access-policy model and its newer RBAC model coexist, and a lot of infrastructure still reaches for access policies that grant far more than “read this one secret.” Two models means one of them is the one nobody’s rechecked.
- You can’t investigate what you never logged. Diagnostic and audit logging is largely off until you turn it on. Nobody notices on day one — you notice during the incident, when you go looking for the trail and find the switch was never flipped. The cost of the missing default lands precisely when you can least afford it.
None of these is a vulnerability in Azure. Each is a default that assumed you’d harden it later, and “later” is the word doing all the damage.
It’s not a bug, it’s an optimisation
This is where “shared responsibility” stops being a compliance slide and starts being the actual architecture of the relationship. The platform secures the things underneath the line — the physical estate, the hypervisor, the managed service’s own patching. Everything above the line — who can reach it, who can do what, what gets recorded — is yours. The default is the vendor handing you a working system with all the above-the-line controls set to their most permissive, because permissive is what makes it work in five minutes.
So the insecurity isn’t negligence; it’s the same optimise-don’t-maximise logic from how much security is too much, except the vendor has optimised the default for their funnel, not your threat model. Their incentive is adoption; the secure delta is the bit only you can price, because only you know what the data’s worth and who’s plausibly coming for it. Reading the default as “what Microsoft thinks is safe” is the mistake. It was never a safety recommendation. It was an onboarding decision.
What secure-by-default would actually look like
The good news in “you own the delta” is that the delta is knowable. A hardened baseline for most workloads is a short, repeatable list — and it’s the anonymised shape of what every serious platform I’ve worked on converges on:
- Turn public access off and reach services privately — private endpoints and network rules, so the resource simply isn’t on the public internet to begin with. Network isolation ahead of credential-only protection.
- Go keyless. Managed identities instead of connection strings and secrets in config. The secret you never issued is the one that can’t leak.
- Scope roles to the actions, not the resource group. Least privilege as the starting point you relax from, not the aspiration you never get back to.
- Turn logging on before you need it, centralised somewhere you’ll actually look, from day one rather than day-of-incident.
Do this and you’ve inverted the vendor’s default: the secure path becomes the paved path, which is the same lesson as shifting the feedback, not the blame, left — people take the safe route when it’s the easy one. Bake the hardened baseline into the template, the module, the landing zone, and “secure by default” becomes true again — because you made it the default, since the platform wouldn’t.
Because that’s the honest reframe. The cloud didn’t hand you an insecure system out of carelessness. It handed you one optimised for a different goal than yours, with a clearly marked line showing which half is your move. Insecure by default, by design — and secure by your design, or not at all.