I need to enforce that when user creates a storage account in azure, it should get appended with customer managed keys. Platform managed keys are prohibited to be used by storage account. Below is the policy that's created . Although the policy is successfully deployed, the storage accounts that we create after the policy deployment does not append the customer manged key details that's defined inside the Azure policy even after 2 hours. When we try adding customer managed key, it instead throws error telling- "Policies attempted to append some fields which already exist in the request with different values. Fields: 'Microsoft.Storage/storageAccounts/encryption.KeySource'. Policy identifiers:'[{"policyAssignment":{"name":"Encryption settings to Storage Account for customer-provided key","id":"funRulerg-mj/providers/Microsoft.Authorization/policyAssignments/"
Can someone pls help me understand, why inspite of "append" effect the policy is not appending the customer managed keys to the storage account. And the error clearly tells that the policy is already in effect due to which it is not allowing to add any customer managed key as well to the storage accounts.
{
"properties": {
"displayName": "Append encryption settings to Storage Account for customer-provided key",
"description": "If customer-provided key isn't configured, append encryption settings to Storage Account using customer-provided key",
"mode": "all",
"parameters": {
"keyvaulturi": {
"type": "String",
"metadata": {
"description": "Uri location of the Key Vault to use for Storage Service Encryption"
}
},
"keyname": {
"type": "String",
"metadata": {
"description": "Name of the Key to use for Storage Service Encryption"
}
}
},
"policyRule": {
"if": {
"allof": [
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"field": "Microsoft.Storage/storageAccounts/encryption.KeySource",
"equals": "Microsoft.Storage"
}
]
},
"then": {
"effect": "append",
"details": [
{
"field": "Microsoft.Storage/storageAccounts/encryption.KeySource",
"value": "Microsoft.Keyvault"
},
{
"field": "Microsoft.Storage/storageAccounts/encryption.keyvaultproperties.keyvaulturi",
"value": "[parameters('keyvaulturi')]"
},
{
"field": "Microsoft.Storage/storageAccounts/encryption.keyvaultproperties.keyname",
"value": "[parameters('keyname')]"
}
]
}
}
}
}
The field "Microsoft.Storage/storageAccounts/encryption.KeySource" is set to "Microsoft.Storage", and according to this https://rjygraham.com/posts/azure-policy-append-as-gentler-deny.html, "Append evaluates before the request gets processed by a Resource Provider during the creation or updating of a resource. Append adds fields to the resource when the if condition of the policy rule is met. If the append effect would override a value in the original request with a different value, then it acts as a deny effect and rejects the request". In the "details" policy is trying to change the vaule of field "Microsoft.Storage/storageAccounts/encryption.KeySource" to "Microsoft.Keyvault" this might be the issue.
Related
I'm working on testing out using GitHub and GitHub Actions to do policy as code for Azure. I have been successful in following the tutorials that Microsoft has where you export the policy you want to manage to GitHub from the Azure portal. This works fine and I'm able to edit and run the workflows to update Azure with changes to policies.
What I'd like to know is, can you create NEW policies in GitHub and push them to Azure? It seems that you need to first export a custom policy from Azure into GitHub, then you can manage that policy. I say this because when I create a new policy and a workflow for that policy I get the following error in GitHub from the workflow:
> Did not find any policies to create/update. No policy files match the
> given patterns or no changes were detected.
The policy I have in the folder is called "policy.json"
I also see:
Error occured while reading policy in path :
policies/global_tagging_policy. Error : Error: Path :
policies/global_tagging_policy. Property id is missing from the policy
definition. Please add id to the definition file.
That leads me to believe I need an ID prior to being able to push a policy, that says to me that Azure must have assigned one... I can't just make one up.
This is the policy I'm trying to push - just a tagging policy for testing, I don't have an ID in there, I read that you don't need to add one... that Azure would do it for you. Am I wrong?:
{
"properties": {
"displayName": "test-policy",
"description": "this is a test policy",
"mode": "indexed",
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag Name",
"description": "Name of the tag, such as 'environment'"
}
},
"tagValue": {
"type": "String",
"metadata": {
"displayName": "Tag Value",
"description": "Value of the tag, such as 'production'"
}
}
}
},
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
},
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"exists": "false"
}
]
},
"then": {
"effect": "modify",
"details": {
"roleDefinitionIds": [
"/providers/microsoft.authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
],
"operations": [
{
"operation": "add",
"field": "[concat('tags[', parameters('tagName'), ']')]",
"value": "[parameters('tagValue')]"
}
]
}
}
}
}
This tripped me up too so I did some exploring of the APIs and files. I've written about this in greater detail here.
To create a custom Policy, Initiative or Assignment file using GitHub Actions you'll need to generate an id, name & type at the root of the JSON.
The name property needs to be unique at the scope you assign it, I use GUIDs for this but you don't have to. Bear in mind if you define/assign at the Management Group scope then the name needs to be 24 characters or less.
The type denotes the type of file, the options are:
Microsoft.Authorization/policyDefinitions --> Policies
Microsoft.Authorization/policySetDefinitions --> Initiatives
Microsoft.Authorization/policyAssignments --> Assignments
The id is a bit more complex, and is a concatenation of the name and type values with other values mixed in.
The prefix depends on the scope which you want to define your Policy/Initiative/Assignment.
For Management Groups it would be:
/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000
Subscriptions would be:
/subscrptions/00000000-0000-0000-0000-000000000000
Resource Groups:
/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroup
This is followed by: providers in all cases
Next is the type value, so whatever you've used for that use again here.
Finally the last segment of the id is the same value you've used for the name property.
In one line that is
/{scope}/providers/{type}/{name}
So as an example:
Policy Definition scoped at a Management Group
{
"id": "/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/policyDefinitions/5f44e572-5d2d-4edf-9d61",
"name": "5f44e572-5d2d-4edf-9d61",
"type": "Microsoft.Authorization/policyDefinitions",
"properties":{}
}
Policy Definition scoped at a Subscription
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/policyDefinitions/8e4a8c58-1938-4467-8698",
"name": "8e4a8c58-1938-4467-8698",
"type": "Microsoft.Authorization/policyDefinitions",
"properties":{}
}
Initiative scoped at a Management Group
{
"id": "/providers/Microsoft.Management/managementGroups/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/policySetDefinitions/be09f23f-0252-4d8a-a805",
"name": "5f44e572-5d2d-4edf-9d61",
"type": "Microsoft.Authorization/policySetDefinitions",
"properties":{}
}
Initiative scoped at a Subscription
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/policySetDefinitions/8e4a8c58-1938-4467-8698",
"name": "8e4a8c58-1938-4467-8698",
"type": "Microsoft.Authorization/policySetDefinitions",
"properties":{}
}
I need to stop creation of all resources on my azure subscription except for:
Logic Apps
Dashboards
Solutions
the only way I can think of doing this right now is via Azure Policy, will anyone know how to write such policy?
well, you basically need to use not and anyof in combination with deny:
"if": {
"not": {
"anyOf": [
{
"field": "type",
"equals": "Microsoft.Logic/workflows"
},
{
"field": "type",
"equals": "Microsoft.OperationsManagement/solutions"
},
{
"field": "type",
"equals": "Microsoft.Portal/dashboards"
}
]
}
},
"then": {
"effect": "Deny"
}
resource types might be wrong, but I'm not sure what are you after exactly.
Policies require definitions (where the policy logic is written) and then a policy assignment (where the definition is assigned to a scope). Policy definitions can be grouped into Policy Initiatives (AKA Policy Set Definitions). These Initiatives can also be assigned to a scope. Scopes can be defined at the Resource Group level, Subscription level, or Management Group level.
Policies can be written and assigned through the portal by first creating a policy definition and then assigning it. IMO this can be a bit cumbersome when done through the portal. Or they can be deployed via ARM template. Unfortunately, the portal template deployment is not currently configured to deploy at anything other than at the resource group level (08/29/2019). But it is much easier to write and deploy via the deployment API. I use Postman to do this.
A subscription scoped (as you are describing) policy deployment can be done via PUT to the following URI.
https://management.azure.com/subscriptions/:subscriptionId/providers/Microsoft.Resources/deployments/mypolicydeployment?api-version=2019-05-01
Where :subscriptionId is Postman parameter notation for your actual Subscription ID.
You will need to obtain a bearer token to authenticate for the PUT request and that user must have permissions to deploy and assign policies. That is a whole other topic, you can learn more about that here (https://learn.microsoft.com/en-us/azure/active-directory/develop/v1-protocols-oauth-code).
Also, I supply a "Content-Type" = "application/json" header with my PUT request.
My this is my body payload for your policy.
{
"location": "westus2",
"properties": {
"mode": "Incremental",
"template": {
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"subscriptionId": {
"type": "string"
}
},
"resources": [
{
"type": "Microsoft.Authorization/policyDefinitions",
"name": "my-deny-policy",
"apiVersion": "2018-05-01",
"location": "westus2",
"properties": {
"displayName": "My Deny Policy",
"policyType": "Custom",
"description": "This policy DENYS all resource creation except, Logic Apps, Dashboards, and Solutions.",
"mode": "All",
"policyRule": {
"if": {
"not": {
"anyOf": [
{
"field": "type",
"equals": "Microsoft.Logic/workflows"
},
{
"field": "type",
"equals": "Microsoft.OperationsManagement/solutions"
},
{
"field": "type",
"equals": "Microsoft.Portal/dashboards"
}
]
}
},
"then": {
"effect": "Deny"
}
}
}
},
{
"name": "my-policy-assignment",
"type": "Microsoft.Authorization/policyAssignments",
"apiVersion": "2018-05-01",
"location": "westus2",
"identity": {
"type": "SystemAssigned"
},
"properties": {
"displayName": "My Policy Assignment",
"policyDefinitionId": "[concat('/subscriptions/', parameters('subscriptionId'), '/providers/Microsoft.Authorization/policyDefinitions/my-deny-policy')]",
"scope": "[concat('/subscriptions/', parameters('subscriptionId'), '/')]",
"notScopes": [],
"parameters": {},
"description": "This assignment contains my policy to DENY creation of all resources except logic apps, dashboards, and solutions.",
"metadata": {}
},
"dependsOn": [
"my-deny-policy"
]
}
]
},
"parameters": {
"subscriptionId": {
"value": "XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX"
}
}
}
}
The deployment template contains a definition containing the policy you have described, as well as a policy assignment. The policy assignment is set to "dependsOn" the policy definition. This is because the policy assignment depends on the existence of the definition to deploy properly. Otherwise, there will be a race condition that you will always lose.
Certain fields can be broken out into parameters as I have done with the subscription ID. In order to apply at another subscription scope, simply change the parameter value and make sure your bearer token is authorized for that subscription.
Where exactly you stock in creating azure policy?
Refer this doc, You can restrict/allow upon resource types
Make a Custom RBAC Role with "ACTIONS" only for these 3 you want.
Policy is OK here but it depends on the User role if he would be able to Unassign such policy from the Subscription.
To prevent user to do so:
Apply policy on level higher then subscrption (mgmt group) where user has no rights.
OR disallow user (in RBAC role) to work on Policy
Definitions & Assigments.
OR Create this Policy with Blueprint and
set ReadOnly Lock for this Bluepring Assignment.
I've applied Azure policy which forces the user to assign a tag while creating a Resource Group.
When i create a new VM and then fill in all the fields, i create a new Resource Group in the same wizard and then click review and create button. This time azure policy is triggered properly and blocks me as the newly created RG is not created with tag.
But when I go to resource group policy and click on Add to create a new RG. that time i don't fill Tags then too policy doesn't get trigger.
I'm little surprise why the first time this policy is working but not the second time.
{
"if": {
"allOf": [
{
"field": "tags",
"exists": "false"
},
{
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
}
]
},
"then": {
"effect": "deny"
}
}
The discrepancy you are experiencing is caused by differences in the JSON representation of the resource group.
Depending on what you click in the portal, the resource group JSON may not have a tags property, e.g.:
{
"id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/foo",
"name": "foo",
"location": "eastus",
"properties": {
"provisioningState": "Succeeded"
}
}
Other times it may be created with an empty tags property, e.g:
{
"id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/foo",
"name": "foo",
"location": "eastus",
"properties": {
"provisioningState": "Succeeded"
},
"tags": {}
}
The "exists": "false" condition in your policy rule will only trigger if the "tags" property is either missing or null, so a resource group with "tags": {} will bypass your policy even though it doesn't have any tags.
Seems figure it out, it is not related to the Azure policy, your policy should work fine, it may be a bug of the blade of creating the resource group in the portal.
I try to create a resource group via powershell several times, the policy works fine.
My test policy:
If it is necessary, you could open an issue in the Github.
I'm trying to force anyone that is provisioning resources or services in Azure to only be able to select a specific region(s). For example, when they provision a resource group, the dropdown only shows a specific region(s). I was hoping there is some global setting that will affect all users. We are also using Azure AD; does that help or matter? I tried searching the Azure docs and the PowerShell commands, but I just can't find any mention of this setting.
You could use Azure Policy to do it.
Here is a sample policy requires that all resources are deployed to the approved location, refer to this link, you could try to deploy with portal or with powershell.
This policy requires that all resources are deployed to the approved locations. You specify an array of approved locations.
Sample template:
{
"properties": {
"displayName": "Allowed locations",
"policyType": "BuiltIn",
"description": "This policy enables you to restrict the locations your organization can specify when deploying resources. Use to enforce your geo-compliance requirements.",
"parameters": {
"listOfAllowedLocations": {
"type": "Array",
"metadata": {
"description": "The list of locations that can be specified when deploying resources.",
"strongType": "location",
"displayName": "Allowed locations"
}
}
},
"policyRule": {
"if": {
"not": {
"field": "location",
"in": "[parameters('listOfAllowedLocations')]"
}
},
"then": {
"effect": "Deny"
}
}
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c",
"type": "Microsoft.Authorization/policyDefinitions",
"name": "e56962a6-4747-49cd-b67b-bf8b01975c4c"
}
is there any way how to restrict access or buy permissions at Azure Marketplace?
You can create a policy like the one below to restrict compute resources from a specific publisher -
{
"policyRule": {
"if": {
"allOf": [
{
"field": "Microsoft.Compute/imagePublisher",
"match": "[parameters('NotAllowedImage')]"
}
]
},
"then": {
"effect": "Deny"
}
},
"parameters": {
"NotAllowedImage": {
"type": "String",
"metadata": {
"displayName": "Not Allowed Image",
"description": "Not Allowed Image for Virtual Machine/Compute"
}
}
},
"metadata": {
"category": "Compute"
}
}
When you assign this image to a subscription or a resource group then at the time you will be asked to enter a value for the image name you would like to restrict , please enter "checkpoint" as your publisher name as this is the one you want to restrict. Save the assignment.
Now once you create a vm/compute resource from "checkpoint" this would fail the validation step as the policy would not allow to create such vm/compute resource.
The Category of the check point resources I see in market place is compute only.
We might not have restrictions on what we can choose from market place but we can utilize azure policy for certain resource regulation/compliance.
These policies would help enforce different rules over your resources(VM'S , VM-SKU , Network , Storage etc.). If you need resources created to stay compliant with your company standards/service level agreements.
Whenever we create resource which has policy tied to it these are evaluated and scanned for compliance with that policy.
More info here - https://learn.microsoft.com/en-us/azure/azure-policy/azure-policy-introduction