Azure / arm-template-whatif

A repository to track issues related to what-if noise suppression
MIT License
90 stars 14 forks source link

Noise on What-If when deploying Functions App Infrastructure with Azure Key Vault #215

Open neerajsubramaniyan opened 3 years ago

neerajsubramaniyan commented 3 years ago

Describe the noise

Resource type

Microsoft.KeyVault/vaults Microsoft.Web/serverfarms Microsoft.Web/sites

apiVersion (i.e. 2019-04-01)

Microsoft.KeyVault/vaults : 2018-02-14] Microsoft.Web/serverfarms : 2020-06-01 Microsoft.Web/sites/ : 2020-06-01

Client (PowerShell, Azure CLI, or API)

Azure CLI

Relevant ARM Template code

Click to expand to see full deployable arm template. To deploy, just set the default value of the parameter appName

```json { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "appName": { "type": "string", "defaultValue": "abcd" }, "environment": { "type": "string", "defaultValue": "test", "allowedValues": [ "test", "stg", "prod" ], "metadata": { "description": "Deploy environment. Will be used to name resources. dev/test/prod" } }, "location": { "type": "string", "defaultValue": "westus2", "metadata": { "description": "Location for resource(s)" } }, "tenantId": { "type": "string", "metadata": { "description": "Company TenantId" } }, "tags": { "type": "object", "defaultValue": { "cost-center": "1234" }, "metadata": { "description": "Resource tags" } }, "storageAccountName": { "type": "string", "defaultValue": "[toLower(concat(parameters('appName'), 'storageaccount', parameters('environment'), parameters('location')))]", "minLength": 3, "maxLength": 24, "metadata": { "description": "Storage account names must be between 3 and 24 characters in length and may contain numbers and lowercase letters only" } }, "storageAccountSku": { "defaultValue": "Standard_RAGRS", "type": "string", "allowedValues": [ "Standard_LRS", "Standard_GRS", "Standard_RAGRS", "Standard_ZRS", "Premium_LRS", "Premium_ZRS", "Standard_GZRS", "Standard_RAGZRS" ], "metadata": { "description": "Storage Account type (SKU)" } }, "storageAccountKind": { "type": "string", "defaultValue": "StorageV2", "allowedValues": [ "Storage", "StorageV2", "BlobStorage", "FileStorage", "BlockBlobStorage" ], "metadata": { "description": "Storage Account kind" } }, "storageAccountAccessTier": { "type": "string", "defaultValue": "Hot", "allowedValues": [ "Hot", "Cool" ], "metadata": { "description": "Storage Account Access Tier" } }, "storageAccountMinTlsVersion": { "type": "string", "defaultValue": "TLS1_2", "allowedValues": [ "TLS1_0", "TLS1_1", "TLS1_2" ], "metadata": { "description": "minimum TLS version on requests to storage" } }, "storageAccountHttpsOnly": { "type": "bool", "defaultValue": true, "metadata": { "description": "Allow https traffic only to storage service" } }, "storageAccountPublicAccess": { "type": "bool", "defaultValue": false, "metadata": { "description": "Allow or disallow public access to storage account" } }, "storageAccountAllowSharedKeyAccess": { "type": "bool", "defaultValue": true, "metadata": { "description": "Allow requests to be authorized with the account access key via Shared Key" } }, "storageAccountNetworkAclsBypass": { "type": "string", "defaultValue": "AzureServices", "metadata": { "description": "Specifies whether traffic is bypassed for Logging/Metrics/AzureServices. Possible values are any combination of Logging, Metrics, AzureServices" } }, "storageAccountNetworkAclsDefaultAction": { "type": "string", "defaultValue": "Allow", "allowedValues": [ "Allow", "Deny" ], "metadata": { "description": "Specifies the default action of allow or deny when no other rules match. - Allow or Deny" } }, "storageAccountIsContainerRestoreEnabled": { "type": "bool", "defaultValue": false, "metadata": { "description": "Enable point in time restore for containers. If true, versioning must be enabled" } }, "storageAccountIsBlobSoftDeleteEnabled": { "type": "bool", "defaultValue": true, "metadata": { "description": "Enable soft delete for blobs." } }, "storageAccountBlobSoftDeleteRetentionDays": { "type": "int", "defaultValue": 7, "metadata": { "description": "Keep deleted blobs for (in days)" } }, "storageAccountIsContainerSoftDeleteEnabled": { "type": "bool", "defaultValue": true, "metadata": { "description": "Enable soft delete for containers" } }, "storageAccountContainerSoftDeleteRetentionDays": { "type": "int", "defaultValue": 7, "metadata": { "description": "Keep deleted containers for (in days)" } }, "storageAccountEnableBlobChangeFeed": { "type": "bool", "defaultValue": false, "metadata": { "description": "Enable blob change feed" } }, "storageAccountIsVersioningEnabled": { "type": "bool", "defaultValue": false, "metadata": { "description": "Enable versioning for blobs." } }, "storageAccountIsShareSoftDeleteEnabled": { "type": "bool", "defaultValue": true, "metadata": { "description": "Azure Files offers soft delete for file shares so that you can more easily recover your data when it's mistakenly deleted by an application or other storage account user" } }, "storageAccountShareSoftDeleteRetentionDays": { "type": "int", "defaultValue": 7, "metadata": { "description": "Keep deleted file shares for (in days)" } }, "keyVaultName": { "type": "string", "defaultValue": "[toLower(concat(parameters('appName'), '-kvault-', parameters('environment'), '-', parameters('location')))]", "metadata": { "description": "Azure Vault Name starting with a letter and containing only 0-9, a-z, A-Z, and -" }, "minLength": 3, "maxLength": 24 }, "keyVaultSku": { "type": "string", "defaultValue": "Standard", "allowedValues": [ "Standard", "Premium" ], "metadata": { "description": "Pricing tier" } }, "keyVaultAccessPolicies": { "type": "array" }, "keyVaultEnabledForDeployment": { "type": "bool", "defaultValue": false, "metadata": { "description": "Property to specify whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault" } }, "keyVaultEnabledForTemplateDeployment": { "type": "bool", "defaultValue": false, "metadata": { "description": "Property to specify whether Azure Resource Manager is permitted to retrieve secrets from the key vault." } }, "keyVaultEnabledForDiskEncryption": { "type": "bool", "defaultValue": false, "metadata": { "description": "Property to specify whether Azure Disk Encryption is permitted to retrieve secrets from the vault and unwrap keys" } }, "keyVaultEnableRbacAuthorization": { "type": "bool", "defaultValue": false, "metadata": { "description": "Use Azure Role based access control for key vault instead of vault access policy" } }, "keyVaultEnableSoftDelete": { "type": "bool", "defaultValue": true, "metadata": { "description": "Property to specify whether the 'soft delete' functionality is enabled for this key vault. It does not accept false value." } }, "keyVaultSoftDeleteRetentionInDays": { "type": "int", "defaultValue": 90, "metadata": { "description": "Number of days to retain deleted keys/secrets in key vault" } }, "keyVaultNetworkAcls": { "type": "object", "defaultValue": { "defaultAction": "allow", "bypass": "AzureServices", "ipRules": [], "virtualNetworkRules": [] }, "metadata": { "description": "A set of rules governing the network accessibility of a vault" } }, "appInsightsName": { "type": "string", "defaultValue": "[toLower(concat(parameters('appName'), '-app-insights-', parameters('environment'), '-', parameters('location')))]", "metadata": { "description": "Name of app insights instance" }, "minLength": 1, "maxLength": 255 }, "functionAppName": { "type": "string", "defaultValue": "[toLower(concat(parameters('appName'), '-functions-app-', parameters('environment'), '-', parameters('location')))]", "metadata": { "description": "Name of azure function name" } }, "use32BitWorkerProcess": { "type": "bool", "defaultValue": true, "metadata": { "description": "To use 32-bit worker process; otherwise 64bit worker process is used." } } }, "variables": { "hostingPlanName": "[toLower(concat(parameters('appName'), '-hosting-plan-', parameters('environment'), '-', parameters('location')))]" }, "resources": [ { "name": "[parameters('storageAccountName')]", "type": "Microsoft.Storage/storageAccounts", "apiVersion": "2019-06-01", "location": "[parameters('location')]", "properties": { "accessTier": "[parameters('storageAccountAccessTier')]", "minimumTlsVersion": "[parameters('storageAccountMinTlsVersion')]", "supportsHttpsTrafficOnly": "[parameters('storageAccountHttpsOnly')]", "allowBlobPublicAccess": "[parameters('storageAccountPublicAccess')]", "allowSharedKeyAccess": "[parameters('storageAccountAllowSharedKeyAccess')]", "networkAcls": { "bypass": "[parameters('storageAccountNetworkAclsBypass')]", "defaultAction": "[parameters('storageAccountNetworkAclsDefaultAction')]", "ipRules": [] } }, "dependsOn": [], "sku": { "name": "[parameters('storageAccountSku')]" }, "kind": "[parameters('storageAccountKind')]", "tags": "[parameters('tags')]" }, { "name": "[concat(parameters('storageAccountName'), '/default')]", "type": "Microsoft.Storage/storageAccounts/blobServices", "apiVersion": "2019-06-01", "properties": { "restorePolicy": { "enabled": "[parameters('storageAccountIsContainerRestoreEnabled')]" }, "deleteRetentionPolicy": { "enabled": "[parameters('storageAccountIsBlobSoftDeleteEnabled')]", "days": "[parameters('storageAccountBlobSoftDeleteRetentionDays')]" }, "containerDeleteRetentionPolicy": { "enabled": "[parameters('storageAccountIsContainerSoftDeleteEnabled')]", "days": "[parameters('storageAccountContainerSoftDeleteRetentionDays')]" }, "changeFeed": { "enabled": "[parameters('storageAccountEnableBlobChangeFeed')]" }, "isVersioningEnabled": "[parameters('storageAccountIsVersioningEnabled')]" }, "tags": "[parameters('tags')]", "dependsOn": [ "[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]" ] }, { "name": "[concat(parameters('storageAccountName'), '/default')]", "type": "Microsoft.Storage/storageAccounts/fileservices", "apiVersion": "2019-06-01", "properties": { "shareDeleteRetentionPolicy": { "enabled": "[parameters('storageAccountIsShareSoftDeleteEnabled')]", "days": "[parameters('storageAccountShareSoftDeleteRetentionDays')]" } }, "tags": "[parameters('tags')]", "dependsOn": [ "[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]", "[concat(concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName')), '/blobServices/default')]" ] }, { "apiVersion": "2018-02-14", "name": "[parameters('keyVaultName')]", "location": "[parameters('location')]", "type": "Microsoft.KeyVault/vaults", "properties": { "enabledForDeployment": "[parameters('keyVaultEnabledForDeployment')]", "enabledForTemplateDeployment": "[parameters('keyVaultEnabledForTemplateDeployment')]", "enabledForDiskEncryption": "[parameters('keyVaultEnabledForDiskEncryption')]", "enableRbacAuthorization": "[parameters('keyVaultEnableRbacAuthorization')]", "accessPolicies": "[parameters('keyVaultAccessPolicies')]", "tenantId": "[parameters('tenantId')]", "sku": { "name": "[parameters('keyVaultSku')]", "family": "A" }, "enableSoftDelete": "[parameters('keyVaultEnableSoftDelete')]", "softDeleteRetentionInDays": "[parameters('keyVaultSoftDeleteRetentionInDays')]", "networkAcls": "[parameters('keyVaultNetworkAcls')]" }, "tags": "[parameters('tags')]", "dependsOn": [] }, { "name": "[parameters('appInsightsName')]", "type": "microsoft.insights/components", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "apiVersion": "2020-02-02", "dependsOn": [], "kind": "web", "properties": { "Application_Type": "web", "Flow_Type": "Bluefield", "Request_Source": "rest", "ApplicationId": "[parameters('appInsightsName')]" } }, { "apiVersion": "2020-06-01", "name": "[variables('hostingPlanName')]", "type": "Microsoft.Web/serverfarms", "location": "[parameters('location')]", "kind": "", "tags": "[parameters('tags')]", "dependsOn": [], "properties": { "name": "[variables('hostingPlanName')]" }, "sku": { "name": "Y1", "tier": "Dynamic" } }, { "apiVersion": "2020-06-01", "name": "[parameters('functionAppName')]", "type": "Microsoft.Web/sites", "kind": "functionapp", "location": "[parameters('location')]", "tags": "[parameters('tags')]", "dependsOn": [ "[concat('Microsoft.Web/serverfarms/', variables('hostingPlanName'))]", "[concat('Microsoft.Storage/storageAccounts/', parameters('storageAccountName'))]", "[concat('microsoft.insights/components/', parameters('appInsightsName'))]" ], "properties": { "name": "[parameters('functionAppName')]", "siteConfig": { "appSettings": [ { "name": "FUNCTIONS_EXTENSION_VERSION", "value": "~3" }, { "name": "FUNCTIONS_WORKER_RUNTIME", "value": "node" }, { "name": "WEBSITE_NODE_DEFAULT_VERSION", "value": "~14" }, { "name": "APPINSIGHTS_INSTRUMENTATIONKEY", "value": "[reference(resourceId('microsoft.insights/components', parameters('appInsightsName')), '2020-02-02-preview').InstrumentationKey]" }, { "name": "APPLICATIONINSIGHTS_CONNECTION_STRING", "value": "[reference(resourceId('microsoft.insights/components', parameters('appInsightsName')), '2020-02-02-preview').ConnectionString]" }, { "name": "AzureWebJobsStorage", "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value)]" }, { "name": "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING", "value": "[concat('DefaultEndpointsProtocol=https;AccountName=', parameters('storageAccountName'), ';EndpointSuffix=', environment().suffixes.storage, ';AccountKey=',listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2019-06-01').keys[0].value)]" }, { "name": "WEBSITE_CONTENTSHARE", "value": "[concat(toLower(parameters('functionAppName')), '8ce8')]" } ], "use32BitWorkerProcess": "[parameters('use32BitWorkerProcess')]", "cors": { "allowedOrigins": [ "*" ] } }, "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]", "clientAffinityEnabled": false } } ], "outputs": {} } ```

Expected response

I expected no noise since the template has not been modified since the resources were deployed

Current (noisy) response

Note: The result may contain false positive predictions (noise).
You can help us improve the accuracy of the result by opening an issue here: https://aka.ms/WhatIfIssues

Resource and property changes are indicated with these symbols:
  - Delete
  + Create
  ~ Modify
  = Nochange
  x Noeffect

The deployment will update the following scope:

Scope: /subscriptions/<subscription-id>/resourceGroups/abcd-resource-group-prod-westus2

  ~ Microsoft.KeyVault/vaults/abcd-kvault-prod-westus2 [2018-02-14]
    + properties.networkAcls:

        bypass:        "AzureServices"
        defaultAction: "allow"

  ~ Microsoft.Web/serverfarms/abcd-hosting-plan-prod-westus2 [2020-06-01]
    - kind:     "functionapp"
    x sku.tier: "Dynamic"

  ~ Microsoft.Web/sites/abcd-functions-app-prod-westus2 [2020-06-01]
    + properties.siteConfig.cors:

        allowedOrigins: [
          0: "*"
        ]

    + properties.siteConfig.localMySqlEnabled:     false
    + properties.siteConfig.netFrameworkVersion:   "v4.6"
    + properties.siteConfig.use32BitWorkerProcess: true

  = Microsoft.Storage/storageAccounts/abcdstorageprodwestus2 [2019-06-01]
  = Microsoft.Storage/storageAccounts/abcdstorageprodwestus2/blobServices/default [2019-06-01]
  = Microsoft.Storage/storageAccounts/abcdstorageprodwestus2/fileservices/default [2019-06-01]
  = microsoft.insights/components/abcd-app-insights-prod-westus2 [2020-02-02]
    x properties.ApplicationId: "abcd-app-insights-prod-westus2"

Resource changes: 3 to modify, 4 no change.

Additional context

What if run on deployment mode COMPLETE

This ARM template is intended to be deployed to a resource group ({appName}-resource-group-westus2) with the following resources

  • Deploys basic infrastructure for Azure Functions App (FunctionApp, Storage Account, Application Insights, Hosting Plan)
  • In addition, also deploys a key vault.
alex-frankel commented 2 years ago

Any property with an x is "NoEffect" meaning they can be removed from the template. Ideally, the RP would reject this instead of silently ignoring them.

The siteConfig noise is a duplicate of #265