From 9dce51d6a119787436a149010c9095a45a2b2371 Mon Sep 17 00:00:00 2001 From: Bernie White Date: Sat, 2 Sep 2023 14:09:21 +1000 Subject: [PATCH] Fixed Azure.Storage.SecureTransfer #2414 --- docs/CHANGELOG-v1.md | 3 + docs/en/rules/Azure.Storage.SecureTransfer.md | 65 ++++++++++++------- docs/examples-storage.bicep | 10 +-- docs/examples-storage.json | 40 ++++++------ .../rules/Azure.Storage.Rule.yaml | 19 ++++-- .../Resources.Storage.Template.json | 3 +- 6 files changed, 83 insertions(+), 57 deletions(-) diff --git a/docs/CHANGELOG-v1.md b/docs/CHANGELOG-v1.md index df07e6deaad..9b43d39f232 100644 --- a/docs/CHANGELOG-v1.md +++ b/docs/CHANGELOG-v1.md @@ -29,6 +29,9 @@ What's changed since pre-release v1.30.0-B0047: - Engineering: - Bump Microsoft.NET.Test.Sdk to v17.7.2. [#2407](https://github.com/Azure/PSRule.Rules.Azure/pull/2407) +- Bug fixes: + - Fixed false positive with `Azure.Storage.SecureTransfer` on new API versions by @BernieWhite. + [#2414](https://github.com/Azure/PSRule.Rules.Azure/issues/2414) ## v1.30.0-B0047 (pre-release) diff --git a/docs/en/rules/Azure.Storage.SecureTransfer.md b/docs/en/rules/Azure.Storage.SecureTransfer.md index 8b540afe64e..ed19e4749b0 100644 --- a/docs/en/rules/Azure.Storage.SecureTransfer.md +++ b/docs/en/rules/Azure.Storage.SecureTransfer.md @@ -1,4 +1,5 @@ --- +reviewed: 2023-09-02 severity: Important pillar: Security category: Encryption @@ -23,6 +24,9 @@ To do this set the _Secure transfer required_ option. When _secure transfer required_ is enabled, attempts to connect to storage using HTTP or unencrypted SMB connections are rejected. +Storage Accounts that are deployed with a newer API version will have this option enabled by default. +However, this does not prevent the option from being disabled. + ## RECOMMENDATION Storage accounts should only accept secure traffic. @@ -35,28 +39,33 @@ Also consider using Azure Policy to audit or enforce this configuration. To deploy Storage Accounts that pass this rule: -- Set the `properties.supportsHttpsTrafficOnly` property to `true`. +- For API versions older then _2019-04-01_, set the `properties.supportsHttpsTrafficOnly` property to `true`. +- For API versions _2019-04-01_ and newer: + - Omit the `properties.supportsHttpsTrafficOnly` property OR + - Explicitly set the `properties.supportsHttpsTrafficOnly` property to `true`. For example: ```json { - "comments": "Storage Account", - "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2019-06-01", - "name": "st0000001", - "location": "[parameters('location')]", - "sku": { - "name": "Standard_GRS", - "tier": "Standard" - }, - "kind": "StorageV2", - "properties": { - "supportsHttpsTrafficOnly": true, - "minimumTlsVersion": "TLS1_2", - "allowBlobPublicAccess": false, - "accessTier": "Hot" + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2023-01-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "sku": { + "name": "Standard_GRS" + }, + "kind": "StorageV2", + "properties": { + "allowBlobPublicAccess": false, + "supportsHttpsTrafficOnly": true, + "minimumTlsVersion": "TLS1_2", + "accessTier": "Hot", + "allowSharedKeyAccess": false, + "networkAcls": { + "defaultAction": "Deny" } + } } ``` @@ -64,23 +73,30 @@ For example: To deploy Storage Accounts that pass this rule: -- Set the `properties.supportsHttpsTrafficOnly` property to `true`. +- For API versions older then _2019-04-01_, set the `properties.supportsHttpsTrafficOnly` property to `true`. +- For API versions _2019-04-01_ and newer: + - Omit the `properties.supportsHttpsTrafficOnly` property OR + - Explicitly set the `properties.supportsHttpsTrafficOnly` property to `true`. For example: ```bicep -resource st0000001 'Microsoft.Storage/storageAccounts@2021-04-01' = { - name: 'st0000001' +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { + name: name location: location sku: { name: 'Standard_GRS' } kind: 'StorageV2' properties: { - supportsHttpsTrafficOnly: true - accessTier: 'Hot' allowBlobPublicAccess: false + supportsHttpsTrafficOnly: true minimumTlsVersion: 'TLS1_2' + accessTier: 'Hot' + allowSharedKeyAccess: false + networkAcls: { + defaultAction: 'Deny' + } } } ``` @@ -88,6 +104,7 @@ resource st0000001 'Microsoft.Storage/storageAccounts@2021-04-01' = { ## LINKS - [Data encryption in Azure](https://learn.microsoft.com/azure/architecture/framework/security/design-storage-encryption#data-in-transit) -- [Require secure transfer in Azure Storage](https://docs.microsoft.com/azure/storage/common/storage-require-secure-transfer) -- [Sample policy for ensuring https traffic](https://docs.microsoft.com/azure/governance/policy/samples/ensure-https-stor-acct) -- [Azure deployment reference](https://docs.microsoft.com/azure/templates/microsoft.storage/storageaccounts) +- [Require secure transfer in Azure Storage](https://learn.microsoft.com/azure/storage/common/storage-require-secure-transfer) +- [DP-3: Encrypt sensitive data in transit](https://learn.microsoft.com/security/benchmark/azure/baselines/storage-security-baseline#dp-3-encrypt-sensitive-data-in-transit) +- [Sample policy for ensuring https traffic](https://learn.microsoft.com/azure/governance/policy/samples/built-in-policies#storage) +- [Azure deployment reference](https://learn.microsoft.com/azure/templates/microsoft.storage/storageaccounts) diff --git a/docs/examples-storage.bicep b/docs/examples-storage.bicep index 831310abb83..22a37ce62d6 100644 --- a/docs/examples-storage.bicep +++ b/docs/examples-storage.bicep @@ -16,7 +16,7 @@ var containerName = 'data' var shareName = 'group' // An example Storage Account -resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = { +resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = { name: name location: location sku: { @@ -36,7 +36,7 @@ resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = { } // Configure blob services -resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2021-06-01' = { +resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2023-01-01' = { parent: storageAccount name: 'default' properties: { @@ -52,7 +52,7 @@ resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2021-06-01' } // An example container -resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2021-06-01' = { +resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-01-01' = { parent: blobService name: containerName properties: { @@ -61,7 +61,7 @@ resource container 'Microsoft.Storage/storageAccounts/blobServices/containers@20 } // Configure file services -resource fileServices 'Microsoft.Storage/storageAccounts/fileServices@2021-06-01' = { +resource fileServices 'Microsoft.Storage/storageAccounts/fileServices@2023-01-01' = { parent: storageAccount name: 'default' properties: { @@ -72,7 +72,7 @@ resource fileServices 'Microsoft.Storage/storageAccounts/fileServices@2021-06-01 } } -resource share 'Microsoft.Storage/storageAccounts/fileServices/shares@2021-06-01' = { +resource share 'Microsoft.Storage/storageAccounts/fileServices/shares@2023-01-01' = { parent: fileServices name: shareName properties: { diff --git a/docs/examples-storage.json b/docs/examples-storage.json index d1f95fdb64d..48e0d53d5b9 100644 --- a/docs/examples-storage.json +++ b/docs/examples-storage.json @@ -1,11 +1,13 @@ { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "1.10-experimental", "contentVersion": "1.0.0.0", "metadata": { + "_EXPERIMENTAL_WARNING": "Symbolic name support in ARM is experimental, and should be enabled for testing purposes only. Do not enable this setting for any production usage, or you may be unexpectedly broken at any time!", "_generator": { "name": "bicep", - "version": "0.4.1124.51302", - "templateHash": "4901265845278602446" + "version": "0.20.4.51522", + "templateHash": "6814134128727565933" } }, "parameters": { @@ -27,10 +29,10 @@ "containerName": "data", "shareName": "group" }, - "resources": [ - { + "resources": { + "storageAccount": { "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2021-06-01", + "apiVersion": "2023-01-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "sku": { @@ -48,9 +50,9 @@ } } }, - { + "blobService": { "type": "Microsoft.Storage/storageAccounts/blobServices", - "apiVersion": "2021-06-01", + "apiVersion": "2023-01-01", "name": "[format('{0}/{1}', parameters('name'), 'default')]", "properties": { "deleteRetentionPolicy": { @@ -63,24 +65,23 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + "storageAccount" ] }, - { + "container": { "type": "Microsoft.Storage/storageAccounts/blobServices/containers", - "apiVersion": "2021-06-01", + "apiVersion": "2023-01-01", "name": "[format('{0}/{1}/{2}', parameters('name'), 'default', variables('containerName'))]", "properties": { "publicAccess": "None" }, "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/blobServices', parameters('name'), 'default')]", - "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + "blobService" ] }, - { + "fileServices": { "type": "Microsoft.Storage/storageAccounts/fileServices", - "apiVersion": "2021-06-01", + "apiVersion": "2023-01-01", "name": "[format('{0}/{1}', parameters('name'), 'default')]", "properties": { "shareDeleteRetentionPolicy": { @@ -89,20 +90,19 @@ } }, "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + "storageAccount" ] }, - { + "share": { "type": "Microsoft.Storage/storageAccounts/fileServices/shares", - "apiVersion": "2021-06-01", + "apiVersion": "2023-01-01", "name": "[format('{0}/{1}/{2}', parameters('name'), 'default', variables('shareName'))]", "properties": { "accessTier": "TransactionOptimized" }, "dependsOn": [ - "[resourceId('Microsoft.Storage/storageAccounts/fileServices', parameters('name'), 'default')]", - "[resourceId('Microsoft.Storage/storageAccounts', parameters('name'))]" + "fileServices" ] } - ] + } } \ No newline at end of file diff --git a/src/PSRule.Rules.Azure/rules/Azure.Storage.Rule.yaml b/src/PSRule.Rules.Azure/rules/Azure.Storage.Rule.yaml index e4f3cddd48d..0294803d786 100644 --- a/src/PSRule.Rules.Azure/rules/Azure.Storage.Rule.yaml +++ b/src/PSRule.Rules.Azure/rules/Azure.Storage.Rule.yaml @@ -54,17 +54,24 @@ metadata: name: Azure.Storage.SecureTransfer ref: AZR-000196 tags: - release: 'GA' - ruleSet: '2020_06' - Azure.WAF/pillar: 'Security' + release: GA + ruleSet: 2020_06 + Azure.WAF/pillar: Security labels: - Azure.MCSB.v1/control: 'DP-3' + Azure.MCSB.v1/control: DP-3 spec: type: - Microsoft.Storage/storageAccounts condition: - field: properties.supportsHttpsTrafficOnly - equals: true + anyOf: + - allOf: + - field: apiVersion + apiVersion: '>=2019-04-01' + - field: properties.supportsHttpsTrafficOnly + hasDefault: true + - allOf: + - field: properties.supportsHttpsTrafficOnly + equals: true --- # Synopsis: Disallow blob containers with public access types. diff --git a/tests/PSRule.Rules.Azure.Tests/Resources.Storage.Template.json b/tests/PSRule.Rules.Azure.Tests/Resources.Storage.Template.json index 8459d70acf0..50b7f741fff 100644 --- a/tests/PSRule.Rules.Azure.Tests/Resources.Storage.Template.json +++ b/tests/PSRule.Rules.Azure.Tests/Resources.Storage.Template.json @@ -99,7 +99,7 @@ { "comments": "Storage Account", "type": "Microsoft.Storage/storageAccounts", - "apiVersion": "2019-06-01", + "apiVersion": "2022-09-01", "name": "[parameters('storageAccountName')]", "location": "[parameters('location')]", "sku": { @@ -116,7 +116,6 @@ ], "defaultAction": "Deny" }, - "supportsHttpsTrafficOnly": true, "encryption": { "services": { "file": {