I went to see a customer recently who uses Azure ARM templates quite extensively. As part of their template deployment script, they create a range of secrets (database passwords, user account passwords) on the fly, store them in a KeyVault and then refer to the KeyVault for the rest of the deployment. This is a practice that we recommend as it means that with every redeployment we can automatically rotate and regenerate secrets.

The customer had followed one of our Quick Start templates to create a child template for the key vault. This child template would take in an array of secret names and values. The parameter look like this:

"secrets": {

"type": "array",
"defaultValue": "{}",
"metadata": {

"description": "all secrets {\"secretName\":\"\",\"secretValue\":\"\"}"

}

}

And the template used the copyIndex function to cycle through the array, writing each secret into the KeyVault.

{

"type": "Microsoft.KeyVault/vaults/secrets",
"name": "[concat(parameters('keyVaultName'), '/', parameters('secrets')[copyIndex()].secretName)]",
"apiVersion": "2015-06-01",
"properties": {

"value": "[parameters('secrets')[copyIndex()].secretValue]"

},

"dependsOn": [
"[concat('Microsoft.KeyVault/vaults/', parameters('keyVaultName'))]"
],

"copy": {

"name": "secretsCopy",
"count": "[length(parameters('secrets'))]"

}

}

From a functional perspective there is nothing wrong with this template, but the customer voiced a concern around the fact that they could see the secrets passed in plain text in the portal.

 

 

As per the ARM parameter best practices sensitive content should either be transmitted as a SecureString or a SecureObject type.
While there is plenty of documentation available around the usage of SecureString, it is more difficult to find resources for SecureObject on the internet.

We still wanted to use an array to take advantage of the iterative capabilities of ARM templates, so SecureString was not an option.
Luckily there is an option to wrap an array in a SecureObject.

Wrapping a PowerShell array in a SecureObject

You can do this very easily by creating a hashtable around the array like so:

$array = @()
$array += "myValue1"
$array += "myValue2"
$object = @{"array"=$array}

In the above example $object can then be passed to an ARM deployment that expects a secureObject.

How does this work in an ARM template parameter file?

Simply wrap the array in a JSON object.

"secrets": {

"value": {

"array": [
{

"secretName": "exampleSecret1",
"secretValue": "secretVaule1"

},

{

"secretName": "exampleSecret2",
"secretValue": "secretValue2"

}

]

}

}

The result

Once wrapped the array content of the SecureObject will no longer appear in the portal. Please note however that the SecureObject wrapper is just that. The values are only secured while they are wrapped and it is not a per-string protection like SecureString. In other words: Before your array becomes a SecureObject all its values will be plaintext on the client.