Most modern cloud applications are built with a need to access other cloud resources. This creates the challenge of managing the credentials in your code for authenticating to cloud services. Keeping credentials secure is an important task. Ideally, the credentials never appear on developer workstations or checked into source control.
Today we are going to walk through an example of using Managed Identities for Azure Resources to authenticate to Azure Key Vault. Never again will you have to managed credentials in your application. And best of all, its all done using containers.
What is Managed Identities for Azure Resources
In short, Managed Identities for Azure Resources, provides Azure services with an identity in Azure AD. You can use the identity to authenticate to any service that supports Azure AD authentication, including Key Vault, without any credentials in your code.
There are two types of identities: System Assigned and User Assigned. System Assigned are directly tied to the service you are using. In our case, the container group. The identities lifespan matches the lifespan of the container group.
User Assigned identities allow for having an identity live past the lifetime of a single instance. These are created and can be used with multiple different services. This is especially great for container groups where an identity is create once with all the permissions, then many container groups can be quickly spun up to take advantage of the identity.
Lets Start Building
Today, we’re building a container to takes advantage of Managed Identities and retrieve secrets from Azure Key Vault. With this, we won’t have to pass any access credentials to our application. The full code can be found HERE.
To keep things simple, let’s start with building a Key Vault Client wrapper using the Azure Go SDK. Note: Make sure you have the latest version of the Azure/go-autorest library. v11.2.1 or later:
The main setup happens in the NewKeyVaultClient function. First we set up the Managed Identity config from the Autorest Auth library. This is using the key vault endpoint to tell Managed Identities which resource we would like to authenticate with.
Authorizer() gets the authentication token for making requests to the key vault API.
The GetSecret function simply makes the API call using the azure SDK and returns the secret.
With the client wrapper setup, time to make the main function.
We use environment variables to pass in the vault name, secret name and the Id for our user assigned Identity. The key vault client wrapper sets up the Managed Identity authentication and retrieves the secret. The Managed Identity authorizer handles everything including refreshing the token when it expires.
First, to handle our dependencies, we’re going to use Dep, one of Go’s dependency managers. Dep will handle everything we need like creating a vendor folder to hold the different dependencies. Initialize dep using the following command
dep init -v
You should now see a vendor folder as well as a Gopkg.toml and a Gopkg.lock.
Time to create our Dockerfile. We are taking advantage of Docker’s multi-stage builds to compile the Go code and move the binary to a small alpine image.
Add the following into a file called Dockerfile
Build and push the image to a container registry like DockerHub or Azure Container Registry. Here, I’m pushing to DockerHub
docker build -t <your-dockerhub-username>/msi-golang .
docker push <your-dockerhub-username>/msi-golang
Deploying to Azure Container Instances
To deploy the container, open either a terminal with the Azure CLI installed or check out CloudShell for a ready-to-go option.
First, create a resource group or skip this step if you already have one. Choose any name you would like, here we call it myResourceGroup:
az group create --name myResourceGroup --location westus
Create the User Assigned Identity
Next we create a user assigned identity. Once we create and add the permissions, we will be able to use this for multiple container groups.
az identity create -g myResourceGroup --name myUserIdentity
The output should look close to the following
To make our lives easier, lets add the important information from this output to some environment variables.
Note: if you’re using Powershell, make sure to add the “$” when declaring these variables.
Create a Key Vault and Set the Permissions
If you don’t already have a Key Vault create, use the following command to create one:
az keyvault create -g myResourceGroup --name <mykeyvault>
We can quickly add a secret to the new vault
az keyvault secret set --name SampleSecret --value "MSI Secret!" --vault-name <mykeyvault>
Now, we can give our identity access to the Key Vault
az keyvault set-policy -n <mykeyvault> --object-id $PRINCIPAL_ID -g myResourceGroup --secret-permissions get
The above command uses the environment variable we set to give our identity “get” permission for secrets in the Key Vault
Next, simply deploy it:
az container create \
--resource-group myResourceGroup \
--name msi-golang \
-e KEYVAULT_VAULT_NAME=<mykeyvault> KEYVAULT_SECRET_NAME=<SampleSecret> MSI_USER_ASSIGNED_CLIENTID=$CLIENT_ID \
--assign-identity $ID \
The above command will create the container instance and set up everything needed for Managed Identities.
Use the following command to show that it was able to access our key vault and get the secret.
az container logs -g myResourceGroup --name msi-golang
The output should look something like
That’s All It Takes
Now you can be off creating application without ever needing to worry about how to securely get the secrets to run your apps.
The full example from this article can be found HERE.
Feel free to leave a comment for any questions or comments. I enjoy hearing people’s experience and helping in any way I can.
If you enjoyed this article, leave a clap or two and tell your friends. Claps are a huge help.