The initial time to a functioning working local dev environment can be a big hurdle, especially if the organization you are working for is running any significant amount of microservices.
This is the first part of a series about Azure CLI and dotnet user-secrets. You can read part 2 here:
Simplifying the process from cloning a repo to being able to run and debug the app locally with access to external resources located in the cloud can be a huge timesaver. Having a standardized way of handling this also reduces the cognitive load on developers moving between different applications.
Credentials, secrets and deployment, in general, are hard. At a customer project at Thon Hotels I worked on, all new dotnet core microservice projects that needed some kind of connection string or other secrets included a bash script
secrets.sh compatible with Git bash, Linux and macOS.
This script creates
dotnet user-secrets for the project in typically two environments (dev and test).
#!/bin/bash # secrets.sh ENVNAME=$(echo $1 | tr '[:upper:]' '[:lower:]') if [ "$ENVNAME" != "dev" ] && [ "$ENVNAME" != "test" ] then echo "usage: ./secrets.sh dev|test" echo "example: ./secrets.sh dev" exit 0 fi # The Git-bash path to Azure CLI is 'az.cmd'. Use 'az' if Unix like environment azCmd="az.cmd" if [ "$(uname)" == "Darwin" ] || [ "$(expr substr $(uname -s) 1 5)" == "Linux" ] then azCmd="az" fi echo "Environment: $ENVNAME" dotnet user-secrets set mysecret "Hardcoded example"
In this example there is a lot of work for only setting one secret, but as the number of configurations required for an application to run increases, the cognitive load stays about the same for the developers cloning and running it.
Regardless of how many secrets a project contains, all you need to get up and running are three simple steps:
$ git clone https://snær-git.net/nnnn.git $ cd nnnn/src/app $ ./secrets.sh dev Environment: dev Successfully saved mysecret = Hardcoded example to the secret store.
You probably noticed
az not being used in the example. Let us start with a very simple az "whoami" equivalent:
# secrets.sh modified echo "Environment: $ENVNAME" echo "Logged into: $($azCmd account show --query name)" echo "Logged in as: $($azCmd account show --query user.name)" dotnet user-secrets set mysecret "Hardcoded example"
Now we'll add a secret based on a value saved in my private keyvault, but first, a gotcha when reading strings from
Azure Keyvault using
az, you'll end up with a "quoted" string. For some reason bash and
az will helpfully add a starting and stopping
" if you don't remove them. A secret containing a connection string with a hidden
" or two inside of it can be very frustrating to debug.
To remove the start and end quotes you can use
sed like this:
sed -e 's/^"//' -e 's/"$//'
Let's first fetch the secret value from my dev keyvault, strip away
" and prepare the secret value for usage in the
# mysecret = fire # This will have " as part of the variable value $ MYSECRET=$($azCmd keyvault secret show --vault-name mykeyvault-$ENVNAME --name mysecret --query value) $ echo "This is $MYSECRET!" This is "fire"! # This strips " $ MYSECRET=$($azCmd keyvault secret show --vault-name mykeyvault-$ENVNAME --name mysecret --query value | sed -e 's/^"//' -e 's/"$//') $ echo "This is $MYSECRET!" This is fire!
Now we'll combine this with the
# secrets.sh modified echo "Environment: $ENVNAME" echo "Logged into: $($azCmd account show --query name)" echo "Logged in as: $($azCmd account show --query user.name)" MYSECRET=$($azCmd keyvault secret show --vault-name mykeyvault-$ENVNAME --name mysecret --query value | sed -e 's/^"//' -e 's/"$//') dotnet user-secrets set mysecret "Hardcoded example is $MYSECRET"
./secrets.sh dev your application now has access to
mysecret and can use it as needed.
$ dotnet user-secret list mysecret = Hardcoded example is fire
One of the strengths of using
az to read values from resources in Azure like this is that the only thing a developer needs to do if one of the Keyvault values changes is to run
secrets.sh for a quick refresh. You also get the ability to control who can access the secrets. Since the developers are logged in with
az they can only fetch secrets and configuration values they have access to.
Another interesting fact is that by using this
secrets.sh pattern you can change where the values are read from and how without having to do anything else than ensure that the developers have the correct CLI installed on their machine.
Hopefully this can inspire you into looking at solutions for automatically configuring secrets and connection strings.
If you only take one thing away from this blog post, let it be this:
Use dotnet user-secrets instead of manually adding secrets to appsettings.json juggling back and forth between "safe" values when committing to avoid secrets ending up in git history by accident 🙃
Git bash? Simply because Git bash is installed by default when installing Git for Windows and there is minimal extra effort using
$azCmdinstead of az directly in the scripts. Also, since these scripts are written to be compatible with Linux as well as
Git bashthey work when running in WSL using the Visual Studio Code Remote - WSL extension ↩︎