Thursday, 12 September 2019

Sample - Billing tags policy initiative

This policy set requires specified tag values for cost center and product name. Uses built-in policies to apply and enforce required tags. You specify the required values for the tags.
If you don't have an Azure subscription, create a free account before you begin.

Sample template

JSON
{
    "properties": {
        "displayName": "Billing Tags Policy Initiative",
        "description": "Specify cost Center tag and product name tag",
        "parameters": {
            "costCenterValue": {
                "type": "String",
                "metadata": {
                    "displayName": "required value for Cost Center tag"
                }
            },
            "productNameValue": {
                "type": "String",
                "metadata": {
                    "displayName": "required value for product Name tag"
                }
            }
        },
        "policyDefinitions": [
            {
                "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/1e30110a-5ceb-460c-a204-c1c3969c6d62",
                "parameters": {
                    "tagName": {
                        "value": "costCenter"
                    },
                    "tagValue": {
                        "value": "[parameters('costCenterValue')]"
                    }
                }
            },
            {
                "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/2a0e14a6-b0a6-4fab-991a-187a4f81c498",
                "parameters": {
                    "tagName": {
                        "value": "costCenter"
                    },
                    "tagValue": {
                        "value": "[parameters('costCenterValue')]"
                    }
                }
            },
            {
                "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/1e30110a-5ceb-460c-a204-c1c3969c6d62",
                "parameters": {
                    "tagName": {
                        "value": "productName"
                    },
                    "tagValue": {
                        "value": "[parameters('productNameValue')]"
                    }
                }
            },
            {
                "policyDefinitionId": "/providers/Microsoft.Authorization/policyDefinitions/2a0e14a6-b0a6-4fab-991a-187a4f81c498",
                "parameters": {
                    "tagName": {
                        "value": "productName"
                    },
                    "tagValue": {
                        "value": "[parameters('productNameValue')]"
                    }
                }
            }
        ]
    },
    "id": "/subscriptions/a48a924d-6007-4c39-a3c0-5466b9012f42/providers/Microsoft.Authorization/policySetDefinitions/billingTagsPolicy",
    "type": "Microsoft.Authorization/policySetDefinitions",
    "name": "billingTagsPolicy"
}
You can deploy this template with PowerShell.

Deploy with PowerShell

This sample requires Azure PowerShell. Run Get-Module -ListAvailable Az to find the version. If you need to install or upgrade, see Install Azure PowerShell module.
Run the Connect-AzAccount cmdlet to connect to Azure.
Azure PowerShell
$policydefinitions = "https://raw.githubusercontent.com/Azure/azure-policy/master/samples/PolicyInitiatives/multiple-billing-tags/azurepolicyset.definitions.json"
$policysetparameters = "https://raw.githubusercontent.com/Azure/azure-policy/master/samples/PolicyInitiatives/multiple-billing-tags/azurepolicyset.parameters.json"

$policyset= New-AzPolicySetDefinition -Name "multiple-billing-tags" -DisplayName "Billing Tags Policy Initiative" -Description "Specify cost Center tag and product name tag" -PolicyDefinition $policydefinitions -Parameter $policysetparameters

New-AzPolicyAssignment -PolicySetDefinition $policyset -Name <assignmentname> -Scope <scope>  -costCenterValue <required value for Cost Center tag> -productNameValue <required value for product Name tag>

Clean up PowerShell deployment

Run the following command to remove the resource group, VM, and all related resources.
Azure PowerShell
Remove-AzResourceGroup -Name myResourceGroup

Apply tags to existing resources

After assigning the policies, you can trigger an update to all existing resources to enforce the tag policies you have added. The following script retains any other tags that existed on the resources:
Azure PowerShell
$resources = Get-AzResource -ResourceGroupName 'ExampleGroup'

foreach ($r in $resources) {
    try {
        Set-AzResource -Tags ($a = if ($r.Tags -eq $NULL) { @{} } else {$r.Tags}) -ResourceId $r.ResourceId -Force -UsePatchSemantics
    }
    catch {
        Write-Host $r.ResourceId + "can't be updated"
    }
}

Sample - Enforce tag and its value

This policy requires a specified tag name and value. You specify the tag name and value to enforce.
If you don't have an Azure subscription, create a free account before you begin.

Sample template

JSON
{
   "properties": {
      "displayName": "Require tag and its value",
      "policyType": "BuiltIn",
      "mode": "Indexed",
      "description": "Enforces a required tag and its value. Does not apply to resource groups.",
      "parameters": {
         "tagName": {
            "type": "String",
            "metadata": {
               "description": "Name of the tag, such as costCenter"
            }
         },
         "tagValue": {
            "type": "String",
            "metadata": {
               "description": "Value of the tag, such as headquarter"
            }
         }
      },
      "policyRule": {
         "if": {
            "not": {
               "field": "[concat('tags[', parameters('tagName'), ']')]",
               "equals": "[parameters('tagValue')]"
            }
         },
         "then": {
            "effect": "deny"
         }
      }
   },
   "id": "/providers/Microsoft.Authorization/policyDefinitions/1e30110a-5ceb-460c-a204-c1c3969c6d62",
   "type": "Microsoft.Authorization/policyDefinitions",
   "name": "1e30110a-5ceb-460c-a204-c1c3969c6d62"
}
You can deploy this template using the Azure portal, with PowerShell or with the Azure CLI.

Deploy with the portal

Deploy the Policy sample to Azure

Deploy with PowerShell

This sample requires Azure PowerShell. Run Get-Module -ListAvailable Az to find the version. If you need to install or upgrade, see Install Azure PowerShell module.
Run the Connect-AzAccount cmdlet to connect to Azure.
Azure PowerShell
$definition = New-AzPolicyDefinition -Name "enforce-tag-value" -DisplayName "Enforce tag and its value" -description "Enforces a required tag and its value." -Policy 'https://raw.githubusercontent.com/Azure/azure-policy/master/samples/built-in-policy/enforce-tag-value/azurepolicy.rules.json' -Parameter 'https://raw.githubusercontent.com/Azure/azure-policy/master/samples/built-in-policy/enforce-tag-value/azurepolicy.parameters.json' -Mode All
$definition
$assignment = New-AzPolicyAssignment -Name <assignmentname> -Scope <scope>  -tagName <tagName> -tagValue <tagValue> -PolicyDefinition $definition
$assignment

Clean up PowerShell deployment

Run the following command to remove the resource group, VM, and all related resources.
Azure PowerShell
Remove-AzResourceGroup -Name myResourceGroup

Deploy with Azure CLI

To run this sample, install the latest version of the Azure CLI. To start, run az login to create a connection with Azure.
Samples for the Azure CLI are written for the bash shell. To run this sample in Windows PowerShell or Command Prompt, you may need to change elements of the script.
Azure CLI
az policy definition create --name 'enforce-tag-value' --display-name 'Enforce tag and its value' --description 'Enforces a required tag and its value.' --rules 'https://raw.githubusercontent.com/Azure/azure-policy/master/samples/built-in-policy/enforce-tag-value/azurepolicy.rules.json' --params 'https://raw.githubusercontent.com/Azure/azure-policy/master/samples/built-in-policy/enforce-tag-value/azurepolicy.parameters.json' --mode All

az policy assignment create --name <assignmentname> --scope <scope> --policy "enforce-tag-value"

Clean up Azure CLI deployment

Run the following command to remove the resource group, VM, and all related resources.
Azure CLI
az group delete --name myResourceGroup --yes

Use tags to organize your Azure resources

You apply tags to your Azure resources giving metadata to logically organize them into a taxonomy. Each tag consists of a name and a value pair. For example, you can apply the name "Environment" and the value "Production" to all the resources in production.
After you apply tags, you can retrieve all the resources in your subscription with that tag name and value. Tags enable you to retrieve related resources from different resource groups. This approach is helpful when you need to organize resources for billing or management.
Your taxonomy should consider a self-service metadata tagging strategy in addition to an auto-tagging strategy to reduce the burden on users and increase accuracy.
The following limitations apply to tags:
  • Not all resource types support tags. To determine if you can apply a tag to a resource type, see Tag support for Azure resources.
  • Each resource or resource group can have a maximum of 50 tag name/value pairs. Currently, storage accounts only support 15 tags, but that limit will be raised to 50 in a future release. If you need to apply more tags than the maximum allowed number, use a JSON string for the tag value. The JSON string can contain many values that are applied to a single tag name. A resource group can contain many resources that each have 50 tag name/value pairs.
  • The tag name is limited to 512 characters, and the tag value is limited to 256 characters. For storage accounts, the tag name is limited to 128 characters, and the tag value is limited to 256 characters.
  • Generalized VMs don't support tags.
  • Tags applied to the resource group are not inherited by the resources in that resource group.
  • Tags can't be applied to classic resources such as Cloud Services.
  • Tag names can't contain these characters: <>%&\?/
To apply tags to resources, the user must have write access to that resource type. To apply tags to all resource types, use the Contributor role. To apply tags to only one resource type, use the contributor role for that resource. For example, to apply tags to virtual machines, use the Virtual Machine Contributor.
 Note
This article provides steps for how to delete personal data from the device or service and can be used to support your obligations under the GDPR. If you’re looking for general info about GDPR, see the GDPR section of the Service Trust portal.

Policies

You can use Azure Policy to enforce tagging rules and conventions. By creating a policy, you avoid the scenario of resources being deployed to your subscription that don't comply with the expected tags for your organization. Instead of manually applying tags or searching for resources that aren't compliant, you can create a policy that automatically applies the needed tags during deployment. The following section shows example policies for tags.

Tags

Apply tag and its default valueAppends a specified tag name and value, if that tag is not provided. You specify the tag name and value to apply.
Billing Tags Policy InitiativeRequires specified tag values for cost center and product name. Uses built-in policies to apply and enforce required tags. You specify the required values for the tags.
Enforce tag and its valueRequires a specified tag name and value. You specify the tag name and value to enforce.
Enforce tag and its value on resource groupsRequires a tag and value on a resource group. You specify the required tag name and value.

PowerShell

 Note
This article has been updated to use the new Azure PowerShell Az module. You can still use the AzureRM module, which will continue to receive bug fixes until at least December 2020. To learn more about the new Az module and AzureRM compatibility, see Introducing the new Azure PowerShell Az module. For Az module installation instructions, see Install Azure PowerShell.
To see the existing tags for a resource group, use:
Azure PowerShell
(Get-AzResourceGroup -Name examplegroup).Tags
That script returns the following format:
PowerShell
Name                           Value
----                           -----
Dept                           IT
Environment                    Test
To see the existing tags for a resource that has a specified resource ID, use:
Azure PowerShell
(Get-AzResource -ResourceId /subscriptions/<subscription-id>/resourceGroups/<rg-name>/providers/Microsoft.Storage/storageAccounts/<storage-name>).Tags
Or, to see the existing tags for a resource that has a specified name and resource group, use:
Azure PowerShell
(Get-AzResource -ResourceName examplevnet -ResourceGroupName examplegroup).Tags
To get resource groups that have a specific tag, use:
Azure PowerShell
(Get-AzResourceGroup -Tag @{ Dept="Finance" }).ResourceGroupName
To get resources that have a specific tag, use:
Azure PowerShell
(Get-AzResource -Tag @{ Dept="Finance"}).Name
To get resources that have a specific tag name, use:
Azure PowerShell
(Get-AzResource -TagName Dept).Name
Every time you apply tags to a resource or a resource group, you overwrite the existing tags on that resource or resource group. Therefore, you must use a different approach based on whether the resource or resource group has existing tags.
To add tags to a resource group without existing tags, use:
Azure PowerShell
Set-AzResourceGroup -Name examplegroup -Tag @{ Dept="IT"; Environment="Test" }
To add tags to a resource group that has existing tags, retrieve the existing tags, add the new tag, and reapply the tags:
Azure PowerShell
$tags = (Get-AzResourceGroup -Name examplegroup).Tags
$tags.Add("Status", "Approved")
Set-AzResourceGroup -Tag $tags -Name examplegroup
To add tags to a resource without existing tags, use:
Azure PowerShell
$r = Get-AzResource -ResourceName examplevnet -ResourceGroupName examplegroup
Set-AzResource -Tag @{ Dept="IT"; Environment="Test" } -ResourceId $r.ResourceId -Force
To add tags to a resource that has existing tags, use:
Azure PowerShell
$r = Get-AzResource -ResourceName examplevnet -ResourceGroupName examplegroup
$r.Tags.Add("Status", "Approved")
Set-AzResource -Tag $r.Tags -ResourceId $r.ResourceId -Force
To apply all tags from a resource group to its resources, and not keep existing tags on the resources, use the following script:
Azure PowerShell
$groups = Get-AzResourceGroup
foreach ($g in $groups)
{
    Get-AzResource -ResourceGroupName $g.ResourceGroupName | ForEach-Object {Set-AzResource -ResourceId $_.ResourceId -Tag $g.Tags -Force }
}
To apply all tags from a resource group to its resources, and keep existing tags on resources that aren't duplicates, use the following script:
Azure PowerShell
$group = Get-AzResourceGroup "examplegroup"
if ($null -ne $group.Tags) {
    $resources = Get-AzResource -ResourceGroupName $group.ResourceGroupName
    foreach ($r in $resources)
    {
        $resourcetags = (Get-AzResource -ResourceId $r.ResourceId).Tags
        if ($resourcetags)
        {
            foreach ($key in $group.Tags.Keys)
            {
                if (-not($resourcetags.ContainsKey($key)))
                {
                    $resourcetags.Add($key, $group.Tags[$key])
                }
            }
            Set-AzResource -Tag $resourcetags -ResourceId $r.ResourceId -Force
        }
        else
        {
            Set-AzResource -Tag $group.Tags -ResourceId $r.ResourceId -Force
        }
    }
}
To remove all tags, pass an empty hash table:
Azure PowerShell
Set-AzResourceGroup -Tag @{} -Name examplegroup

Azure CLI

To see the existing tags for a resource group, use:
Azure CLI
az group show -n examplegroup --query tags
That script returns the following format:
JSON
{
  "Dept"        : "IT",
  "Environment" : "Test"
}
Or, to see the existing tags for a resource that has a specified name, type, and resource group, use:
Azure CLI
az resource show -n examplevnet -g examplegroup --resource-type "Microsoft.Network/virtualNetworks" --query tags
When looping through a collection of resources, you might want to show the resource by resource ID. A complete example is shown later in this article. To see the existing tags for a resource that has a specified resource ID, use:
Azure CLI
az resource show --id <resource-id> --query tags
To get resource groups that have a specific tag, use az group list:
Azure CLI
az group list --tag Dept=IT
To get all the resources that have a particular tag and value, use az resource list:
Azure CLI
az resource list --tag Dept=Finance
Every time you apply tags to a resource or a resource group, you overwrite the existing tags on that resource or resource group. Therefore, you must use a different approach based on whether the resource or resource group has existing tags.
To add tags to a resource group without existing tags, use:
Azure CLI
az group update -n examplegroup --set tags.Environment=Test tags.Dept=IT
To add tags to a resource without existing tags, use:
Azure CLI
az resource tag --tags Dept=IT Environment=Test -g examplegroup -n examplevnet --resource-type "Microsoft.Network/virtualNetworks"
To add tags to a resource that already has tags, retrieve the existing tags, reformat that value, and reapply the existing and new tags:
Azure CLI
jsonrtag=$(az resource show -g examplegroup -n examplevnet --resource-type "Microsoft.Network/virtualNetworks" --query tags)
rt=$(echo $jsonrtag | tr -d '"{},' | sed 's/: /=/g')
az resource tag --tags $rt Project=Redesign -g examplegroup -n examplevnet --resource-type "Microsoft.Network/virtualNetworks"
To apply all tags from a resource group to its resources, and not keep existing tags on the resources, use the following script:
Azure CLI
groups=$(az group list --query [].name --output tsv)
for rg in $groups
do
  jsontag=$(az group show -n $rg --query tags)
  t=$(echo $jsontag | tr -d '"{},' | sed 's/: /=/g')
  r=$(az resource list -g $rg --query [].id --output tsv)
  for resid in $r
  do
    az resource tag --tags $t --id $resid
  done
done
To apply all tags from a resource group to its resources, and keep existing tags on resources, use the following script:
Azure CLI
groups=$(az group list --query [].name --output tsv)
for rg in $groups
do
  jsontag=$(az group show -n $rg --query tags)
  t=$(echo $jsontag | tr -d '"{},' | sed 's/: /=/g')
  r=$(az resource list -g $rg --query [].id --output tsv)
  for resid in $r
  do
    jsonrtag=$(az resource show --id $resid --query tags)
    rt=$(echo $jsonrtag | tr -d '"{},' | sed 's/: /=/g')
    az resource tag --tags $t$rt --id $resid
  done
done

Templates

To tag a resource during deployment, add the tags element to the resource you're deploying. Provide the tag name and value.

Apply a literal value to the tag name

The following example shows a storage account with two tags (Dept and Environment) that are set to literal values:
JSON
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "location": {
            "type": "string",
            "defaultValue": "[resourceGroup().location]"
        }
    },
    "resources": [
        {
            "apiVersion": "2019-04-01",
            "type": "Microsoft.Storage/storageAccounts",
            "name": "[concat('storage', uniqueString(resourceGroup().id))]",
            "location": "[parameters('location')]",
            "tags": {
                "Dept": "Finance",
                "Environment": "Production"
            },
            "sku": {
                "name": "Standard_LRS"
            },
            "kind": "Storage",
            "properties": {}
        }
    ]
}
To set a tag to a datetime value, use the utcNow function.

Apply an object to the tag element

You can define an object parameter that stores several tags, and apply that object to the tag element. Each property in the object becomes a separate tag for the resource. The following example has a parameter named tagValues that is applied to the tag element.
JSON
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "location": {
            "type": "string",
            "defaultValue": "[resourceGroup().location]"
        },
        "tagValues": {
            "type": "object",
            "defaultValue": {
                "Dept": "Finance",
                "Environment": "Production"
            }
        }
    },
    "resources": [
        {
            "apiVersion": "2019-04-01",
            "type": "Microsoft.Storage/storageAccounts",
            "name": "[concat('storage', uniqueString(resourceGroup().id))]",
            "location": "[parameters('location')]",
            "tags": "[parameters('tagValues')]",
            "sku": {
                "name": "Standard_LRS"
            },
            "kind": "Storage",
            "properties": {}
        }
    ]
}

Apply a JSON string to the tag name

To store many values in a single tag, apply a JSON string that represents the values. The entire JSON string is stored as one tag that can't exceed 256 characters. The following example has a single tag named CostCenter that contains several values from a JSON string:
JSON
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "location": {
            "type": "string",
            "defaultValue": "[resourceGroup().location]"
        }
    },
    "resources": [
        {
            "apiVersion": "2019-04-01",
            "type": "Microsoft.Storage/storageAccounts",
            "name": "[concat('storage', uniqueString(resourceGroup().id))]",
            "location": "[parameters('location')]",
            "tags": {
                "CostCenter": "{\"Dept\":\"Finance\",\"Environment\":\"Production\"}"
            },
            "sku": {
                "name": "Standard_LRS"
            },
            "kind": "Storage",
            "properties": {}
        }
    ]
}

Apply tags from resource group

To apply tags from a resource group to a resource, use the resourceGroup function. When getting the tag value, use the tags.[tag-name] syntax instead of the tags.tag-name syntax, because some characters aren't parsed correctly in the dot notation.
JSON
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "location": {
            "type": "string",
            "defaultValue": "[resourceGroup().location]"
        }
    },
    "resources": [
        {
            "apiVersion": "2019-04-01",
            "type": "Microsoft.Storage/storageAccounts",
            "name": "[concat('storage', uniqueString(resourceGroup().id))]",
            "location": "[parameters('location')]",
            "tags": {
                "Dept": "[resourceGroup().tags['Dept']]",
                "Environment": "[resourceGroup().tags['Environment']]"
            },
            "sku": {
                "name": "Standard_LRS"
            },
            "kind": "Storage",
            "properties": {}
        }
    ]
}

Portal

  1. To view the tags for a resource or a resource group, looks for existing tags in the overview. If you have not previously applied tags, the list is empty.
    View tags for resource or resource group
  2. To add a tag, select Click here to add tags.
  3. Provide a name and value. Select + to add the tag.
    Add tag
  4. Continue adding tags as needed. When done, select Save.
    Save tags
  5. The tags are now displayed in the overview.
    Show tags
  6. To add or delete a tag, select change.
  7. To delete a tag, select the trash icon. Then, select Save.
    Delete tag
To bulk assign tags to multiple resources:
  1. From any list of resources, select the checkbox for the resources you want to assign the tag.
    Select multiple resources
  2. Select Assign tags
    Assign tags
  3. After each name and value, select +. When done, select Assign.
    Select assign
To view all resources with a tag:
  1. Select All services and Tags.
    Find by tag
  2. Select the tag for viewing resources.
    Select tag
  3. All resources with that tag are displayed.
    View resources by tag
  4. For quick access, pin the view to the dashboard.
    Pin to dashboard
  5. The view is available from the dashboard.
    Dashboard

REST API

The Azure portal and PowerShell both use the Resource Manager REST API behind the scenes. If you need to integrate tagging into another environment, you can get tags by using GET on the resource ID and update the set of tags by using a PATCH call.

Tags and billing

You can use tags to group your billing data. For example, if you're running multiple VMs for different organizations, use the tags to group usage by cost center. You can also use tags to categorize costs by runtime environment, such as the billing usage for VMs running in the production environment.
You can retrieve information about tags through the Azure Resource Usage and RateCard APIs or the usage comma-separated values (CSV) file. You download the usage file from the Azure Account Center or Azure portal. For more information, see Download or view your Azure billing invoice and daily usage data. When downloading the usage file from the Azure Account Center, select Version 2. For services that support tags with billing, the tags appear in the Tags column.
For REST API operations, see Azure Billing REST API Reference.

Next steps