Skip to content

Commit

Permalink
Fixed selector for indexed Azure policies #2401 (#2402)
Browse files Browse the repository at this point in the history
* Fixed selector for indexed Azure policies #2401

* Update tests

* Updtae change log
  • Loading branch information
BernieWhite authored Aug 25, 2023
1 parent a15675b commit 92e6d30
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 18 deletions.
15 changes: 10 additions & 5 deletions docs/CHANGELOG-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers

## Unreleased

What's changed since pre-release v1.30.0-B0011:

- New rules:
- Azure Container Apps:
- Check that Container Apps uses a supported API version by @BenjaminEngeset.
[#2398](https://github.com/Azure/PSRule.Rules.Azure/issues/2398)
[#2398](https://github.com/Azure/PSRule.Rules.Azure/issues/2398)
- Bug fixes:
- Fixed non-resource group rule triggering for a resource group by @BernieWhite.
[#2401](https://github.com/Azure/PSRule.Rules.Azure/issues/2401)

## v1.30.0-B0011 (pre-release)

Expand All @@ -36,13 +41,13 @@ What's changed since v1.29.0:
- New rules:
- Azure Database for MySQL:
- Check that Azure AD-only authentication is configured for Azure Database for MySQL databases by @BenjaminEngeset.
[#2227](https://github.com/Azure/PSRule.Rules.Azure/issues/2227)
[#2227](https://github.com/Azure/PSRule.Rules.Azure/issues/2227)
- Azure Firewall:
- Check that Azure Firewall polices has configured threat intelligence-based filtering in `alert and deny` mode by @BenjaminEngeset.
[#2354](https://github.com/Azure/PSRule.Rules.Azure/issues/2354)
[#2354](https://github.com/Azure/PSRule.Rules.Azure/issues/2354)
- Backup vault:
- Check that immutability is configured for Backup vaults by @BenjaminEngeset.
[#2387](https://github.com/Azure/PSRule.Rules.Azure/issues/2387)
[#2387](https://github.com/Azure/PSRule.Rules.Azure/issues/2387)
- Front Door:
- Check that managed identity for Azure Front Door instances are configured by @BenjaminEngeset.
[#2378](https://github.com/Azure/PSRule.Rules.Azure/issues/2378)
Expand All @@ -51,7 +56,7 @@ What's changed since v1.29.0:
[#2376](https://github.com/Azure/PSRule.Rules.Azure/issues/2376)
- Recovery Services vault:
- Check that immutability is configured for Recovery Services vaults by @BenjaminEngeset.
[#2386](https://github.com/Azure/PSRule.Rules.Azure/issues/2386)
[#2386](https://github.com/Azure/PSRule.Rules.Azure/issues/2386)
- Engineering:
- Bump BenchmarkDotNet to v0.13.7.
[#2385](https://github.com/Azure/PSRule.Rules.Azure/pull/2385)
Expand Down
7 changes: 3 additions & 4 deletions src/PSRule.Rules.Azure/Data/Policy/PolicyAssignmentVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1354,10 +1354,9 @@ private static string GetPolicyRuleHash(string definitionId, JObject condition,

private static void AddSelectors(PolicyDefinition policyDefinition, PolicyMode policyMode)
{
if (policyMode != PolicyMode.Indexed)
return;

policyDefinition.With = new string[] { "PSRule.Rules.Azure\\Azure.Resource.SupportsTags" };
policyDefinition.With = policyMode == PolicyMode.Indexed
? new string[] { "PSRule.Rules.Azure\\Azure.Policy.Indexed" }
: new string[] { "PSRule.Rules.Azure\\Azure.Policy.All" };
}

private static void OptimizeConditions(PolicyDefinition policyDefinition)
Expand Down
142 changes: 142 additions & 0 deletions src/PSRule.Rules.Azure/rules/Common.Selector.Rule.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,148 @@ spec:
- Microsoft.Automation/automationAccounts/watchers
- Microsoft.Resources/templateSpecs/versions

---
# Synopsis: Resources that supports tags but not resource groups.
apiVersion: github.com/microsoft/PSRule/v1
kind: Selector
metadata:
name: Azure.Policy.Indexed
annotations:
export: false
spec:
if:
allOf:

- type: '.'
notIn:
- Microsoft.Resources/resourceGroups
- Microsoft.Resources/subscriptions/resourceGroups

# Only include resource types
- type: '.'
like: 'Microsoft.*/*'

# Exclude resource providers that do not support tags
- type: '.'
notStartsWith:
- Microsoft.Addons/
- Microsoft.Advisor/
- Microsoft.Billing/
- Microsoft.Blueprint/
- Microsoft.Capacity/
- Microsoft.Classic
- Microsoft.Consumption/
- Microsoft.Gallery/
- Microsoft.Security/
- microsoft.support/
- Microsoft.WorkloadMonitor/
- Microsoft.ManagedServices/
- Microsoft.Management/
- Microsoft.PolicyInsights/

# Exclude resource types that do not support tags
- type: '.'
notIn:
- Microsoft.Subscription
- Microsoft.AzureActiveDirectory/b2ctenants
- Microsoft.OperationsManagement/solutions
- Microsoft.Kubernetes/registeredSubscriptions
- Microsoft.Network/privateDnsZonesInternal
- type: '.'
notEndsWith:
- /providers/roleAssignments
- /providers/diagnosticSettings

# Specific exception cases
- anyOf:
- type: '.'
notStartsWith: Microsoft.Resources/
- type: '.'
in:
- Microsoft.Resources/deploymentScripts
# - Microsoft.Resources/resourceGroups
- Microsoft.Resources/templateSpecs
- Microsoft.Resources/templateSpecs/versions

- anyOf:
- type: '.'
notStartsWith: Microsoft.CostManagement/
- type: '.'
in:
- Microsoft.CostManagement/Connectors

- anyOf:
- type: '.'
notStartsWith: Microsoft.KubernetesConfiguration/
- type: '.'
in:
- Microsoft.KubernetesConfiguration/privateLinkScopes

- anyOf:
- type: '.'
notStartsWith: Microsoft.ManagedIdentity/
- type: '.'
in:
- Microsoft.ManagedIdentity/userAssignedIdentities

- anyOf:
- type: '.'
notStartsWith: Microsoft.Authorization/
- type: '.'
in:
- Microsoft.Authorization/resourceManagementPrivateLinks

- anyOf:
- type: '.'
notStartsWith: Microsoft.Insights/
- type: '.'
in:
- Microsoft.Insights/actionGroups
- Microsoft.Insights/activityLogAlerts
- Microsoft.Insights/alertRules
- Microsoft.Insights/autoscaleSettings
- Microsoft.Insights/components
- Microsoft.Insights/dataCollectionEndpoints
- Microsoft.Insights/dataCollectionRules
- Microsoft.Insights/guestDiagnosticSettings
- Microsoft.Insights/metricAlerts
- Microsoft.Insights/notificationGroups
- Microsoft.Insights/privateLinkScopes
- Microsoft.Insights/scheduledQueryRules
- Microsoft.Insights/webTests
- Microsoft.Insights/workbooks
- Microsoft.Insights/workbookTemplates

- anyOf:
- type: '.'
notLike: 'Microsoft.*/*/*'
- type: '.'
in:
- Microsoft.Automation/automationAccounts/runbooks
- Microsoft.Automation/automationAccounts/configurations
- Microsoft.Automation/automationAccounts/compilationJobs
- Microsoft.Automation/automationAccounts/modules
- Microsoft.Automation/automationAccounts/nodeConfigurations
- Microsoft.Automation/automationAccounts/python2Packages
- Microsoft.Automation/automationAccounts/watchers
- Microsoft.Resources/templateSpecs/versions

---
# Synopsis: Any Azure resource type.
apiVersion: github.com/microsoft/PSRule/v1
kind: Selector
metadata:
name: Azure.Policy.All
annotations:
export: false
spec:
if:
allOf:

# Only include resource types
- type: '.'
like: 'Microsoft.*/*'

---
# Synopsis: Identities resources that have been exported from an Azure subscription.
apiVersion: github.com/microsoft/PSRule/v1
Expand Down
10 changes: 5 additions & 5 deletions tests/PSRule.Rules.Azure.Tests/PolicyAssignmentVisitorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void GetPolicyDefinition()
Assert.Equal("Microsoft.Storage/storageAccounts", actual.Types[0]);
Assert.Null(actual.Where);
Assert.Equal("{\"field\":\"properties.networkAcls.defaultAction\",\"equals\":\"Deny\"}", actual.Condition.ToString(Formatting.None));
Assert.Equal(new string[] { "PSRule.Rules.Azure\\Azure.Resource.SupportsTags" }, actual.With);
Assert.Equal(new string[] { "PSRule.Rules.Azure\\Azure.Policy.Indexed" }, actual.With);

actual = definitions.FirstOrDefault(definition => definition.DefinitionId == "/providers/Microsoft.Authorization/policyDefinitions/04c4380f-3fae-46e8-96c9-30193528f602");
Assert.NotNull(actual);
Expand All @@ -57,7 +57,7 @@ public void GetPolicyDefinition()
Assert.Single(actual.Types);
Assert.Equal("Microsoft.Compute/virtualMachines", actual.Types[0]);
Assert.Equal("{\"anyOf\":[{\"allOf\":[{\"field\":\"properties.storageProfile.imageReference.publisher\",\"equals\":\"Canonical\"},{\"field\":\"properties.storageProfile.imageReference.offer\",\"equals\":\"UbuntuServer\"},{\"anyOf\":[{\"field\":\"properties.storageProfile.imageReference.sku\",\"in\":[\"18.04-LTS\",\"16.04-LTS\",\"16.04.0-LTS\",\"14.04.0-LTS\",\"14.04.1-LTS\",\"14.04.5-LTS\"]}]}]},{\"allOf\":[{\"field\":\"properties.storageProfile.imageReference.publisher\",\"equals\":\"RedHat\"},{\"field\":\"properties.storageProfile.imageReference.offer\",\"in\":[\"RHEL\",\"RHEL-SAP-HANA\"]},{\"anyOf\":[{\"field\":\"properties.storageProfile.imageReference.sku\",\"like\":\"6.*\"},{\"field\":\"properties.storageProfile.imageReference.sku\",\"like\":\"7*\"}]}]},{\"allOf\":[{\"field\":\"properties.storageProfile.imageReference.publisher\",\"equals\":\"SUSE\"},{\"field\":\"properties.storageProfile.imageReference.offer\",\"in\":[\"SLES\",\"SLES-HPC\",\"SLES-HPC-Priority\",\"SLES-SAP\",\"SLES-SAP-BYOS\",\"SLES-Priority\",\"SLES-BYOS\",\"SLES-SAPCAL\",\"SLES-Standard\"]},{\"field\":\"properties.storageProfile.imageReference.sku\",\"in\":[\"12-SP2\",\"12-SP3\",\"12-SP4\"]}]},{\"allOf\":[{\"field\":\"properties.storageProfile.imageReference.publisher\",\"equals\":\"OpenLogic\"},{\"field\":\"properties.storageProfile.imageReference.offer\",\"in\":[\"CentOS\",\"Centos-LVM\",\"CentOS-SRIOV\"]},{\"anyOf\":[{\"field\":\"properties.storageProfile.imageReference.sku\",\"like\":\"6.*\"},{\"field\":\"properties.storageProfile.imageReference.sku\",\"like\":\"7*\"}]}]},{\"allOf\":[{\"field\":\"properties.storageProfile.imageReference.publisher\",\"equals\":\"cloudera\"},{\"field\":\"properties.storageProfile.imageReference.offer\",\"equals\":\"cloudera-centos-os\"},{\"field\":\"properties.storageProfile.imageReference.sku\",\"like\":\"7*\"}]}]}", actual.Where.ToString(Formatting.None));
Assert.Equal(new string[] { "PSRule.Rules.Azure\\Azure.Resource.SupportsTags" }, actual.With);
Assert.Equal(new string[] { "PSRule.Rules.Azure\\Azure.Policy.Indexed" }, actual.With);

actual = definitions.FirstOrDefault(definition => definition.DefinitionId == "/providers/Microsoft.Authorization/policyDefinitions/f9be5368-9bf5-4b84-9e0a-7850da98bb46");
Assert.NotNull(actual);
Expand All @@ -68,7 +68,7 @@ public void GetPolicyDefinition()
Assert.Equal("Microsoft.StreamAnalytics/streamingJobs", actual.Types[0]);
var condition = actual.Condition.ToString(Formatting.None);
Assert.Equal("{\"field\":\"resources\",\"allOf\":[{\"greaterOrEqual\":1,\"field\":\"properties.logs[*]\",\"anyOf\":[{\"allOf\":[{\"field\":\"retentionPolicy.enabled\",\"equals\":\"true\"},{\"anyOf\":[{\"field\":\"retentionPolicy.days\",\"equals\":\"0\"},{\"value\":{\"$\":{\"padLeft\":{\"path\":\"retentionPolicy.days\"},\"totalLength\":3,\"paddingCharacter\":\"0\"}},\"greaterOrEquals\":365,\"convert\":true}]},{\"field\":\"enabled\",\"equals\":\"true\"}]},{\"allOf\":[{\"field\":\"enabled\",\"equals\":\"true\"},{\"anyOf\":[{\"field\":\"retentionPolicy.enabled\",\"notEquals\":\"true\"},{\"field\":\"properties.storageAccountId\",\"exists\":false}]}]}]}],\"where\":{\"type\":\".\",\"equals\":\"Microsoft.Insights/diagnosticSettings\"}}", actual.Condition.ToString(Formatting.None));
Assert.Equal(new string[] { "PSRule.Rules.Azure\\Azure.Resource.SupportsTags" }, actual.With);
Assert.Equal(new string[] { "PSRule.Rules.Azure\\Azure.Policy.Indexed" }, actual.With);
}

[Fact]
Expand Down Expand Up @@ -160,7 +160,7 @@ public void GetResourceGroupLocation()
Assert.Equal("Microsoft.Resources/resourceGroups", actual.Types[0]);
Assert.Null(actual.Where);
Assert.Equal("{\"field\":\"location\",\"in\":[\"australiaeast\",\"australiasoutheast\",\"eastus\",\"westus\"]}", actual.Condition.ToString(Formatting.None));
Assert.Null(actual.With);
Assert.Equal(new string[] { "PSRule.Rules.Azure\\Azure.Policy.All" }, actual.With);
}

[Fact]
Expand All @@ -186,7 +186,7 @@ public void GetFieldConcat()
Assert.Equal("Microsoft.Resources/resourceGroups", actual.Types[0]);
Assert.Null(actual.Where);
Assert.Equal("{\"field\":\"tags['env']\",\"exists\":true}", actual.Condition.ToString(Formatting.None));
Assert.Null(actual.With);
Assert.Equal(new string[] { "PSRule.Rules.Azure\\Azure.Policy.All" }, actual.With);
}

#region Helper methods
Expand Down
30 changes: 27 additions & 3 deletions tests/PSRule.Rules.Azure.Tests/emittedJsonRulesData.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"Microsoft.Storage/storageAccounts"
],
"with": [
"PSRule.Rules.Azure\\Azure.Resource.SupportsTags"
"PSRule.Rules.Azure\\Azure.Policy.Indexed"
],
"condition": {
"field": "properties.minimumTlsVersion",
Expand Down Expand Up @@ -49,7 +49,7 @@
"Microsoft.Compute/virtualMachines"
],
"with": [
"PSRule.Rules.Azure\\Azure.Resource.SupportsTags"
"PSRule.Rules.Azure\\Azure.Policy.Indexed"
],
"where": {
"anyOf": [
Expand Down Expand Up @@ -348,7 +348,7 @@
"Microsoft.Web/sites"
],
"with": [
"PSRule.Rules.Azure\\Azure.Resource.SupportsTags"
"PSRule.Rules.Azure\\Azure.Policy.Indexed"
],
"where": {
"field": "kind",
Expand Down Expand Up @@ -401,6 +401,9 @@
"type": [
"Microsoft.Network/loadBalancers"
],
"with": [
"PSRule.Rules.Azure\\Azure.Policy.All"
],
"condition": {
"greaterOrEqual": 1,
"field": "properties.loadBalancingRules[*]",
Expand Down Expand Up @@ -429,6 +432,9 @@
"type": [
"Microsoft.Network/loadBalancers"
],
"with": [
"PSRule.Rules.Azure\\Azure.Policy.All"
],
"condition": {
"greaterOrEquals": 1,
"field": "properties.loadBalancingRules[*]",
Expand All @@ -452,6 +458,9 @@
"type": [
"Microsoft.Network/networkSecurityGroups"
],
"with": [
"PSRule.Rules.Azure\\Azure.Policy.All"
],
"condition": {
"count": 1,
"field": "properties.securityRules[*]",
Expand Down Expand Up @@ -480,6 +489,9 @@
"type": [
"Microsoft.Network/networkSecurityGroups/securityRules"
],
"with": [
"PSRule.Rules.Azure\\Azure.Policy.All"
],
"condition": {
"greater": 0,
"field": "properties.securityRules[*]",
Expand Down Expand Up @@ -517,6 +529,9 @@
"Microsoft.Network/networkSecurityGroups/securityRules",
"Microsoft.Network/networkSecurityGroups"
],
"with": [
"PSRule.Rules.Azure\\Azure.Policy.All"
],
"where": {
"anyOf": [
{
Expand Down Expand Up @@ -600,6 +615,9 @@
"Microsoft.Network/virtualNetworks/subnets",
"Microsoft.Network/virtualNetworks"
],
"with": [
"PSRule.Rules.Azure\\Azure.Policy.All"
],
"where": {
"anyOf": [
{
Expand Down Expand Up @@ -670,6 +688,9 @@
"type": [
"Microsoft.Network/privateEndpoints"
],
"with": [
"PSRule.Rules.Azure\\Azure.Policy.All"
],
"where": {
"allOf": [
{
Expand Down Expand Up @@ -717,6 +738,9 @@
"type": [
"Microsoft.Resources/subscriptions"
],
"with": [
"PSRule.Rules.Azure\\Azure.Policy.All"
],
"condition": {
"value": "Manual",
"equals": false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"spec": {
"recommend": "This policy enables you to restrict the locations your organization can specify when deploying resources. Use to enforce your geo-compliance requirements. Excludes resource groups, Microsoft.AzureActiveDirectory/b2cDirectories, and resources that use the 'global' region.",
"with": [
"PSRule.Rules.Azure\\Azure.Resource.SupportsTags"
"PSRule.Rules.Azure\\Azure.Policy.Indexed"
],
"where": {
"allOf": [
Expand Down

0 comments on commit 92e6d30

Please sign in to comment.