Start with the trust boundaries
Before choosing any service, draw the lines across which trust does not automatically flow. In a typical web estate there are four: between the internet and your edge, between your edge and your application, between your application and your data, and between your delivery environment and production.
The value of doing this first is that it converts security from a list of products into a list of questions. At each boundary, what identity is presented, what is checked, what is logged, and what happens when the check fails? A design that can answer those four questions at four boundaries is already better than most.
Identity is the primary control
In a cloud estate the network is no longer the primary boundary; identity is. Almost every serious incident we have reviewed involved a credential that was valid, held by something that should not have had it, and used from somewhere nobody was watching.
Prefer managed identity to any secret
Where one Azure resource needs to reach another, a managed identity removes the credential entirely. There is nothing to rotate, nothing to store and nothing to leak. This should be the default, and any deviation from it should be written down with a reason.
Scope role assignments narrowly
Assign roles at the resource, not the subscription, unless the workload genuinely operates across the subscription. The convenience of a broad assignment is real; so is the blast radius. Where a built-in role grants more than is needed, define a custom role — it is more work once and considerably less work at audit.
Note
Human access and workload access are different problems. Humans need conditional access, multi-factor authentication and time-bound elevation. Workloads need no interactive credential at all. Designs that treat them identically tend to weaken both.
Network controls still matter
Identity being primary does not make the network irrelevant. It makes it a second layer that limits what a valid-but-stolen credential can reach.
- Private endpoints for data services, so that storage and databases are not reachable from the public internet even with a correct key.
- A single ingress point. One edge service, with a web application firewall, and origins that only accept traffic from it. An origin that is also directly reachable is not protected by the firewall in front of it.
- Egress control. Restricting what your application can call outward is what turns a compromise into a contained compromise.
Secrets belong in a vault
For the residual secrets that cannot be replaced with a managed identity — third-party API keys, mostly — use a key vault, reference the secret rather than copying it, and set an expiry. A secret with no expiry is a secret nobody will ever rotate.
Application setting referencing a vault secret
THIRD_PARTY_API_KEY=@Microsoft.KeyVault(
SecretUri=https://example-vault.vault.azure.net/secrets/third-party-api-key/
)
Watch out
A static website has no server, so it has no secrets. Anything the browser can read is public. If a design requires a static site to hold an API key, the design is wrong: put a small server-side endpoint in front of the third-party service and keep the key there.
Logging and evidence
Security controls that produce no evidence are indistinguishable from security controls that are switched off. Decide during design what you would need in order to answer, six months later, the question "who accessed this and when".
- Send platform and resource logs to a workspace that the workload's own identity cannot modify.
- Set retention against your actual obligation, not the default.
- Alert on control-plane changes — role assignments, firewall rules, vault access policies — not only on application errors.
- Test the query you would run during an incident, before the incident.
Separate the delivery boundary
The pipeline that deploys to production is a production-level trust boundary and is frequently the weakest one. It usually holds an identity with broad rights, it is often configured by whoever set it up first, and it is rarely reviewed. Use federated credentials rather than long-lived secrets, restrict deployment to protected branches, and require a review on any change to the workflow file itself.
Reviewing the design
We use a short checklist at design review. It is not exhaustive; it is the set of questions that have most often exposed a real weakness.
| Question | A weak answer |
|---|---|
| What identity does this component use? | "The application's connection string." |
| What can that identity reach? | "Everything in the resource group." |
| Where is the secret stored? | "In the pipeline variables." |
| What is logged when access is denied? | "The application returns a 403." |
| Who can change the deployment workflow? | "Anyone with write access." |
| How would we revoke access today? | "We would raise a ticket." |
None of this is exotic. It is the ordinary discipline of writing down where trust stops, and then being unwilling to make an exception because a deadline is close.