About this landing zone
I run Azure and M365 environments, but I usually inherit them. So I wanted to build a small version of it myself to understand things better.
What it is
An Azure landing zone under my personal subscription (with Platform, Landing Zones, Sandbox and Decommissioned management layers under the primary), policies assigned at the top so everything below inherits them, a central Log Analytics workspace collecting subscription activity log, and a monthly budget with alerts (just in case wild bots decide to try putting me in financial ruin by running up costs.) The Okta identity lab's resources sits within this landing zone group, so it's the first workload run against policies.
This is a simple implementation written in Bicep, not an enterprise-grade solution using the Landing Zone Accelerator.
Audit first, then deny
The policies in place went in as Audit-only initially to understand the impact before enforcing them. The first scan found 17 problems across 12 resources (every one was a missing tag.)
I tagged the 12 resources, added owner to the lab's Bicep so new resources arrive compliant, rescanned to zero, then switched the policies to Deny.
Things that broke
The deployment tried to fill in the policy's own blanks. Policy rules contain expressions like [parameters('effect')] that are meant for Azure Policy to fill in later. My template stored them in variables, and then built a list of them in a loop. Both times, the deployment engine evaluated them itself and failed with The template parameter 'effect' is not found. What-if didn't catch the second one. The fix was to stop being clever: every rule written out in full, directly in the resource.
I created the management groups and then couldn't use them. Creating management groups needs rights at the top of the tenant, so I elevated, deployed, and removed the elevation. Then the next deployment failed with AuthorizationFailed on the group I'd just made. Azure only makes you Owner of a management group you create if you don't already inherit Owner from above, and while elevated, I did. The fix was to grant Owner on the Glasscliff group explicitly before dropping the elevation.
Tagging a certificate isn't the same as tagging anything else. az resource tag reads the whole resource, adds the tags and writes the whole thing back. That works for most resources, but the web app's certificate failed with an error about its keyVaultId. az tag update only touches tags and never looks at the rest of the resource, and it worked first time.
What I'd change
- Separate subscriptions. In an enterprise environment, a landing zone puts logging and other shared services in their own subscriptions. This one has a single subscription, using a resource group as the management unit instead.
- The web app's resource group isn't managed by any of this code. Its tags are correct now, but nothing keeps them that way, and Deny will block any update that drops them.
- Privileged access. JIT elevation through Privileged Identity Management needs an Entra ID P2 license, which this tenant doesn't have... yet.
- Networking. A hub network with a firewall is the expensive part of a landing zone. Why incur costs for no particular reason?