Can't pass a format parameter to uctNow() function - azure

I try to create an azure policy that appends a created-on : dd/mm/yyyy tag on newly created resources.
I'm using the following default policy :
{
"properties": {
"displayName": "Append a tag and its value to resources",
"policyType": "BuiltIn",
"mode": "Indexed",
"description": "Appends the specified tag and value when any resource which is missing this tag is created or updated. Does not modify the tags of resources created before this policy was applied until those resources are changed. Does not apply to resource groups. New 'modify' effect policies are available that support remediation of tags on existing resources (see https://aka.ms/modifydoc).",
"metadata": {
"version": "1.0.1",
"category": "Tags"
},
"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": {
"field": "[concat('tags[', parameters('tagName'), ']')]",
"exists": "false"
},
"then": {
"effect": "append",
"details": [
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"value": "[parameters('tagValue')]"
}
]
}
}
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/2a0e14a6-b0a6-4fab-991a-187a4f81c498",
"type": "Microsoft.Authorization/policyDefinitions",
"name": "2a0e14a6-b0a6-4fab-991a-187a4f81c498"
}
With the following parameters : [utcNow('d')]
Unfortunately as you can see I keep getting this error message.
The inner exception 'The policy language function 'utcNow' has '1'
argument(s). Expected number of arguments is '0'.
According to the documentation, shouldn't I be able to set a 'd' parameters to the function ?
If I removed the parameters it works and gives me the date in yyyyMMddTHHmmssZ format as per the documentation says.
How to get the date in dd/mm/yyyy format instead?

Some of the ARM template functions are not allowed to use in policy definition. You can check it here.
utcNow() - Unlike an ARM template, this property can be used outside defaultValue.
Returns a string that is set to the current date and time in Universal ISO 8601 DateTime format yyyy-MM-ddTHH:mm:ss.fffffffZ.

The best solution I have seen makes use of the Concat function along with substring. My implementation looks like this:
"field": "tags['CreatedOnDate']",
"value": "[concat(substring(utcNow(),5,2),'/', substring(utcNow(),8,2),'/',substring(utcNow(),0,4),'-',substring(utcNow(),11,8))]"
Which produces a result like 11/30/2022-18:45:55

Related

Azure Policy - GitHub Actions - Authoring Custom Policies

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":{}
}

Azure Policy field type

I want to create a policy where i audit/deny PostgreSQL Databases which do not have firewall rules configured. This is a policy which is workin but the compliance state shows every single rule in it...
{
"mode": "All",
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.DBforPostgreSQL/servers/firewallRules"
},
{
"field": "Microsoft.DBforPostgreSQL/servers/firewallRules/startIpAddress",
"exists": "false"
},
{
"field": "Microsoft.DBforPostgreSQL/servers/firewallRules/endIpAddress",
"exists": "false"
}
]
},
"then": {
"effect": "[parameters('effect')]"
}
},
"parameters": {
"effect": {
"type": "String",
"metadata": {
"displayName": "Effect",
"description": "The effect determines what happens when the policy rule is evaluated to match"
},
"allowedValues": [
"Audit",
"Deny",
"Disabled"
],
"defaultValue": "Audit"
}
}
}
As soon as I change Microsoft.DBforPostgreSQL/servers/firewallRules to Microsoft.DBforPostgreSQL/servers it cannot create the policy with error:
The policy definition '6bab4b2f-30b3-4f07-a92e-496b6309d14d' targets multiple resource types, but the policy rule is authored in a way that makes the policy not applicable to the target resource types 'Microsoft.DBforPostgreSQL/servers,Microsoft.DBforPostgreSQL/servers/firewallRules'. This is because the policy rule has a condition that can never be satisfied by the target resource types. If an alias is used, please make sure that the alias gets evaluated against only the resource type it belongs to by adding a type condition before it, or split the policy into multiple ones to avoid targeting multiple resource types.
Does anyone have an idea how to fix that?

How ignore/hide/deactivate my policy non-compliance state and get 100% compliance?

Below is my policy definition and is correctly working (policy is responsible to assign tags from resource group to resources):
{
"properties": {
"displayName": "inheritTags",
"policyType": "Custom",
"mode": "Indexed",
"metadata": {
"createdBy": "3332dc03-2402-46e3-9098-c7350b0bc8dd",
"createdOn": "2019-11-25T14:49:57.8136557Z",
"updatedBy": "3332dc03-2402-46e3-9098-c7350b0bc8dd",
"updatedOn": "2019-11-26T19:43:48.752452Z"
},
"parameters": {},
"policyRule": {
"if": {
"allOf": [
{
"value": "[resourceGroup().tags]",
"exists": "true"
},
{
"value": "[resourceGroup().tags]",
"notEquals": ""
}
]
},
"then": {
"effect": "modify",
"details": {
"operations": [
{
"operation": "addOrReplace",
"field": "tags",
"value": "[resourceGroup().tags]"
}
],
"roleDefinitionIds": [
"/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
]
}
}
}
},
"id": "/subscriptions/78afced4-1c58-4e66-8242-c042890d34c3/providers/Microsoft.Authorization/policyDefinitions/9f2a0e94-5ada-47b0-8125-42464f93cf37",
"type": "Microsoft.Authorization/policyDefinitions",
"name": "9f2a0e94-5ada-47b0-8125-42464f93cf37"
}
Nevertheless in Overview tab on Policy page I have information that assigned policy definition is in Non-compliant state:
Reason for that? Different values due to comparing previous state to expected state and I know that source of "issues" are keywords like exists, notEquals and so on: https://learn.microsoft.com/en-us/azure/governance/policy/how-to/determine-non-compliance#compliance-reasons
How to ignore those compliance messages and get resource compliance, you know tags are correctly assigned so what is the problem? or maybe I have wrong understanding of azure policies?
The resources that are coming up as non-compliant is because they do not have the same tags as the RG. For some resources, modify won't because they don't support tags or don't support updating/adding tags. I can't tell what type of resource it is so I can't say forsure that is the issues. If this is the case that those resources don't support tags, then you can just excluded that resource from the assignment to see the compliance percentage not including those. (Edit the assignment and add an exclusion)

How to call a REST function from an Azure Policy

Is it possible to call an Azure Function from an Azure Policy ?
Assume a function that returns a boolean based on a ResourceId. The function looks up the resource and decides if the resource contains a tag with a certain name and if the tag conforms to a set list of values. If the tag conforms, the resource returns true, otherwise false.
Consider the policy below and note the PCODE section.
Is something like this possible ? I can find no documentation or samples allowing this.
{
"properties": {
"displayName": "Enforce tag and its value",
"policyType": "BuiltIn",
"description": "Enforces a required tag and its value.",
},
"policyRule": {
"if": {
//ORIGINAL IN SAMPLE
"not": {
"field": "MyTagName",
"equals": "Sample Tag Value"
}
//PCODE TO CALL FUNCTION
"not": {
"evaluate": "https://url.../ReturnsBoolean/resourceId()"
}
},
"then": {
"effect": "deny"
}
}
},
"id": "/providers/Microsoft.Authorization/policyDefinitions/1e30110a-5ceb-460c-a204-c1c3969c6d62",
"type": "Microsoft.Authorization/policyDefinitions",
"name": "1e30110a-5ceb-460c-a204-c1c3969c6d62"
}
This is not currently possible using azure policy as it exists today.
The following document shows you the policy functions that azure policy supports:
policy-functions

Policy and Initiative to copy Tags to resources in Resource Group

I'm struggling to create a parameterized version of the Azure Policy example which copies Tags applied to a Resource Group to any resources within it. This is the example I'm using as inspiration: https://github.com/Azure/azure-policy/tree/master/samples/ResourceGroup/copy-resourcegroup-tag, which is:
{
"if": {
"field": "tags.example",
"exists": "false"
},
"then": {
"effect": "append",
"details": [
{
"field": "tags.example",
"value": "[resourceGroup().tags.example]"
}
]
}
}
We have a number of tags added to Resource Groups, and for billing purposes I need to ensure these are applied to all resources within. I am looking to create an Initiative which contains the same policy several times, each time using a different parameterized tag name. My parameterized version of the example policy looks like this:
"parameters": {
"tagName": {
"type": "String",
"metadata": {
"displayName": "Tag name",
"description": "The tag to copy to child resources"
}
}
},
"policyRule": {
"if": {
"field": "[concat('tags.', parameters('tagName'))]",
"exists": "false"
},
"then": {
"effect": "append",
"details": [
{
"field": "[concat('tags.', parameters('tagName'))]",
"value": "[concat('resourceGroup().tags.', parameters('tagName'))]"
}
]
}
}
When the policy applies I get a result of non-compliant. Viewing the compliance details shows:
Reason for non-compliance
Current value must exist.
Field
tags.ApplicationName
Current value
--
There is a tag called ApplicationName with a value on the Resource Group. The documentation says the reason for "Current value must exist" is the exists condition. This seems counter-intuitive to the way I am expecting this to work - I know it doesn't exist which is why I want to set the value.
Is there any way to debug these beyond assigning the policy and waiting several hours for a result?
Thanks for your help!
I've figured this out, my syntax was wrong, I need to refer to the Tags using keys rather than as attributes, i.e. tags['ApplicationName'] rather than tags.ApplicationName. The policyRule property needs to be:
"policyRule": {
"if": {
"field": "[concat('tags[', parameters('tagName'), ']')]",
"exists": "false"
},
"then": {
"effect": "append",
"details": [
{
"field": "[concat('tags[', parameters('tagName'), ']')]",
"value": "[resourceGroup().tags[parameters('tagName')]]"
}
]
}
}
I also misunderstood how this feature works, it seems that policies with an Append effect can only append at the point of resource creation, not retrospectively on an existing resource. The above policy adds the Tags for new resources but results in a "non-compliant" report for existing resource.
This behavior is as documented here:
"When a policy definition using the append effect is run as part of an evaluation cycle, it doesn't make changes to resources that already exist. Instead, it marks any resource that meets the if condition as non-compliant."

Resources