Azure / azure-quickstart-templates

Azure Quickstart Templates
https://aka.ms/azqst
MIT License
14.09k stars 16.14k forks source link

KeyVault secret doesn't support content type #2263

Open gregjhogan opened 8 years ago

gregjhogan commented 8 years ago

It seems like there isn't a way to set the content type for a key vault secret through an ARM template. This prevents people from using an ARM template to completely deploy an web app with an SSL cert that they already have. I try to set the content type below, but it doesn't actually set it.

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0",
    "parameters": {
        "keyVaultName": {
            "type": "string"
        },
        "location": {
            "type": "string",
            "defaultValue": "[resourceGroup().location]"
        },
        "tenantId": {
            "type": "string",
            "defaultValue": "[subscription().tenantId]"
        },
        "certificate": {
            "type": "securestring"
        }
    },
    "variables": {
        "apiVersion": "2015-06-01"
    },
    "resources": [
        {
            "apiVersion": "[variables('apiVersion')]",
            "type": "Microsoft.KeyVault/vaults",
            "name": "[parameters('keyVaultName')]",
            "location": "[parameters('location')]",
            "tags": {
                "template": "admin-keyvault"
            },
            "properties": {
                "sku": {
                    "name": "Standard",
                    "family": "A"
                },
                "tenantId": "[parameters('tenantId')]",
                "accessPolicies": [ ],
                "enabledForDeployment": true,
                "enabledForTemplateDeployment": true
            },
            "resources": [
                {
                    "apiVersion": "[variables('apiVersion')]",
                    "type": "secrets",
                    "name": "test-cert",
                    "dependsOn": [ "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]" ],
                    "properties": { "value": "[parameters('certificate')]", "contentType": "application/x-pkcs12" }
                }
            ]
        }
    ]
}
ChronosWS commented 8 years ago

Verified still a problem on 11/18/2016

seanbamsft commented 8 years ago

@ChronosWS I fixed this back in August and it appears to be working right now. The one case where I know it won't update contentType is if you are attempting to update an existing secret. To avoid creating a large number of unique secret versions for repeated template deployments, we skip the update if the secret value matches the existing secret. The Set-AzureKeyVaultSecretAttribute PowerShell cmdlet can update attributes on existing secrets. If you are seeing this bug for new secrets, please let me know which cloud environment (Public, China, etc.) and region so I can investigate further.

gregjhogan commented 8 years ago

@seanbamsft thanks, that is great! Is there now secureobject ARM template parameter support (parameter file key vault reference)? e.g. put a JSON string into a key vault secret, set the content type to application/json, and reference it from an ARM template parameter file where the parameter is of type secureobject

marrobi commented 7 years ago

@gregjhogan  @seanbamsft I'd like to do that too. Have we any examples? At the moment template validation fails whatever I try.

seanbamsft commented 7 years ago

@gregjhogan @marrobi I don't think that is possible with Azure Resource Manager's template language. It looks like they always treat the secret as a string and there is no function to reinterpret a string as an object (there is a string() function that can reinterpret an object as a string). If you have a secret that contains multiple parts that need to be accessed, I think the best you can do is store them with some delimiter and then use split() to access the parts. For example, if I have a secret with a value like "user\np@ssw0rd" (i.e., user name on one line, password on the next), I can create a variable in the template like this:

"variables": {
    "accountParts": "[split(parameters('secretValue'),'\n')]",
    "account": {
        "userName": "[variables('accountParts')[0]]",
        "password": "[variables('accountParts')[1]]",
    }
}

That would allow me to use the account object in a resource definition.

gregjhogan commented 7 years ago

@seanbamsft I have done that before in simple situations, but there are more complex scenarios that are much more difficult to accommodate. For example, I would like put the ipSecurityRestriction list for a web app in a key vault. Think about what you would have to do to convert a delimited string into an arbitrary size array of objects. There are several ways to solve this problem, but I like the idea of putting it into a key vault the best (so I can easily pass it as an ARM template parameter, but keep it secret). I found a way to make it work, but it is pretty ugly and I am hoping someday you have better support for JSON objects in key vaults (or perhaps just an ARM template function that converts a string into a JSON object).

{
  "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/test-group/providers/Microsoft.Web/sites/test-site/config/web",
  "name": "test-site",
  "type": "Microsoft.Web/sites/config",
  "location": "Central US",
  "properties": {
    ...
    "ipSecurityRestrictions": [
      {
        "ipAddress": "123.456.0.0",
        "subnetMask": "255.255.0.0"
      },
      ...
    ]
  }
}