marp | title | description | header | author | footer | theme | transition | paginate | _paginate | html |
---|---|---|---|---|---|---|---|---|---|---|
true |
Getting Started with Compliance & Governance using Azure Policy |
Presentation slides for Getting Started with Compliance & Governance using Azure Policy |
**[Getting Started with Compliance & Governance using Azure Policy](https://sheeeng.github.io/getting-started-with-compliance-and-governance-using-azure-policy-presentation/)** |
Leonard Sheng Sheng Lee |
[Leonard Sheng Sheng Lee](https://github.com/sheeeng) / Made with [Marp](https://marp.app/) |
uncover |
fade |
true |
true |
true |
- Recapitulation of DevOps Journey
- Compliance & Governance
- Basics of Azure Policy
<style scoped>img[alt="image"] { border: 3px solid #008AD7; width: 80%; } </style>
<style scoped>img[alt="image"] { border: 3px solid #008AD7; width: 80%; } </style>
DevOps, DevSecOps, GitOps
Site Reliability Engineering (SRE)
Platform Engineering
✨ Governance Engineering ✨
“Good strategy and good governance are the grease and guide rails for success.” - Bill Bensing
Applying SRE Principles to Regulated Software
Bill Bensing
Under Control: Why Governance Engineering
is Coming to Cloud Native
Ian Miell
"To put it plainly, regulators are going to expect compliance and audit functions to have the ability to report on their controls regularly, efficiently and clearly." - Ian Miell
Description vs. Implementation
- Azure resources must exist only in allowed locations.
For example, Norway or Europe regions.
Description vs. Implementation
- A Cloud Service Provider policy written in a product.
For example, Azure Policy.
- Efficiency and Speed
- Accuracy and Consistency
- Transparency, Scalability
- Adaptability
- Ian Miell
<style scoped>img[alt="image"] { border: 3px solid #008AD7; width: 90%; } </style>
Get-AzPolicyDefinition -BuiltIn `
| Where-Object {$_.Properties.metadata.category -eq 'Tags'} `
| Select-Object -ExpandProperty properties `
| Select-Object -Property DisplayName `
| Format-List
# OR
| Where-Object {$_.Properties.metadata.category -eq 'Storage'} `
# OR
| Where-Object {$_.Properties.metadata.category -eq 'Regulatory Compliance'} `
$policyDefinition = Get-AzPolicyDefinition `
-BuiltIn | Where-Object `
{$_.Properties.DisplayName -eq 'Require a tag on resources'}
# OR
{$_.Properties.DisplayName -eq 'Allowed locations for resource groups'}
# OR
{$_.Properties.DisplayName -eq 'Allowed locations'}
{
"properties": {
"displayName": "AuditResourcesTags",
"policyType": "Custom",
"mode": "All",
"description": "Enforces required tags and its value on resources.",
"metadata": {
"version": "1.0.0",
"category": "Tags"
},
//...
//... tagName1, tagValue1, tagName2, tagValue2, etc.
"parameters": {
//...
"tagName5": {
"type": "String",
"metadata": {
"displayName": "Fifth Tag Name",
"description": "Name of the tag, such as 'environment'."
}
},
"tagValue5": {
"type": "String",
"metadata": {
"displayName": "Fifth Tag Value",
"description": "Value of the tag, such as 'production'."
}
}
},
//...
//...
"policyRule": {
"if": {
"not": {
"anyOf": [
//... tagName1, tagName2, etc.
{
"field": "[concat('tags[', parameters('tagName5'), ']')]",
"equals": "[parameters('tagValue5')]"
}
]
}
},
"then": { "effect": "audit" }
}
}
}
//...
"policyRule": {
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
},
{
"not": {
"anyOf": [
//... tagName1, tagName2, etc.
{
"field": "[concat('tags[', parameters('tagName5'), ']')]",
"equals": "[parameters('tagValue5')]"
}
]
}
}
]
},
"then": { "effect": "audit" }
}
}
}
{
"properties": {
"displayName": "DenyActionDelete",
"policyType": "Custom",
"mode": "Indexed",
"description": "Deny action delete for critical resources.",
"metadata": {
"version": "1.0.0",
"category": "DenyAction"
},
//...
// ...
"parameters": {},
"policyRule": {
"if": {
"anyOf": [
{
"field": "type",
"equals": "Microsoft.DocumentDB/databaseAccounts"
},
{
"field": "type",
"equals": "Microsoft.Storage/storageAccounts"
},
{
"field": "type",
"equals": "Microsoft.KeyVault/vaults"
}
]
},
// ...
// ...
"then": {
"effect": "DenyAction",
"details": {
"actionNames": [
"delete"
],
"cascadeBehaviors": {
"resourceGroup": "deny"
}
}
}
}
}
}
New-AzPolicyDefinition `
-Name $name `
-Policy $policyFilePath `
-SubscriptionId $subscriptionId
<style scoped>img[alt="image"] { border: 3px solid #008AD7; width: 90%; } </style>
<style scoped>img[alt="image"] { border: 3px solid #008AD7; width: 90%; } </style>
Exhibit: Azure Policy Assignment Require resources to have a 'Creator` tag.
$policyParameterObject = @{ 'tagName' = 'Creator' }
$message="Creator tag is required for resources."
$nonComplianceMessages = @( @{Message=$message} )
$policyAssignment = New-AzPolicyAssignment `
-Name $REQUIRE_RESOURCES_CREATOR_TAG `
-Scope "/subscriptions/$($azContext.Subscription.Id)" `
-PolicyDefinition $policyDefinition `
-PolicyParameterObject $policyParameterObject `
-NonComplianceMessage $nonComplianceMessages
Exhibit: Azure Policy Assignment Require resources reside in allowed locations.
$allowedLocations = Get-AzLocation `
| Where-Object `
{($_.DisplayName -like '*europe*') -or ($_.DisplayName -like '*norway*')}
$policyParameterObject = @{'listOfAllowedLocations'=($allowedLocations.location)}
$message="The selected locations are not allowed for resources."
$nonComplianceMessages = @( @{Message=$message} )
$policyAssignment = New-AzPolicyAssignment `
-Name $REQUIRE_RESOURCES_ALLOWED_LOCATIONS `
-Scope "/subscriptions/$($azContext.Subscription.Id)" `
-PolicyDefinition $policyDefinition `
-PolicyParameterObject $policyParameterObject `
-NonComplianceMessage $nonComplianceMessages
}
Exhibit: Azure Policy Assignment Audit resources to have the five tags. (Part 1/2)
$policyParameterObject = @{
'tagName1' = 'Organization'
'tagValue1' = 'Acme Corporation'
'tagName2' = 'BusinessUnit'
'tagValue2' = 'Road Runner'
'tagName3' = 'ProjectOwner'
'tagValue3' = 'Wile E. Coyote'
'tagName4' = 'Application'
'tagValue4' = 'Beep-Beep!'
'tagName5' = 'Environment'
'tagValue5' = 'Fast and Furry-ous'
}
Exhibit: Azure Policy Assignment Audit resources to have the five tags. (Part 2/2)
$message="Required tags and its values are needed for resources."
$nonComplianceMessages = @( @{Message=$message} )
$policyAssignment = New-AzPolicyAssignment `
-Name $AUDIT_RESOURCES_TAGS `
-Scope "/subscriptions/$($azContext.Subscription.Id)" `
-PolicyDefinition $policyDefinition `
-PolicyParameterObject $policyParameterObject `
-NonComplianceMessage $nonComplianceMessages
Exhibit: Azure Policy Assignment DenyAction Delete
$message="Deny action delete for critical resources."
$nonComplianceMessages = @( @{Message=$message} )
$policyAssignment = New-AzPolicyAssignment `
-Name $policyDefinition.Name `
-Scope "/subscriptions/$($azContext.Subscription.Id)" `
-PolicyDefinition $policyDefinition `
-NonComplianceMessage $nonComplianceMessages
Exhibit: Missing Required Tag
<style scoped>img[alt="image"] { border: 3px solid #008AD7; width: 70%; } </style>Exhibit: Missing Allowed Locations
<style scoped>img[alt="image"] { border: 3px solid #008AD7; width: 65%; } </style>Exhibit: DenyAction Delete
<style scoped>img[alt="image"] { border: 3px solid #008AD7; width: 65%; } </style>Exhibit: Azure Resource Manager (ARM) Templates
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
//...
"resources": [
{
"name": "[format('store{0}', uniqueString(resourceGroup().id))]",
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2022-09-01",
"tags": {},
"location": "[resourceGroup().location]",
"kind": "StorageV2",
"sku": {
"name": "[parameters('storageAccountType')]"
}
}
],
"outputs": {}
}
<style scoped>img[alt="giffiti"] { border: 3px solid #008AD7; width: 80%; } </style>
Exhibit: Azure Bicep Storage Account Without Tags
resource storageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' = {
name: uniqueStorageName
location: location
sku: {
name: storageSKU
}
kind: 'StorageV2'
properties: {
supportsHttpsTrafficOnly: true
}
tags: null
}
Exhibit: Terraform Storage Account Without Tags
resource "azurerm_storage_account" "deleteme654" {
name = "deleteme654"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.name
account_tier = "Standard"
account_replication_type = "LRS"
tags = null
}
[
{
"info": {
"evaluationDetails": {
"evaluatedExpressions": [
{
"expression": "tags[Creator]",
"expressionKind": "Field",
"operator": "Exists",
"path": "tags[Creator]",
"result": "True",
"targetValue": "false"
}
],
"reason": "Creator tag is required for resources."
},
"policyAssignmentId": ".../policyAssignments/RequireResourcesCreatorTag",
"policyAssignmentName": "RequireResourcesCreatorTag",
"policyAssignmentParameters": {
"tagName": "Creator"
},
"policyAssignmentScope": "/subscriptions/***",
"policyDefinitionDisplayName": "Require a tag on resources",
"policyDefinitionEffect": "deny",
"policyDefinitionId": "...",
"policyDefinitionName": "871b6d14-10aa-478d-b590-94f262ecfa99",
"policyExemptionIds": []
},
"type": "PolicyViolation"
}
]
Exhibit: Azure Bicep
Resource Group not in Allowed Locations
resource newRG 'Microsoft.Resources/resourceGroups@2021-01-01' = {
name: resourceGroupName
location: 'Taiwan North'
}
Exhibit: Terraform
Resource Group not in Allowed Locations
resource "azurerm_resource_group" "deleteme987" {
name = "deleteme987"
location = "Taiwan North"
}
[
{
"info": {
"evaluationDetails": {
"evaluatedExpressions": [
{
"expression": "type",
"expressionKind": "Field",
"expressionValue": "Microsoft.Resources/subscriptions/resourcegroups",
"operator": "Equals",
"path": "type",
"result": "True",
"targetValue": "Microsoft.Resources/subscriptions/resourceGroups"
},
{
"expression": "location",
"expressionKind": "Field",
"expressionValue": "taiwannorth",
"operator": "NotIn",
"path": "location",
"result": "True",
"targetValue": [
"northeurope",
"westeurope",
"norwayeast",
"europe",
"norway",
"norwaywest"
]
}
],
"reason": "The selected locations are not allowed for resource groups."
},
//...
//...
"policyAssignmentId": ".../policyAssignments/RequireResourceGroupsAllowedLocations",
"policyAssignmentName": "RequireResourceGroupsAllowedLocations",
"policyAssignmentParameters": {
"listOfAllowedLocations": [
"northeurope",
"westeurope",
"norwayeast",
"europe",
"norway",
"norwaywest"
]
},
"policyAssignmentScope": "/subscriptions/***",
"policyDefinitionDisplayName": "Allowed locations for resource groups",
"policyDefinitionEffect": "deny",
"policyDefinitionId": "...",
"policyDefinitionName": "e765b5de-1225-4ba3-bd56-1ac6695af988",
"policyExemptionIds": []
},
"type": "PolicyViolation"
}
]
Exhibit: DenyAction Delete for Storage Account
[
{
"info": {
"evaluationDetails": {
"evaluatedExpressions": [
{
"expression": "type",
"expressionKind": "Field",
"expressionValue": "Microsoft.Storage/storageAccounts",
"operator": "Equals",
"path": "type",
"result": "True",
"targetValue": "Microsoft.Storage/storageAccounts"
}
],
"reason": "Deny action delete for critical resources."
},
// ...
// ...
"policyAssignmentId": ".../policyAssignments/DenyActionDelete",
"policyAssignmentName": "DenyActionDelete",
"policyAssignmentParameters": {},
"policyAssignmentScope": "/subscriptions/***",
"policyDefinitionDisplayName": "DenyActionDelete",
"policyDefinitionEffect": "DenyAction",
"policyDefinitionId": "/...",
"policyDefinitionName": "DenyActionDelete",
"policyExemptionIds": []
},
"type": "PolicyViolation"
}
]
Agility
Governance
<style scoped>img[alt="image"] { width: 35%; float: center; } </style>This page intentionally left blank.