Nuking All Azure Resource Groups Under All Azure subscriptions
The code
You can copy the script below as a one-liner:
The Terraform code is also here:
Overview
In Microsoft Azure, Resource Groups are logical containers that are directly linked to their resources. If you want to delete your resources, just right click on the resource group poof! The resources are gone.
This is a breath of fresh air compared to the asset inventory, visibility, and cleanup nightmare in AWS. But it comes with its own security challenges.
Background
To understand how this exploit/mischief works, you’ll need to understand:
- Azure Resource Management Hierarchy: How Resource Groups and Subscriptions are tied to resources
- Azure Role Assignments: How privileged identities can have access across Azure subscriptions
Resource Management Hierarchy
Azure resource management hierarchy works like this:
- Azure Tenant (not shown): This is similar to an AWS Organization. It is at a higher level than Management groups.
- Management Groups: similar to AWS OUs. Hierarchy of grouping accounts).
- Subscriptions: A subscription is a similar construct to an AWS Account. It can have multiple resource groups inside it.
- Resource Groups: As mentioned before, these are containers that are directly linked to their resources. If you delete a resource group, you delete its resources too.
Azure Role Assignments
In AWS, we have the concept of “Cross Account Trust.” Essentially, you modify RoleA
’s Trust Policy in AccountA
so that it allows RoleB
from AccountB
to “Assume” that role via sts:AssumeRole
. When you make the sts:AssumeRole
call, it returns a set of temporary credentials that you can then use against the target account.
Unfortunately, this becomes a complicated web/mesh/mess of trust.
Identities exist in one AWS account but do not exist in another. But at least sts:AssumeRole
generates credentials that are scoped to a single AWS Account!
In Azure, all identities exist at the Active Directory level. Their permissions per subscription are based on role assignments. This is much cleaner, in my opinion. Rather than a a mesh/web/mess, it is a one-direction series of role assignments.
Azure Role Assignments can be scoped at these levels:
- Tenant level: This has the same effect across all management groups, all subscriptions, and all resource groups.
- Management group level: This has the same effect across all subscriptions, and all resource groups that are in this management group.
- Subscription level: This has the same effect across all resource groups that are within that subscription
- Resource group level: Only applies to that resource group.
Where can I nuke things
So, how does this information affect where you can apply this nuke-azure script?
Well, the most likely point of entry is CI/CD pipelines - specifically those that provision infrastructure.
Here’s a great example. You have a CI/CD pipeline to Azure that leverages Terraform. You have different pipeline jobs for different Azure environments. You originally intend for each of those jobs to be scoped to a specific subscription. But all of those jobs leverage ✨God-Mode Tenant-level credentials✨. In this case, it would be possible for a developer who has the ability to run Terraform on their own Azure subscription to run Terraform against other Azure subscriptions. That could cause this scenario:
Nuking Azure with Terraform’s null_resource and local-exec provisioner
Here’s the Terraform code:
The bash code does this:
- Gets a list of all Azure subscriptions
- For each subscription, list the resource groups
- For each resource group, delete the resource group
- Profit
You can test the above code by doing the following:
- Create an Azure Test tenant. Don’t do this in production.
- Create a subscription within that tenant
- Create a few resource groups in that subscription
- Then log in to Azure on command line using
az login
- Insert the Terraform mentioned above into a file called
main.tf
. Then, from within that directory, run these commands to apply the Terraform:
terraform init
terraform plan
terraform apply --auto-approve
Example output is below.
Conclusion
Infrastructure Provisioning and scheduling pipelines are some of the highest impact attack vectors in any organization. It is crucial to lock these down in a reasonable way that doesn’t stifle innovation but still prevents mass destruction. My recommendation in this case would be to limit the scope of the Infrastructure Provisioning Service Principals so that they are on a per-subscription level.