Microservice and Azure Integration Part 4 : Adding Azure KeyVault

In this post, I’m going to add Azure KeyVault integration to my little microservice. The beauty of KeyVault is it’s layered security. I don’t need to keep anything in my appsettings.json, or in my secrets.json. KeyVault takes care of all of that now, meaning my code doesn’t contain any hardcoded secrets.

The trick to doing this is to create a new KeyVault Key/Pair within AppConfiguration. This automatically lists all the KeyVault secrets you (based on your access level) have access to.

Even in AppConfiguration you can only create a Key/Value pair that links to the secret. you can’t actually see the secret itself. Any reference in code to the Key/Value Pair is just a link to a Configuration, which in turn is only a link to the KeyVault.

What this does is allow you in Azure to have users that can create/edit secrets, and users that can only read the links in AppConfiguration, thus creating a separation of security concerns..

Note : When setting this up, I had to assign myself as a KeyVault administrator in Keyvault, even though I am the owner of the subscription.

Next is to add a secret into the keyvault. For this i’m going to create a CosmosDb resource, and store it’s connection string in there. then we’re going to access this in code.

The next stage is to add this secret now into the AppConfiguration as a Key/Value pair. This time we add as a KeyVault reference rather than a key/value pair.

Now, when we look in the KeyValue pair at the value, instead of seeing the connection string, we see only a link to the Vault, thus protecting our secret from non-KeyVault administrators.

Now I don’t need any keyvault references in my codebase, i can just access the configuration value to get any secret. Azure handles all the authorisation between the resources.

Now we need to wire keyvault into the microservice, this can be done with the following few lines in the program.cs

C#
var configuration = new ConfigurationBuilder()
            .AddConfiguration(localconfiguration)
            .AddAzureAppConfiguration(options =>
            {
  options.Connect(localconfiguration["ConnectionStrings:AzureAppConfiguration"]);
                options.ConfigureKeyVault(kv =>
                {
                    kv.SetCredential(new DefaultAzureCredential());
                } );
            })
            .Build();

In which we add the configure keyvault option, and pass it the default credentials. (in this case, the currently logged in user) which will drop try a number of different credential types starting with Environment Credential.

I also add in a transient service for CosmosClient. This will read the Database connection from KeyVault via AppConfiguration.

C#
services.AddTransient(x => new CosmosClient(configuration["CosmosDBConnection"]));

To try this out I’ve changed the code in the myapplication.cs to:

C#
try
            {
                
                var container = _cosmosClient.GetContainer("testdb-1", "myData");
                var sqlQuery = new QueryDefinition(query: "SELECT * FROM myData c WHERE c.name LIKE @name").WithParameter("@name", name);
                using (FeedIterator<Person> myPeople = container.GetItemQueryIterator<Person>(sqlQuery))
                {
                    while (myPeople.HasMoreResults)
                    {
                        FeedResponse<Person> response = await myPeople.ReadNextAsync();
                        foreach (Person p in response)
                        {
                            if (_configuration["LoggingDestination"] == "Console")
                            {
                                Console.WriteLine($"Hello {p.name}, Console Azure");
                            }
                            else
                            {
                                _logger.LogDebug($"Hello {p.name}, Debug Azure");
                            }
                        }
                    }
                    
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
            }

(I’ve created a small cosmos db with a bit of data in) CosmosClient is injected into the class, we set up a new QueryDefinition with a named parameter and then return the results to an output that is dependent on the AppConfiguration setting. This is useful for feature flags as it can be toggled without having to restart the application.

Running the application as such with a Debug(file) toggle:

C#
await app.Run("%a%");

gives us the correct results into a log file:

Plaintext
Dave
Sally
James

In the next part, I’m going to setup a consumer that will take a message and persist it to a database, and take another type of message and return the results.


Posted

in

, , ,

by

Tags: