Skip to content

Commit 90195f1

Browse files
committed
Add custom Azure Policy for Arc SQL Server license type configuration
Add new DeployIfNotExists policy, deployment and remediation scripts, and documentation screenshots for enforcing LicenseType on Arc-enabled SQL Server extensions. New files: - policy/azurepolicy.json: custom policy definition - scripts/deployment.ps1: policy definition and assignment creation - scripts/start-remediation.ps1: remediation task with role checks - docs/screenshots/: visual references Updated README paths for sql-server-samples repo structure. Removed old flat policy files (params.json, policy.json, rules.json) replaced by the new structured layout.
1 parent b2b511c commit 90195f1

File tree

11 files changed

+608
-243
lines changed

11 files changed

+608
-243
lines changed
Lines changed: 95 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,120 @@
1-
# LicenseType-SQLArc
1+
# Arc-enabled SQL Server license type configuration with Azure Policy
22

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.
3+
This repo deploys and remediates a custom Azure Policy that configures and enforces Arc-enabled SQL Server extension `LicenseType` to a selected target value (for example `Paid` or `PAYG`).
44

5-
Use Azure CLI or PowerShell to create the policy definition.
5+
## What Is In This Repo
66

7-
## Artifacts
7+
- `policy/azurepolicy.json`: Custom policy definition (DeployIfNotExists).
8+
- `scripts/deployment.ps1`: Creates/updates the policy definition and policy assignment.
9+
- `scripts/start-remediation.ps1`: Starts a remediation task for the created assignment.
10+
- `docs/screenshots/`: Visual references.
811

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+
## Prerequisites
1213

13-
## Copy policy artifacts to your environment
14+
- PowerShell with Az modules installed (`Az.Resources`).
15+
- Logged in to Azure (`Connect-AzAccount`).
16+
- Permissions to create policy definitions/assignments and remediation tasks at target scope.
1417

15-
```PowerShell
18+
## Deploy Policy
1619

17-
curl https://raw.githubusercontent.com/microsoft/sql-server-samples/refs/heads/master/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-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-license-type-compliance/rules.json -o rules.json
20+
Parameter reference:
1921

20-
```
22+
| Parameter | Required | Default | Allowed values | Description |
23+
|---|---|---|---|---|
24+
| `ManagementGroupId` | Yes | N/A | Any valid management group ID | Scope where the policy definition is created. |
25+
| `ExtensionType` | No | `Both` | `Windows`, `Linux`, `Both` | Targets the Arc SQL extension platform. When `Both` (default), a single policy definition and assignment covers both platforms. When a specific type is selected, the naming and scope are tailored to that platform. |
26+
| `SubscriptionId` | No | Not set | Any valid subscription ID | If provided, policy assignment scope is the subscription. |
27+
| `TargetLicenseType` | Yes | N/A | `Paid`, `PAYG` | Target `LicenseType` value to enforce. |
28+
| `LicenseTypesToOverwrite` | No | All | `Unspecified`, `Paid`, `PAYG`, `LicenseOnly` | Select which current license states are eligible for update. Use `Unspecified` to include resources with no `LicenseType` configured. |
2129

22-
## Create policy
30+
Definition and assignment creation:
2331

24-
Use the following command to create policy
32+
1. Clone the repo.
2533

26-
```PowerShell
34+
```powershell
35+
git clone https://github.com/microsoft/sql-server-samples.git
36+
cd sql-server-samples/samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance
37+
```
2738

28-
$SubId = "<your-subscription-id>"
29-
$PolicyName = "LicenseType-SQLArc"
39+
2. Login to Azure.
3040

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
41+
```powershell
42+
Connect-AzAccount
4043
```
4144

42-
## Assign policy
45+
```powershell
46+
# Example: target both platforms (default)
47+
.\scripts\deployment.ps1 -ManagementGroupId "<management-group-id>" -SubscriptionId "<subscription-id>" -TargetLicenseType "PAYG" -LicenseTypesToOverwrite @("Paid")
4348
44-
Use the following command to assign policy
49+
# Example: target only Linux
50+
.\scripts\deployment.ps1 -ManagementGroupId "<management-group-id>" -ExtensionType "Linux" -SubscriptionId "<subscription-id>" -TargetLicenseType "PAYG" -LicenseTypesToOverwrite @("Paid")
51+
```
52+
The first example (without `-ExtensionType`) will:
53+
* Create/update a single policy definition and assignment covering **both** Windows and Linux.
54+
* Assign that policy at the specified subscription scope.
55+
* Enforce LicenseType = PAYG.
56+
* Update only resources where current `LicenseType` is `Paid`.
4557

46-
```PowerShell
58+
The second example creates a Linux-specific definition and assignment, with platform-tailored naming.
4759

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
60+
Scenario examples:
5261

53-
if ([string]::IsNullOrWhiteSpace($RgName)) {
54-
$Scope = "/subscriptions/$SubId"
55-
} else {
56-
$Scope = "/subscriptions/$SubId/resourceGroups/$RgName"
57-
}
62+
```powershell
63+
# Target Paid, both Linux and Windows, but only for resources with missing LicenseType or LicenseOnly (do not target PAYG)
64+
.\scripts\deployment.ps1 -ManagementGroupId "<management-group-id>" -TargetLicenseType "Paid" -LicenseTypesToOverwrite @("Unspecified","LicenseOnly")
5865
59-
az account set --subscription $SubId
66+
# Target PAYG, but only where current LicenseType is Paid (do not target missing or LicenseOnly)
67+
.\scripts\deployment.ps1 -ManagementGroupId "<management-group-id>" -ExtensionType "Linux" -TargetLicenseType "PAYG" -LicenseTypesToOverwrite @("Paid")
6068
61-
az policy assignment create `
62-
--name "LicenseType-SQLArc-Assign" `
63-
--policy "LicenseType-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
69+
# Overwrite all known existing LicenseType values (Paid, PAYG, LicenseOnly), but not missing
70+
.\scripts\deployment.ps1 -ManagementGroupId "<management-group-id>" -ExtensionType "Linux" -TargetLicenseType "Paid" -LicenseTypesToOverwrite @("Paid","PAYG","LicenseOnly")
7171
```
7272

73-
## Create remediation task
74-
75-
Use the following command to create a remediation task
76-
77-
```PowerShell
78-
79-
$RemediationName = "Remediate-LicenseType-SQLArc"
80-
$PolicyAssignmentName = "LicenseType-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-
```
73+
Note: `scripts/deployment.ps1` automatically grants required roles to the policy assignment managed identity at assignment scope, preventing common `PolicyAuthorizationFailed` errors during DeployIfNotExists deployments.
74+
75+
## Start Remediation
10176

102-
## Remove remediation task
103-
104-
```PowerShell
105-
106-
$RemediationName = "Remediate-LicenseType-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-
}
77+
Parameter reference:
78+
79+
| Parameter | Required | Default | Allowed values | Description |
80+
|---|---|---|---|---|
81+
| `ManagementGroupId` | Yes | N/A | Any valid management group ID | Used to resolve the policy definition/assignment naming context. |
82+
| `ExtensionType` | No | `Both` | `Windows`, `Linux`, `Both` | Must match the platform used for the assignment. When `Both` (default), remediates the combined assignment. |
83+
| `SubscriptionId` | No | Not set | Any valid subscription ID | If provided, remediation runs at subscription scope. |
84+
| `TargetLicenseType` | Yes | N/A | `Paid`, `PAYG` | Must match the assignment target license type. |
85+
| `GrantMissingPermissions` | No | `false` | Switch (`present`/`not present`) | If set, checks and assigns missing required roles before remediation. |
86+
87+
```powershell
88+
# Example: remediate both platforms (default)
89+
.\scripts\start-remediation.ps1 -ManagementGroupId "<management-group-id>" -SubscriptionId "<subscription-id>" -TargetLicenseType "PAYG" -GrantMissingPermissions
90+
91+
# Example: remediate only Linux
92+
.\scripts\start-remediation.ps1 -ManagementGroupId "<management-group-id>" -ExtensionType "Linux" -SubscriptionId "<subscription-id>" -TargetLicenseType "PAYG" -GrantMissingPermissions
13193
```
94+
95+
## Managed Identity And Roles
96+
97+
The policy assignment is created with `-IdentityType SystemAssigned`. Azure creates a managed identity on the assignment and uses it to apply DeployIfNotExists changes during enforcement and remediation.
98+
99+
Required roles:
100+
101+
- `Azure Extension for SQL Server Deployment` (`7392c568-9289-4bde-aaaa-b7131215889d`)
102+
- `Reader` (`acdd72a7-3385-48ef-bd42-f606fba81ae7`)
103+
- `Resource Policy Contributor` (required so DeployIfNotExists can create template deployments)
104+
105+
## Troubleshooting
106+
107+
If you see `PolicyAuthorizationFailed`, the policy assignment identity is missing one or more required roles at assignment scope (or inherited scope), often causing missing `Microsoft.HybridCompute/machines/extensions/write` permission.
108+
109+
Use one of these options:
110+
111+
- Re-run `scripts/deployment.ps1` (default behavior assigns `Resource Policy Contributor` automatically).
112+
- Re-run `scripts/deployment.ps1` (default behavior assigns required roles automatically).
113+
- Run `scripts/start-remediation.ps1 -GrantMissingPermissions` (checks and assigns missing required roles before remediation).
114+
115+
## Screenshots
116+
117+
![overview](./docs/screenshots/overview.png)
118+
![pre-policy](./docs/screenshots/pre-policy.png)
119+
![remediation](./docs/screenshots/remediation.png)
120+
![postpolicy](./docs/screenshots/post-policy.png)
173 KB
Loading
86.7 KB
Loading
86.5 KB
Loading
115 KB
Loading

samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/params.json

Lines changed: 0 additions & 27 deletions
This file was deleted.

samples/manage/azure-arc-enabled-sql-server/compliance/arc-sql-license-type-compliance/policy.json

Lines changed: 0 additions & 14 deletions
This file was deleted.

0 commit comments

Comments
 (0)