Skip to content

✨ Managed Identity - Migrate Azure services from connection string secrets to Managed Identity #1552

@ssw-yakshaver

Description

@ssw-yakshaver

Requested by: @jernejk via YakShaver.ai 🦬
cc: @jernejk, @Freego1783

Hi Team!

Β Β πŸŸ₯Β Β Watch the video (1 min 13 sec)

Β Β πŸ“ SSW Rule: Do you use Azure Managed Identities?

Pain

SSW.Rewards has System Assigned Managed Identity already enabled on the App Service, and Key Vault RBAC is properly configured. However, the actual service connections (SQL, Blob Storage, Notification Hub) still use connection string secrets stored in Key Vault rather than authenticating via Managed Identity directly.

This means:

  • Secrets still need to be rotated and managed
  • Connection strings with embedded credentials are stored in Key Vault
  • The Managed Identity setup gives false confidence β€” it's only used for Key Vault access, not for the services themselves

Current State (what MSI is/isn't used for)

Service Current Auth MSI Ready?
Key Vault βœ… MSI (RBAC role assignment) βœ… Done
Blob Storage ❌ Connection string via Key Vault (despite preferMsi: true in code) 🟑 Partially
Azure SQL (App DB) ❌ SQL credentials via Key Vault ❌ No
Azure SQL (Hangfire) ❌ SQL credentials via Key Vault ❌ No
Notification Hub ❌ Connection string via Key Vault ❌ No
Azure Maps ❌ API key via Key Vault ⚠️ May not support MSI
Graph API (email) ❌ Client secret via Key Vault ⚠️ Separate concern
Firebase ❌ Credentials JSON via Key Vault ⚠️ External service

Acceptance Criteria

SQL Server β†’ Managed Identity Auth

  • Update sql.bicep to enable Azure AD-only authentication (currently has both SQL admin + AD admin)
  • Create contained database users for the App Service MSI in both databases (app + Hangfire)
  • Update Infrastructure/ConfigureServices.cs to use DefaultAzureCredential with SqlConnection (via Azure.Identity + Microsoft.Data.SqlClient)
  • Update Hangfire SQL connection to use MSI token-based auth
  • Remove SqlConnectionString and HangfireSqlConnectionString secrets from Key Vault
  • Update webapp.bicep to remove Key Vault connection string references, replace with server/database name app settings

Blob Storage β†’ Managed Identity Auth

  • Code already has preferMsi: true β€” verify it works with service URI instead of connection string
  • Update webapp.bicep to pass Blob Storage service URI instead of connection string
  • Add "Storage Blob Data Contributor" RBAC role assignment for App Service MSI on the storage account
  • Remove ContentStorageConnectionString secret from Key Vault

Infrastructure (Bicep)

  • Add RBAC role assignments in Bicep for SQL and Blob Storage (similar pattern to existing add-kv-role-assignment.bicep)
  • Update webapp.bicep app settings to use service endpoints instead of Key Vault secret references where possible
  • Keep Key Vault for secrets that genuinely can't use MSI (Firebase credentials, Graph client secret, Azure Maps key)

Testing & Verification

  • Verify local development still works with connection strings (dev uses Docker SQL)
  • Verify deployed app connects to SQL via MSI
  • Verify Blob Storage operations work via MSI
  • Verify Hangfire job processing works via MSI
  • Health checks pass

Documentation

  • Update README or docs with MSI configuration notes
  • Document which services still require Key Vault secrets and why

⚠️ Gotchas

  • SysAdmin dependency: Creating contained database users and assigning SQL AD roles likely requires elevated permissions β€” a SysAdmin may need to be involved
  • Not all services support MSI: Firebase, Azure Maps, and Graph API client secrets will likely remain in Key Vault β€” that's OK
  • Local dev unchanged: DefaultAzureCredential falls back to connection strings/local auth, so Docker-based local dev should still work
  • Different MSI patterns per service: SQL needs Azure AD auth + contained users, Blob needs RBAC roles, each has different SDK integration

Screenshot

Screenshot
Figure: SSW Rewards lacks managed identity integration despite SSW rules

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions