Introduction
There seems to be a lot of ways that we deploy the actual secret values into a key vault. The problem basically boils down to that someone at some point needs to view the password, in clear text when it is entered into whichever solution you have chosen.
I have seen solutions with blob storage hosting files with the actual values. I have also seen “master key vaults”, in which a secret is created and then picked up by a deployment and put into a local key vault.
I have seen solutions using Terraform and custom PS-scripts. All of these have the same common problem: They simply just move the problem one step over, and to me scripting is a way to solve something that is unsolvable without scripts.
My simple solution
I am a simple guy; I like simple solutions. I also had some other restraints: Azure DevOps and ARM. I do not like the idea of a centralized key vault and local copies. They still need to be updated manually, by someone at some point and then everything needs to be re-run anyway.
My solution makes use of secret-type variables in Azure DevOps. The person that creates the deploy pipeline enters the value or makes room for it to be updated by someone at some point. The variable is then used to override the parameter value in the deployment.
The step in the pipeline can either be part of a specific deployment or stored in a separate release-pipeline that only certain people have access to.
The solution step by step
To make this work you need to walk thru these steps:
- Create the ARM-template and parameter file.
- Create a DevOps build.
- Create the DevOps release pipeline.
- Run the pipeline and verify the results.
I will assume that you have a repo that DevOps has access to, that you are using VS Code and know how to create pipelines in DevOps.
Create the ARM-template and parameter file
If you have not installed the extension Azure Resource Manager (ARM) Tools, now is a great time to do so.
The examples below are just for one value. If you need to add more, simply copy, paste and rename.
The templatefile
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", "contentVersion": "1.0.0.0", "parameters": { "keyVaultName": { "type": "string", "metadata": { "description": "Your keyvault name " } }, "secretName": { "type": "string", "metadata": { "description": "The name to give your secret " } }, "secretValue": { "type": "securestring", "metadata": { "description": "The value of the secret" } } }, "resources": [ { "name": "[concat(parameters('keyVaultName'), '/', parameters('secretName'))]", "type": "Microsoft.KeyVault/vaults/secrets", "apiVersion": "2019-09-01", "tags": {}, "properties": { "value": "[parameters('secretValue')]", "contentType": "secret", "attributes": { "enabled": true } } } ], "outputs": {} }
There is really nothing special except for one crucial
part: You need to make the value of the secret be a securestring type. If not, the value will be accessible from deployment logs.
If you are interested in more information, you can find the ARM template definition for adding a key vault secret here.
The parameterfile
{ "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", "contentVersion": "1.0.0.0", "parameters": { "secretName": { "value": "myARMCreatedSecret" }, "keyVaultName": { "value": "myKeyVaultName" }, "secretValue": { "value": "overridden" } } }
There is only one noteworthy thing in the parameter-file: the secretValue is set to overridden. It does not have to be, but since the value will be overridden from Azure DevOps deployment, I added this value as some form of documentation. You can set it to whatever you like, even an empty string.
Create a DevOps build
After checking in the code, create a build for your key vault updates. If you don’t know how, I suggest you read up on it elsewhere. There is even an MS Learn course if you prefer.
Make sure that the ARM-template and parameter file are published at the end of the build.
Create a devops release pipeline
I will not go thru the basics of this step either, just the parts that are important to remember.
Create secret variables
Start by adding some variables that will hold the values for your secret.
Go to variables and click Add.
Add a variable called mySecret. Then add the value.
Initially, the secret is in clear view. Simply click the little padlock, to turn it into a secret value.
Now, save your updated pipeline. If you click the padlock again (after save), the secret will be gone. This means that the secret is safe and secure in the pipeline, when using variables.
Use the secret value
In your pipeline, you will add a ARM template deployment Task and set everything like usual, such as your Resource Manager Connection and such. Point to your new template and parameter files.
Given the examples above the should be set to:
- Template: $(System.DefaultWorkingDirectory)/_Build/drop/keyvault/templatefile.json
- Template Parameters: $(System.DefaultWorkingDirectory)/_Build/drop/keyvault/templatefile.parameters.TEST.json
- Override Template Parameters: -secretValue “$(mySecret)”
The last one is the important one. This tells Azure DevOps to override the parameter called “secretValue” with the value in the DevOps variable “mySecret”.
Run the pipeline and verify the results
After you have run the pipeline to deploy the secret, simply look in the key vault you are updating and verify the result.
Note that the ARM will create the secret and add the value the first time, all the next runs will add a new version of the secret value. Even if the value is the same.
Here is the secret created by my DevOps Pipeline:
Here is the secret value set by the DevOps Pipeline:
Conclusion
I know there are other ways of deploying the secret and its value. I just like the simplicity of this approach and the fact that there is one truth: The value in the DevOps Pipeline. If you need to update the value in the key vault, any key vault, you update the Pipeline variable and create a new release.
The built-in release management of pipelines also guarantees that you get traceability. Who updated the value? When? When was it deployed and by who?