Featured image of post Passwordless PostgreSQL with Managed Identity

Passwordless PostgreSQL with Managed Identity

Secrets are the worst.

I hate managing them. You put them in Key Vault, but then you need a secret to access Key Vault. You put them in environment variables, but then they leak into logs. You rotate them, and everything breaks.

The best way to manage a password is to not have one.

Azure Managed Identity

For our MyDashboard backend, we decided to ban connection strings containing passwords. Instead, we use Azure System-Assigned Managed Identity. The App Service itself becomes an identity in Azure AD, and we grant that identity permission to log into the PostgreSQL database.

The Setup

It requires three pieces, and it was a bit tricky to figure out the first time.

1. Infrastructure (Bicep)

You need to enable the identity on your App Service. This is the easy part.

1
2
3
4
5
6
resource appService 'Microsoft.Web/sites@2021-02-01' = {
  name: 'my-app-service'
  identity: {
    type: 'SystemAssigned' // <--- This magic line
  }
}

2. Database User

You need to log into Postgres (as an admin) and create a user that maps to the Managed Identity.

1
2
3
SET aad_validate_oids_in_tenant = off; -- Required for some reason
CREATE ROLE "my-app-service" WITH LOGIN PASSWORD '123'; 
GRANT azure_ad_user TO "my-app-service";

(Pro tip: The password ‘123’ here is a dummy requirement by Postgres. It will never be used. Azure AD handles the actual check).

3. The Code (.NET)

This is where DefaultAzureCredential shines.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// In Program.cs
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
// Connection string looks like: 
// "Host=my-server.postgres.database.azure.com;Database=mydb;Username=my-app-service;SSL Mode=Require;"
// NOTICE: No Password!

builder.Services.AddDbContext<MyDbContext>(options =>
{
    options.UseNpgsql(connectionString, npgsqlOptions =>
    {
        // This magic line tells Npgsql to fetch a token from Azure AD!
        npgsqlOptions.UseAzureADAuthentication();
    });
});

Now, if you check your appsettings.json, strictly speaking, there are no secrets. Just names. If an attacker steals your config file, they can’t access your database. Splendid!

All rights reserved
Built with Hugo
Theme Stack designed by Jimmy