Azure RBAC Policy Reference
This document outlines the Azure RBAC permissions required for NightOps to manage Microsoft Azure resources. The policy follows the principle of least privilege.
Quick Start
For a quick setup, use the custom RBAC role below. For more granular control, see the Per-Service Permissions section.
Complete NightOps Custom Role
{
"Name": "NightOps Resource Manager",
"Description": "Allows NightOps to manage compute resources for cost optimization",
"Actions": [
"Microsoft.Compute/virtualMachines/read",
"Microsoft.Compute/virtualMachines/start/action",
"Microsoft.Compute/virtualMachines/deallocate/action",
"Microsoft.Compute/virtualMachines/instanceView/read",
"Microsoft.Compute/virtualMachineScaleSets/read",
"Microsoft.Compute/virtualMachineScaleSets/write",
"Microsoft.Sql/servers/read",
"Microsoft.Sql/servers/databases/read",
"Microsoft.Sql/servers/databases/pause/action",
"Microsoft.Sql/servers/databases/resume/action",
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/agentPools/read",
"Microsoft.ContainerService/managedClusters/agentPools/write"
],
"NotActions": [],
"DataActions": [],
"NotDataActions": [],
"AssignableScopes": [
"/subscriptions/YOUR_SUBSCRIPTION_ID"
]
}
Create the Custom Role
az role definition create --role-definition nightops-role.json
Create Service Principal and Assign Role
# Create service principal
az ad sp create-for-rbac \
--name "NightOps" \
--role "NightOps Resource Manager" \
--scopes /subscriptions/YOUR_SUBSCRIPTION_ID
Per-Service Permissions
Virtual Machines
| Permission | Purpose |
|---|---|
Microsoft.Compute/virtualMachines/read | List and get VM details |
Microsoft.Compute/virtualMachines/instanceView/read | Get VM power state |
Microsoft.Compute/virtualMachines/start/action | Start deallocated VMs |
Microsoft.Compute/virtualMachines/deallocate/action | Deallocate running VMs |
Built-in Role Alternative: Virtual Machine Contributor
The built-in role includes delete permissions. Use the custom role for least privilege.
Azure SQL Database
| Permission | Purpose |
|---|---|
Microsoft.Sql/servers/read | List SQL servers |
Microsoft.Sql/servers/databases/read | List and get database details |
Microsoft.Sql/servers/databases/pause/action | Pause serverless databases |
Microsoft.Sql/servers/databases/resume/action | Resume paused databases |
Built-in Role Alternative: SQL DB Contributor
Pause/resume is only available for serverless tier databases.
AKS Node Pools
| Permission | Purpose |
|---|---|
Microsoft.ContainerService/managedClusters/read | List and get cluster details |
Microsoft.ContainerService/managedClusters/agentPools/read | List and get node pool details |
Microsoft.ContainerService/managedClusters/agentPools/write | Update node pool size |
Built-in Role Alternative: Azure Kubernetes Service Contributor
VM Scale Sets
| Permission | Purpose |
|---|---|
Microsoft.Compute/virtualMachineScaleSets/read | List and get VMSS details |
Microsoft.Compute/virtualMachineScaleSets/write | Update VMSS capacity |
Built-in Role Alternative: Virtual Machine Contributor
Multi-Subscription Setup
For managing resources across multiple Azure subscriptions, assign the custom role at each subscription level.
Architecture
┌─────────────────┐ ┌─────────────────┐
│ Hub Subscription│ │ Spoke Subscription│
│ (NightOps) │────────▶│ (Customer) │
│ │ RBAC │ │
└─────────────────┘ └─────────────────┘
Setup Steps
- Create the custom role in each subscription (or at management group level)
- Create a single service principal in Azure AD
- Assign the role to the service principal in each subscription
# Assign role in spoke subscription
az role assignment create \
--assignee "SERVICE_PRINCIPAL_APP_ID" \
--role "NightOps Resource Manager" \
--scope "/subscriptions/SPOKE_SUBSCRIPTION_ID"
Management Group Level
For easier management across many subscriptions, create the role at the management group level:
{
"AssignableScopes": [
"/providers/Microsoft.Management/managementGroups/YOUR_MANAGEMENT_GROUP"
]
}
Tag-Based Access Control
Azure supports Conditions for fine-grained access control based on resource tags.
Example: Restrict to Tagged Resources
az role assignment create \
--assignee "SERVICE_PRINCIPAL_APP_ID" \
--role "NightOps Resource Manager" \
--scope "/subscriptions/YOUR_SUBSCRIPTION_ID" \
--condition "((!(ActionMatches{'Microsoft.Compute/virtualMachines/start/action'})) OR (@Resource[Microsoft.Compute/virtualMachines/tags.nightops-managed] StringEquals 'true'))" \
--condition-version "2.0"
ABAC (Attribute-Based Access Control) conditions are in preview for some resource types.
Permissions Summary Table
| Service | Read Permissions | Write Permissions |
|---|---|---|
| VMs | virtualMachines/read, instanceView/read | start/action, deallocate/action |
| SQL | servers/read, databases/read | databases/pause/action, databases/resume/action |
| AKS | managedClusters/read, agentPools/read | agentPools/write |
| VMSS | virtualMachineScaleSets/read | virtualMachineScaleSets/write |
Terraform Module
# Create custom role
resource "azurerm_role_definition" "nightops" {
name = "NightOps Resource Manager"
scope = data.azurerm_subscription.current.id
description = "Allows NightOps to manage compute resources"
permissions {
actions = [
"Microsoft.Compute/virtualMachines/read",
"Microsoft.Compute/virtualMachines/start/action",
"Microsoft.Compute/virtualMachines/deallocate/action",
"Microsoft.Compute/virtualMachines/instanceView/read",
"Microsoft.Compute/virtualMachineScaleSets/read",
"Microsoft.Compute/virtualMachineScaleSets/write",
"Microsoft.Sql/servers/read",
"Microsoft.Sql/servers/databases/read",
"Microsoft.Sql/servers/databases/pause/action",
"Microsoft.Sql/servers/databases/resume/action",
"Microsoft.ContainerService/managedClusters/read",
"Microsoft.ContainerService/managedClusters/agentPools/read",
"Microsoft.ContainerService/managedClusters/agentPools/write",
]
not_actions = []
}
assignable_scopes = [
data.azurerm_subscription.current.id
]
}
# Create service principal
resource "azuread_application" "nightops" {
display_name = "NightOps"
}
resource "azuread_service_principal" "nightops" {
application_id = azuread_application.nightops.application_id
}
resource "azuread_service_principal_password" "nightops" {
service_principal_id = azuread_service_principal.nightops.id
}
# Assign custom role
resource "azurerm_role_assignment" "nightops" {
scope = data.azurerm_subscription.current.id
role_definition_id = azurerm_role_definition.nightops.role_definition_resource_id
principal_id = azuread_service_principal.nightops.object_id
}
Bicep Template
targetScope = 'subscription'
@description('The principal ID to assign the role to')
param principalId string
resource nightopsRole 'Microsoft.Authorization/roleDefinitions@2022-04-01' = {
name: guid(subscription().id, 'NightOps Resource Manager')
properties: {
roleName: 'NightOps Resource Manager'
description: 'Allows NightOps to manage compute resources for cost optimization'
type: 'CustomRole'
permissions: [
{
actions: [
'Microsoft.Compute/virtualMachines/read'
'Microsoft.Compute/virtualMachines/start/action'
'Microsoft.Compute/virtualMachines/deallocate/action'
'Microsoft.Compute/virtualMachines/instanceView/read'
'Microsoft.Compute/virtualMachineScaleSets/read'
'Microsoft.Compute/virtualMachineScaleSets/write'
'Microsoft.Sql/servers/read'
'Microsoft.Sql/servers/databases/read'
'Microsoft.Sql/servers/databases/pause/action'
'Microsoft.Sql/servers/databases/resume/action'
'Microsoft.ContainerService/managedClusters/read'
'Microsoft.ContainerService/managedClusters/agentPools/read'
'Microsoft.ContainerService/managedClusters/agentPools/write'
]
notActions: []
}
]
assignableScopes: [
subscription().id
]
}
}
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(subscription().id, principalId, nightopsRole.id)
properties: {
roleDefinitionId: nightopsRole.id
principalId: principalId
principalType: 'ServicePrincipal'
}
}
Security Best Practices
Use Azure tags (nightops-managed=true) to identify resources that NightOps should manage.
Enable Azure Activity Log and configure alerts for NightOps actions for compliance and debugging.
For Azure-hosted deployments, use Managed Identity instead of service principal secrets.
If using service principal secrets, rotate them regularly and store in Azure Key Vault.
Next Steps
- Azure Supported Services - Learn about supported services