What is the best way to store secrets using Azure Key Vault?

As I said already, you should NEVER store passwords in any file going to your Git repo – there is a circle in Dante’s hell just for people doing that 🙂

Up until recently you had a few options to store secrets where the most used one was to store them in Application settings of your Azure App Service (there is another circle for people still using cloud service/VMs in 2018) and then during the runtime app service will override the local dev settings with the appropriate environment ones.  That is a bit better as now you don’t have to be afraid of anyone having access to your repo that just about anyone having access to the Azure Portal with services.

To make this even safer Microsoft created a secure storage called Azure Key Vault to which you move all the secrets from Application Settings and now only folks who have access to Azure Key Vault can see them.

The problem is now how to authenticate with Key Vault and the only solution up until a few  months ago was to  use Azure Key Vault from a web app using client secret which basically meant that you have to store your Key Vault password into the Application settings which kind of made the whole purpose of Key Vault questionable as anyone having access to App settings will get the password for Key Vault and 3 minutes later access to the secrets there.

Alas, do not despair, my dear reader, as little thinker fairies from Microsoft Azure team invented Azure Active Directory Managed Service Identity (MSI) just so we can secure our secrets in a worry-free way.

So what is MSI and how it helps with the problem?

Good question!

Basically, the idea is here that you make an AAD account for your app service with secret credentials not shown anywhere on the portal and then you grant Azure Key Vault access rights to that account so without any secrets stored anywhere your app service will be authorized for Key Vault access.

How to create AAD account for your app service?

Easy peasy! Open your app service and scroll the settings until you find Manage service identity one click On and Save – that’s it.
Here is how I did that on my app service called keyvault-demo

How to authorize managed service identity to access Key Vault?

Also easy (you have to love new MS/Azure stack – superb simple and strong stuff) – open or create Key Vault, click on Access Policies and then click on Add.

Here is how I did that on my key vault called nivatech-demo

On the Add access policy first select the template what the app service should have access too (I’ve given it in this blog post access to everything (keys, secrets and certs) , then click Select principal list item and in the search box on the right side enter the name of app service MSI you want to authorize (in this blog post keyvault-demo) and then click Select.

Don’t forget to click Save on the next screen 🙂

Et voila! Your app service can now access key vault and read keys/secrets/certs.

Can I see the sample of the code reading the value from Key Vault using this MSI thingy?

Oh, sure – it is quite simple.

Let say we want to store in our key vault a secret which will be used for JWT authorization in a key called jwt-secret-key and with value Y31n55o835dv2CpSAKsErqVUqkNb42P0.

In Key Vault find Secrets and click Generate/Import button.

And then fill the fields with the key name and value

(The story about the need of rotating keys will have to wait for some other time so we will not set any expiration date here)

How can I retrieve the value from Key Vault in my service?

The best way is to add KeyVault as a configuration provider and then the value will come out of the simple usage of IConfiguration as all the other config values.

The way how I do this in Papiri application is by modifying Program.cs file to be something like this

public class Program
{
    public static void Main(string[] args)
    {
        
        var builder = WebHost.CreateDefaultBuilder(args);

        //Add CacheKey Vault to configuration pipeline
        builder.ConfigureAppConfiguration((context, configBuilder) =>
        {
            // vault host address - you can get the value from app settings
            var vaultHost = "https://nivatech-demo.vault.azure.net/";
            
            //Create Managed Service Identity token provider
            var tokenProvider = new AzureServiceTokenProvider();
            
            //Create the CacheKey Vault client
            var kvClient = new KeyVaultClient((authority, resource, scope) => 
                            tokenProvider.KeyVaultTokenCallback(authority, resource, scope));
            
            //Add CacheKey Vault to configuration pipeline
            configBuilder.AddAzureKeyVault(vaultHost, kvClient, new DefaultKeyVaultSecretManager());
        });
        

        builder
            .UseApplicationInsights()
            .UseStartup<Startup>();
        builder.Build().Run();
    }
}

and that’s pretty much it – anywhere in your code you can do now

var keyFromVault = this.configuration.GetValue<string>("jwt-secret-key");

Wow, this is super cool but how can I run this code on my dev box?

I don’t use KeyVault locally (I prefer user secrets) but if you want to use it it is easy and all it is need is a few steps:

  1. Go to Key Vault / Access Policies / Add New and add yourself.

    My subscription is tied to my Microsoft Account (MSA) and I use the same to login to my dev box but this works the same if you are using AAD accounts.
  2. Install on your dev machine azure CLI 2.0
  3. Then run az login  command on your dev box to and login with the same account from #1 to your Azure subscription
az login

That’s it – the code snippet from above should now work on your local box too!

Questions/Comments/Corrections/Suggestions – more then welcome 🙂

(In some of the future posts I will share how I secure in my Papiri application using MSI secret access to blob storage and service bus)

How to run Azure app service with Asp.Net Core 2.2 Preview?

So, you like Asp.Net Core 2.2 Preview as much as I do and you want to deploy your website to Azure as app service – easy peasy, right?

Not so fast cowboy! 🙂

Asp.Net Core 2.2 is ATM still in Preview and in order to be able to deploy it to Azure service you need to add 2.2 runtime extension.

First, open your app service and find Extensions section and click add

Then you find Asp.Net  Core 2.2 Runtime extension select it and accept EULA

After a few seconds, the extension is installed and your 2.2 websites are working fine now deployed on Azure.

So go and get that cup of coffee you deserve for a job well done!

How to protect API with JWT tokens in Asp.Net Core

Unless you are a time traveler and just landed in 2018, the app you are working on is using for sure some REST API (we’ll skip GraphQL for now) to CRUD the data it works with.

My preferred technology for implementing such an API is  Asp.Net Core WebAPI so creating endpoints is quite a trivial task.

Protecting the endpoints from the unauthorized access is, unfortunately, a bit less trivial task but still easy in Asp.Net Core compared to how it was done in the past.

In Papiri we are using claims-based authentication using the JWT bearer tokens.

What is JWT?

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties. It is a de facto standard on the web for performing authorization which is not dependent on any technology or platform. If you check out the https://jwt.io/ you can see libraries in many different languages.

Basically JWT token is a base64 encoded string which consists of 3 parts separated by dots – like this one

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.XbPfbIHMI6arZ3Y922BhjWgQzWXcXNrz0ogtVhfEd2o.

You can take this string and paste it on jwt.io to see what it contains…

The first part of that string is called header and it contains things like what algorithm and token type are used.

The second part of the string contains set of claims which we want to be sent as a part of the JWT token. Purpose of this part is to define claims which we want to be part of principal claims once the authorization is complete on API side.

The third part is a signature part which is an encrypted checksum of the previous two sections. Purpose of this part is to verify that the claims sent to the backend have not been tampered and thus making token invalid.

How to create JWT token?

First of all, you need app secret key which you will use to encrypt JWT signature. You DO NOT put that in your git repo, config files etc as if someone will get a hold of it he would be able to generate JWT token with any set of claims impersonating different roles etc.

(You should store app secret it in Azure Key Vault but how to do that is part of some of the future blog posts)

var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

Once we transform the secret into the credentials object we need to define the set of claims which will be sent in jwt token – here are claims we use in Papiri app

var claims = new List<Claim>()
{
    new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
    new Claim(JwtRegisteredClaimNames.UniqueName, user.Email),
    new Claim(JwtRegisteredClaimNames.GivenName, user.FirstName),
    new Claim(JwtRegisteredClaimNames.FamilyName, user.FamilyName),
    new Claim(JwtRegisteredClaimNames.Jti, KeyGenerator.GetSecureGuid().ToString()),
    new Claim(JwtRegisteredClaimNames.Iss, issuer),
    new Claim(JwtRegisteredClaimNames.Iat, DateTime.UtcNow.ToEpochMillis().ToString(), ClaimValueTypes.DateTime),
    new Claim(JwtRegisteredClaimNames.Email, user.Email)
};

A few thoughts about the claims:

  • You always need to have jti claim set to some random value on every token generation as a form of salting the signature which makes it harder for cracking
  • iat claim is the claim which represents when the claim is issued at and you can then set the expiration policy which will invalidate claim after x seconds for example which reduces the risk of someone stealing the token and using it in issuing its own calls.
  • As you can tell we send also a few data describing the user in more details which we need to simplify our microservice architecture and avoid cross service authorization calls.

All right, credentials and claims are ready so lets define the token expiration and create it!

var expires = DateTime.Now.AddMinutes(1);

var jwtSecurityToken = new JwtSecurityToken(
    expires: expires,
    claims:claims,
    signingCredentials: creds);

string token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);

And there we are – we got the signed JWT token containing our claims.

How to send JWT token with API requests?

The best approach is to send it in Authentication request header in a form of Barer token – something like this

Authentication: Bearer JWT_TOKEN_GOES_HERE

In C# this is usually done like this

using (var client = new HttpClient())
{
     client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", token);
     ...
}

How to authorize API calls with JWT bearer authentication header?

So now there is a call hitting your endpoint with the bearer token, how to use that in your endpoint? In Asp.Net Core that is super easy!

In your Asp.Net Core Startup.cs class find the ConfigureServices method and add this code there

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(cfg =>
    {
        cfg.TokenValidationParameters = new TokenValidationParameters()
        {         
            ValidateAudience = false,
            ValidateIssuer = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = issuer,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(APP_SECRET_HERE))
        };
    });

One more time: do not put app secret in your code – this is just demoware sample – wait until I describe how to store it properly in Azure Key Vault in next blog post 🙂

One more line needed to be added to Configure method

app.UseAuthentication();

Now when we have this set all we need to do is to put the [Authorize] attribute on controller we want to protect and that’s it!

If the token is valid the claims will be transferred to the set of claims User property controller has inside the action and you are good to go!

There you go – crash course in JWT tokens in Asp.Net Core!