From 5977082f600141988e5e0a07c361b8ceccc8fe6b Mon Sep 17 00:00:00 2001 From: Benjamin Engeset <99641908+BenjaminEngeset@users.noreply.github.com> Date: Sat, 23 Sep 2023 03:34:51 +0200 Subject: [PATCH] feat(new): Added Azure.ACR.AnonymousAccess (#2433) * feat(new): Added Azure.ACR.AnonymousAccess * Added security baseline * Bump selector --------- Co-authored-by: Bernie White --- docs/CHANGELOG-v1.md | 5 + docs/en/rules/Azure.ACR.AnonymousAccess.md | 92 +++++++++++++++++++ .../rules/Azure.ACR.Rule.yaml | 38 ++++++++ .../Azure.ACR.Tests.ps1 | 20 ++++ .../Resources.ACR.json | 2 + 5 files changed, 157 insertions(+) create mode 100644 docs/en/rules/Azure.ACR.AnonymousAccess.md diff --git a/docs/CHANGELOG-v1.md b/docs/CHANGELOG-v1.md index 80cf50e026..f944065e57 100644 --- a/docs/CHANGELOG-v1.md +++ b/docs/CHANGELOG-v1.md @@ -28,6 +28,11 @@ See [upgrade notes][1] for helpful information when upgrading from previous vers ## Unreleased +- New rules: + - Azure Container Registry: + - Check that Container Registries disables anonymous pull access by @BenjaminEngeset. + [#2422](https://github.com/Azure/PSRule.Rules.Azure/issues/2422) + ## v1.30.0-B0080 (pre-release) What's changed since pre-release v1.30.0-B0047: diff --git a/docs/en/rules/Azure.ACR.AnonymousAccess.md b/docs/en/rules/Azure.ACR.AnonymousAccess.md new file mode 100644 index 0000000000..83b998fe23 --- /dev/null +++ b/docs/en/rules/Azure.ACR.AnonymousAccess.md @@ -0,0 +1,92 @@ +--- +severity: Important +pillar: Security +category: Identity and access management +resource: Container Registry +online version: https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.ACR.AnonymousAccess/ +--- + +# Anonymous pull access + +## SYNOPSIS + +Disable anonymous pull access. + +## DESCRIPTION + +Azure Container Registry (ACR) allows you to pull or push content from an Azure container registry by being authenticated. +However, it is possible to pull content from an Azure container registry by being unauthenticated (anonymous pull access). + +By default, access to pull or push content from an Azure container registry is only available to authenticated users. + +Generally speaking it is not a good practice to allow data-plane operations to unauthenticated users. +However, anonymous pull access can be used in scenarios that do not require user authentication such as distributing public container images. + +## RECOMMENDATION + +Consider disabling anonymous pull access in scenarios that require user authentication. + +## EXAMPLES + +### Configure with Azure template + +To deploy Azure Container Registries that pass this rule: + +- Set the `properties.anonymousPullEnabled` property to `false`. + +For example: + +```json +{ + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-01-01-preview", + "name": "[parameters('registryName')]", + "location": "[parameters('location')]", + "sku": { + "name": "Standard" + }, + "properties": { + "anonymousPullEnabled": false + } +} +``` + +### Configure with Bicep + +To deploy Azure Container Registries that pass this rule: + +- Set the `properties.anonymousPullEnabled` property to `false`. + +For example: + +```bicep +resource acr 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' = { + name: registryName + location: location + sku: { + name: 'Standard' + } + properties: { + anonymousPullEnabled: false + } +} +``` + +### Configure with Azure CLI + +```bash +az acr update --name myregistry --anonymous-pull-enabled false +``` + +## NOTES + +The anonymous pull access feature is currently in preview. +Anonymous pull access is only available in the `Standard` and `Premium` service tiers. + +## LINKS + +- [Authentication with Azure AD](https://learn.microsoft.com/azure/well-architected/security/design-identity-authentication) +- [Make your container registry content publicly available](https://learn.microsoft.com/azure/container-registry/anonymous-pull-access) +- [Azure security baseline for Container Registry](https://learn.microsoft.com/security/benchmark/azure/baselines/container-registry-security-baseline) +- [IM-1: Use centralized identity and authentication system](https://learn.microsoft.com/security/benchmark/azure/baselines/container-registry-security-baseline#im-1-use-centralized-identity-and-authentication-system) +- [Azure deployment reference](https://learn.microsoft.com/en-us/azure/templates/microsoft.containerregistry/registries#registryproperties) diff --git a/src/PSRule.Rules.Azure/rules/Azure.ACR.Rule.yaml b/src/PSRule.Rules.Azure/rules/Azure.ACR.Rule.yaml index e165888639..6101847931 100644 --- a/src/PSRule.Rules.Azure/rules/Azure.ACR.Rule.yaml +++ b/src/PSRule.Rules.Azure/rules/Azure.ACR.Rule.yaml @@ -131,6 +131,27 @@ spec: field: properties.policies.retentionPolicy.status equals: enabled +--- +# Synopsis: Disable anonymous pull access. +apiVersion: github.com/microsoft/PSRule/v1 +kind: Rule +metadata: + name: Azure.ACR.AnonymousAccess + ref: AZR-000401 + tags: + release: preview + ruleSet: 2023_09 + Azure.WAF/pillar: Security + labels: + Azure.MCSB.v1/control: 'IM-1' +spec: + with: + - Azure.ACR.IsPremiumSKU + - Azure.ACR.IsStandardSKU + condition: + field: properties.anonymousPullEnabled + hasDefault: false + #endregion Rules #region Selectors @@ -152,4 +173,21 @@ spec: - field: sku.tier equals: Premium +--- +# Synopsis: Azure Container Registries using a Standard SKU. +apiVersion: github.com/microsoft/PSRule/v1 +kind: Selector +metadata: + name: Azure.ACR.IsStandardSKU +spec: + if: + allOf: + - type: '.' + equals: Microsoft.ContainerRegistry/registries + - anyOf: + - field: sku.name + equals: Standard + - field: sku.tier + equals: Standard + #endregion Selectors diff --git a/tests/PSRule.Rules.Azure.Tests/Azure.ACR.Tests.ps1 b/tests/PSRule.Rules.Azure.Tests/Azure.ACR.Tests.ps1 index 4592c6b332..0537ca4d81 100644 --- a/tests/PSRule.Rules.Azure.Tests/Azure.ACR.Tests.ps1 +++ b/tests/PSRule.Rules.Azure.Tests/Azure.ACR.Tests.ps1 @@ -238,6 +238,26 @@ Describe 'Azure.ACR' -Tag 'ACR' { $ruleResult.Length | Should -Be 3; $ruleResult.TargetName | Should -BeIn 'registry-G', 'registry-I', 'registry-J'; } + + It 'Azure.ACR.AnonymousAccess' { + $filteredResult = $result | Where-Object { $_.RuleName -eq 'Azure.ACR.AnonymousAccess' }; + + # Fail + $ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Fail' }); + $ruleResult.Length | Should -Be 1; + $ruleResult.TargetName | Should -BeIn 'registry-B'; + $ruleResult.Detail.Reason.Path | Should -BeIn 'properties.anonymousPullEnabled'; + + # Pass + $ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'Pass' }); + $ruleResult.Length | Should -Be 8; + $ruleResult.TargetName | Should -BeIn 'registry-C', 'registry-D', 'registry-E', 'registry-F', 'registry-G', 'registry-H', 'registry-I', 'registry-J'; + + # None + $ruleResult = @($filteredResult | Where-Object { $_.Outcome -eq 'None' }); + $ruleResult.Length | Should -Be 1; + $ruleResult.TargetName | Should -BeIn 'registry-A'; + } } Context 'Resource name' { diff --git a/tests/PSRule.Rules.Azure.Tests/Resources.ACR.json b/tests/PSRule.Rules.Azure.Tests/Resources.ACR.json index e334d45df4..3adf872ac1 100644 --- a/tests/PSRule.Rules.Azure.Tests/Resources.ACR.json +++ b/tests/PSRule.Rules.Azure.Tests/Resources.ACR.json @@ -31,6 +31,7 @@ "Name": "registry-B", "Properties": { "loginServer": "registry-B.azurecr.io", + "anonymousPullEnabled": true, "adminUserEnabled": false, "policies": { "quarantinePolicy": { @@ -187,6 +188,7 @@ "ResourceName": "registry-C", "Name": "registry-C", "Properties": { + "anonymousPullEnabled": false, "loginServer": "registry-C.azurecr.io", "policies": { "quarantinePolicy": {