Skip to content

Commit 9b40c9f

Browse files
author
Alexander (Sasha) Nosov
committed
Add arc-sql-licence-type-compliance policy
1 parent 62ee48c commit 9b40c9f

4 files changed

Lines changed: 268 additions & 0 deletions

File tree

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
# LicenceType-SQLArc
2+
3+
This Azure Policy ensures that all SQL Arc servers have the required `LicenseType` value. Servers that do not match the required license type are marked as non-compliant. The remediation task sets `LicenseType` to the value specified by the `requiredLicenseType` parameter.
4+
5+
Use Azure CLI or PowerShell to create the policy definition.
6+
7+
## Artifacts
8+
9+
- **policy.json**: Main policy definition referencing external parameter and rule files.
10+
- **params.json**: Defines policy parameters.
11+
- **rules.json**: Contains the policy rule logic.
12+
13+
## Copy policy artifacts to your environment
14+
15+
```PowerShell
16+
17+
curl https://raw.githubusercontent.com/microsoft/sql-server-samples/refs/heads/master/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-licence-type-compliance/params.json -o params.json
18+
curl https://raw.githubusercontent.com/microsoft/sql-server-samples/refs/heads/master/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-licence-type-compliance/rules.json -o rules.json
19+
20+
```
21+
22+
## Create policy
23+
24+
Use the following command to create policy
25+
26+
```PowerShell
27+
28+
$SubId = "<your-subscription-id>"
29+
$PolicyName = "LicenceType-SQLArc"
30+
31+
az policy definition create `
32+
--name $PolicyName `
33+
--display-name $PolicyName `
34+
--description "This Azure Policy ensures that all SQL Arc servers have the required LicenseType. Servers that do not match are marked as non-compliant and remediated to the required license type." `
35+
--rules "@rules.json" `
36+
--params "@params.json" `
37+
--mode Indexed `
38+
--subscription $SubId `
39+
--only-show-errors | Out-Null
40+
```
41+
42+
## Assign policy
43+
44+
Use the following command to assign policy
45+
46+
```PowerShell
47+
48+
$SubId = "<your-subscription-id>"
49+
$RgName = "<your-resource-group>" # optional; set to "" to target subscription scope
50+
$Location = "<your-azure-region>" # e.g., eastus, westus2
51+
$RequiredLicenseType = "PAYG" # e.g., PAYG, LicenseOnly
52+
53+
if ([string]::IsNullOrWhiteSpace($RgName)) {
54+
$Scope = "/subscriptions/$SubId"
55+
} else {
56+
$Scope = "/subscriptions/$SubId/resourceGroups/$RgName"
57+
}
58+
59+
az account set --subscription $SubId
60+
61+
az policy assignment create `
62+
--name "LicenceType-SQLArc-Assign" `
63+
--policy "LicenceType-SQLArc" `
64+
--scope "$Scope" `
65+
--params "{ \"effect\": { \"value\": \"DeployIfNotExists\" }, \"requiredLicenseType\": { \"value\": \"$RequiredLicenseType\" } }" `
66+
--mi-system-assigned `
67+
--role "Contributor" `
68+
--identity-scope "$Scope" `
69+
--location "$Location" `
70+
--only-show-errors | Out-Null
71+
```
72+
73+
## Create remediation task
74+
75+
Use the following command to create a remediation task
76+
77+
```PowerShell
78+
79+
$RemediationName = "Remediate-LicenceType-SQLArc"
80+
$PolicyAssignmentName = "LicenceType-SQLArc-Assign"
81+
$SubId = "<your-subscription-id>"
82+
$RgName = "<your-resource-group>"
83+
84+
az account set --subscription $SubId
85+
86+
if ([string]::IsNullOrWhiteSpace($RgName)) {
87+
az policy remediation create `
88+
--name $RemediationName `
89+
--policy-assignment $PolicyAssignmentName `
90+
--resource-discovery-mode ReEvaluateCompliance `
91+
--only-show-errors | Out-Null
92+
} else {
93+
az policy remediation create `
94+
--name $RemediationName `
95+
--policy-assignment $PolicyAssignmentName `
96+
--resource-group "$RgName" `
97+
--resource-discovery-mode ReEvaluateCompliance `
98+
--only-show-errors | Out-Null
99+
}
100+
```
101+
102+
## Remove remediation task
103+
104+
```PowerShell
105+
106+
$RemediationName = "Remediate-LicenceType-SQLArc"
107+
$RgName = "<your-resource-group>"
108+
$SubId = "<your-subscription-id>"
109+
110+
if ([string]::IsNullOrWhiteSpace($RgName)) {
111+
az policy remediation cancel `
112+
--name $RemediationName `
113+
--subscription $SubId `
114+
--only-show-errors | Out-Null
115+
az policy remediation delete `
116+
--name $RemediationName `
117+
--subscription $SubId `
118+
--only-show-errors | Out-Null
119+
} else {
120+
az policy remediation cancel `
121+
--name $RemediationName `
122+
--resource-group $RgName `
123+
--subscription $SubId `
124+
--only-show-errors | Out-Null
125+
az policy remediation delete `
126+
--name $RemediationName `
127+
--resource-group $RgName `
128+
--subscription $SubId `
129+
--only-show-errors | Out-Null
130+
}
131+
```
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"effect": {
3+
"type": "String",
4+
"metadata": {
5+
"displayName": "Effect",
6+
"description": "Enable or disable the execution of the policy."
7+
},
8+
"allowedValues": [
9+
"DeployIfNotExists",
10+
"Disabled"
11+
],
12+
"defaultValue": "DeployIfNotExists"
13+
},
14+
"requiredLicenseType": {
15+
"type": "String",
16+
"metadata": {
17+
"displayName": "Required License Type",
18+
"description": "The license type that SQL Arc servers must have to be considered compliant."
19+
},
20+
"allowedValues": [
21+
"PAYG",
22+
"Paid",
23+
"LicenseOnly"
24+
],
25+
"defaultValue": "PAYG"
26+
}
27+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"properties": {
3+
"displayName": "LicenceType-SQLArc",
4+
"policyType": "Custom",
5+
"mode": "Indexed",
6+
"description": "Policy to ensure all SQL Arc servers have the required LicenseType. Servers that do not match are marked as non-compliant and remediated to the required license type.",
7+
"metadata": {
8+
"category": "SQLArc",
9+
"version": "1.0.0"
10+
},
11+
"parameters": "./params.json",
12+
"policyRule": "./rules.json"
13+
}
14+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
{
2+
"if": {
3+
"allOf": [
4+
{
5+
"equals": "Microsoft.HybridCompute/machines/extensions",
6+
"field": "type"
7+
},
8+
{
9+
"equals": "Microsoft.AzureData",
10+
"field": "Microsoft.HybridCompute/machines/extensions/publisher"
11+
},
12+
{
13+
"equals": "WindowsAgent.SqlServer",
14+
"field": "Microsoft.HybridCompute/machines/extensions/type"
15+
}
16+
]
17+
},
18+
"then": {
19+
"effect": "[parameters('effect')]",
20+
"details": {
21+
"type": "Microsoft.HybridCompute/machines/extensions",
22+
"roleDefinitionIds": [
23+
"/providers/Microsoft.Authorization/roleDefinitions/7392c568-9289-4bde-aaaa-b7131215889d",
24+
"/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7"
25+
],
26+
"name": "[field('fullName')]",
27+
"existenceCondition": {
28+
"equals": "[string(createObject('LicenseType', parameters('requiredLicenseType')))]",
29+
"value": "[string(intersection(if(empty(field('Microsoft.HybridCompute/machines/extensions/settings')), createObject(), field('Microsoft.HybridCompute/machines/extensions/settings')), createObject('LicenseType', parameters('requiredLicenseType'))))]"
30+
},
31+
"evaluationDelay": "AfterProvisioningSuccess",
32+
"deployment": {
33+
"properties": {
34+
"mode": "incremental",
35+
"template": {
36+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
37+
"contentVersion": "1.0.0.0",
38+
"parameters": {
39+
"extensionName": {
40+
"type": "string"
41+
},
42+
"vmLocation": {
43+
"type": "string"
44+
},
45+
"agentName": {
46+
"type": "string"
47+
},
48+
"existingSettings": {
49+
"type": "object"
50+
},
51+
"requiredLicenseType": {
52+
"type": "string"
53+
}
54+
},
55+
"variables": {
56+
"vmExtensionPublisher": "Microsoft.AzureData",
57+
"updatedSettings": {
58+
"LicenseType": "[parameters('requiredLicenseType')]"
59+
}
60+
},
61+
"resources": [
62+
{
63+
"name": "[parameters('extensionName')]",
64+
"type": "Microsoft.HybridCompute/machines/extensions",
65+
"location": "[parameters('vmLocation')]",
66+
"apiVersion": "2022-11-10",
67+
"properties": {
68+
"publisher": "[variables('vmExtensionPublisher')]",
69+
"type": "[parameters('agentName')]",
70+
"settings": "[union(parameters('existingSettings'), variables('updatedSettings'))]"
71+
}
72+
}
73+
]
74+
},
75+
"parameters": {
76+
"extensionName": {
77+
"value": "[field('fullName')]"
78+
},
79+
"vmLocation": {
80+
"value": "[field('location')]"
81+
},
82+
"agentName": {
83+
"value": "[field('name')]"
84+
},
85+
"existingSettings": {
86+
"value": "[field('Microsoft.HybridCompute/machines/extensions/settings')]"
87+
},
88+
"requiredLicenseType": {
89+
"value": "[parameters('requiredLicenseType')]"
90+
}
91+
}
92+
}
93+
}
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)