---
title: "How to Secure Azure Service Accounts with Managed Identities"
description: "Learn how to replace secret-based Azure service accounts with managed identities, grant least-privilege Azure RBAC access, validate token-based authentication, and remove stored secrets."
canonical: "https://adamtheautomator.com/secure-azure-managed-identities/"
---

# How to Secure Azure Service Accounts with Managed Identities

> Learn how to replace secret-based Azure service accounts with managed identities, grant least-privilege Azure RBAC access, validate token-based authentication, and remove stored secrets.

Source: https://adamtheautomator.com/secure-azure-managed-identities/

---

ATA Learning

Tap to hide

[

ATA Learning

](/)

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Search for:  

*   [](https://twitter.com/adbertram)
*   [](https://github.com/Adam-the-Automator)
*   [](https://www.linkedin.com/company/adam-the-automator-llc)
*   [](/feed/)

![How to Secure Azure Service Accounts with Managed Identities](https://adamtheautomator.com/wp-content/uploads/2026/04/featured_image-20.webp)

# How to Secure Azure Service Accounts with Managed Identities

[![](https://secure.gravatar.com/avatar/d0b9d42e21e5622713f8b693aa5c0f9244d5f7dd200ed29b8398f52dee5de337?s=192&d=mm&r=g)Adam Bertram](https://adamtheautomator.com/author/adam-bertram/)30 April 20266 min. read

Categories: [Cloud](/category/cloud/)

Tags:[Active Directory](/tag/active-directory/)[Azure](/tag/azure/)[Azure Active Directory](/tag/azure-active-directory/)[Azure CLI](/tag/azure-cli/)

Table of Contents

*   [Prerequisites](#prerequisites)
*   [Deploying the Managed Identity](#deploying-the-managed-identity)
*   [System-Assigned vs. User-Assigned](#system-assigned-vs-user-assigned)
*   [Step 1: Find What Already Exists](#step-1-find-what-already-exists)
*   [Step 2: Create Or Enable The Managed Identity](#step-2-create-or-enable-the-managed-identity)
*   [Step 3: Grant The Smallest Useful Role](#step-3-grant-the-smallest-useful-role)
*   [Step 4: Validate Token-Based Access](#step-4-validate-token-based-access)
*   [Step 5: Remove The Secret](#step-5-remove-the-secret)
*   [Put PIM Around The Humans](#put-pim-around-the-humans)
*   [Audit Who Can Abuse The Identity](#audit-who-can-abuse-the-identity)
*   [Common Mistakes](#common-mistakes)
*   [Remove The Secret And Keep Privilege Time-Bound](#remove-the-secret-and-keep-privilege-time-bound)

If your app, function, VM, or automation job still signs into [Azure](https://learn.microsoft.com/en-us/azure/) with a username and secret, you are adding avoidable operational and security overhead every time someone stores it, copies it, rotates it, or forgets it exists. [Managed identities](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) are the clean option: Azure holds the credential, rotates it automatically, and you never see it.

This tutorial walks you through creating a managed identity for your Azure workload and granting it exactly the role it needs. You will enable the identity, assign a narrowly scoped role, validate that your workload can get a token, and remove the old secret. You will also put [Privileged Identity Management (PIM)](https://learn.microsoft.com/en-us/entra/id-governance/privileged-identity-management/pim-getting-started) around the humans who manage the workload so nothing has standing privilege when you are done.

## Prerequisites

If you want to follow along hands-on, you’ll need:

*   A recent [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/) installation and an authenticated session. Run `az account show` to confirm your session is active; if it fails, follow Microsoft’s [Azure CLI authentication guide](https://learn.microsoft.com/en-us/cli/azure/authenticate-azure-cli?view=azure-cli-latest) before continuing.
    
*   Permission to create identity resources and assign [Azure role-based access control (Azure RBAC)](https://learn.microsoft.com/en-us/azure/role-based-access-control/) roles.
    
*   A target service such as [Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/) or Storage that supports Microsoft Entra authentication. Microsoft maintains a [full list of Azure services that support managed identities](https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/managed-identities-status).
    
*   Optional: Microsoft Entra ID P2 (or Entra ID Governance) plus the appropriate admin role if you want to use [PIM](https://learn.microsoft.com/en-us/entra/id-governance/privileged-identity-management/pim-configure) for human admin access.
    

## Deploying the Managed Identity

This is the part most teams want to rush. Do not. The setup works when you create the identity first, assign narrowly, validate, and only then remove the old secret. Strange how that keeps working.

* * *

**_Key Insight: The question is not “Which identity looks modern?” The question is “Which identity matches the workload’s lifecycle without leaving a secret behind?”_**

* * *

That lifecycle question drives the rest of the setup.

### System-Assigned vs. User-Assigned

[Managed identities](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) come in two forms:

*   **System-assigned** identity: tied to one Azure resource and deleted with it.
    
*   **User-assigned** identity: a standalone resource you can attach to more than one workload.
    

Use system-assigned when the identity should die with the workload. Use user-assigned when you need the same identity across multiple resources or a stable identity before deployment. That choice looks boring until you need to change it later.

### Step 1: Find What Already Exists

Before creating anything, check what managed identities already exist in the tenant. You want to avoid naming collisions and understand what scope is already in use.

```bash
az rest --method get --url 'https://graph.microsoft.com/v1.0/servicePrincipals?$filter=(servicePrincipalType eq '\''ManagedIdentity'\'')'
```

That query returns every managed identity in the tenant. It is useful when you need to find existing identities instead of guessing which team named them `prod-app` and left it there.

Then check the role assignments at the scope you plan to use:

```bash
az role assignment list \
  --scope /subscriptions/<sub-id>/resourceGroups/<rg-name> \
  --fill-principal-name false \
  -o table
```

That shows what is already assigned at the resource group scope. `--fill-principal-name false` keeps the command from doing extra Graph lookups you do not need during a review pass.

### Step 2: Create Or Enable The Managed Identity

If the workload needs a reusable identity, create a user-assigned managed identity first:

```bash
az identity create \
  --name uai-ordering-api \
  --resource-group rg-shared-identities \
  --location eastus
```

This gives you a `principalId` for RBAC and a `clientId` for runtime selection. If the workload should own its identity lifecycle, enable a system-assigned identity on the Azure resource instead of creating a standalone one.

### Step 3: Grant The Smallest Useful Role

Now bind the identity to the exact data it needs. For a Key Vault-backed app, that usually means a vault-scoped data role, not subscription-wide access.

```
principalId=$(az identity show \
  --name uai-ordering-api \
  --resource-group rg-shared-identities \
  --query principalId -o tsv)
```

This pulls the managed identity’s `principalId` so you can assign the role in the next step.

```bash
az role assignment create \
  --assignee-object-id "$principalId" \
  --assignee-principal-type ServicePrincipal \
  --role "Key Vault Secrets User" \
  --scope /subscriptions/<sub-id>/resourceGroups/<rg-name>/providers/Microsoft.KeyVault/vaults/<vault-name>
```

[Key Vault Secrets User](https://learn.microsoft.com/en-us/azure/key-vault/general/rbac-guide) is a data-plane role. That matters. Control-plane access and data-plane access are not the same thing, and mixing them up is how people accidentally hand an app far more power than it needs.

| Scope | When to use it | Risk if too broad |
| --- | --- | --- |
| Resource | A single narrowly scoped resource | Lowest blast radius |
| Resource group | Several related resources owned together | Easy to overreach |
| Subscription | Rare exception only | Hard to justify later |

Keep the scope as narrow as the workload allows. Subscription scope is a last resort, not a shortcut.

### Step 4: Validate Token-Based Access

Once the identity is assigned, test it from the Azure resource that actually runs the workload — the workload host. That host is whatever Azure resource has the managed identity attached: a VM, an App Service instance, a Function App, or similar. On a VM, Azure App Service, or other Azure resource with a managed identity, use `az login --identity`. If you are using a user-assigned identity, specify the client ID or resource ID explicitly.

```bash
az login --identity --client-id <user-assigned-client-id>
```

This tells Azure CLI to sign in as the user-assigned identity attached to the workload host instead of your personal account.

```bash
az account get-access-token --resource https://vault.azure.net --query expiresOn -o tsv
```

This asks Azure CLI for a Key Vault token and prints the expiration time, which confirms the managed identity can actually mint a token for the target service.

For application code, the [DefaultAzureCredential](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview-for-developers) path is the normal way Azure Identity libraries switch to managed identity in production without changing your application logic.

### Step 5: Remove The Secret

Do not leave the old client secret in place because it is still there.

Your cleanup should be simple:

*   Remove the client secret or password from the [app registration](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals).
    
*   Delete the secret from your vault, CI variables, and deployment files.
    
*   Rotate any dependent credentials that may have copied it.
    
*   Re-run the workload validation after removal.
    

If the app still works after the secret is gone, you are done with the deployment piece.

## Put PIM Around The Humans

Managed identities secure the workload. [Privileged Identity Management (PIM)](https://learn.microsoft.com/en-us/entra/id-governance/privileged-identity-management/pim-getting-started) secures the people. You need both if you want zero standing privilege instead of just prettier standing privilege.

Nobody likes this section because it puts friction where people are used to convenience. That friction is the control.

| Human role | Default state | Why it matters |
| --- | --- | --- |
| Owner | Eligible | No permanent admin |
| User Access Administrator | Eligible | Limits who can widen access |
| Approver | Time-bound | Forces a second check |

Use PIM to:

*   Make `Owner` and `User Access Administrator` eligible, not permanently active.
    
*   Keep activation windows short.
    
*   Review who can activate and who can approve.
    
*   Stop treating “we need it for troubleshooting” as a permanent operating model.
    

If someone can assign managed identities, grant roles, and keep those rights forever, you still have a standing-privilege problem. It just has nicer documentation now.

## Audit Who Can Abuse The Identity

You should also audit who can change the permission model, not just who can use it. That is the part people skip because it feels administrative instead of exciting, which is exactly why it gets ignored.

Use [Azure RBAC role assignments](https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments) to find the humans who can grant or extend access at the scope you care about:

```bash
az role assignment list \
  --scope /subscriptions/<sub-id> \
  --fill-principal-name false \
  --query "[?roleDefinitionName=='Owner' || roleDefinitionName=='User Access Administrator'].[principalName, roleDefinitionName, scope]" \
  -o table
```

That command shows the principals with the power to hand out more access at subscription scope. Run the same pattern at the resource-group or resource scope if your identity only needs a narrow boundary.

| Question | What to check | Where |
| --- | --- | --- |
| Who can assign roles? | Owners and User Access Administrators | Subscription and resource group |
| Who can activate PIM? | Eligible approvers and activators | PIM settings |
| What still has secrets? | App registrations and vaults | Microsoft Entra and Key Vault |

Then ask three simple questions:

*   Who can assign the identity a new role?
    
*   Who can activate PIM for the people who manage this workload?
    
*   Which [app registrations](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals) and service principals still carry secrets that should not exist anymore?
    

If the answers are fuzzy, you do not have an identity problem. You have an ownership problem with a login attached.

## Common Mistakes

The deployment usually fails for the same reasons:

The biggest mistake is treating [managed identities](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) as authorization. It is authentication. [Azure RBAC](https://learn.microsoft.com/en-us/azure/role-based-access-control/) still does the permission work.

| Mistake | Better move |
| --- | --- |
| Keep the old secret “just in case” | Remove it after validation |
| Give the managed identity a subscription-wide role | Scope it to the vault or resource |
| Use a user-based service account for automation | Replace it with a managed identity |
| Skip ownership review | Track who can grant access |

The last line is the one teams miss most often. The identity is clean, but the people around it still can widen access whenever they want.

## Remove The Secret And Keep Privilege Time-Bound

If your Azure workload still depends on a stored secret, the path forward is straightforward: create a managed identity, grant only the role it needs, validate the token flow, and remove the secret from the [app registration](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals). Then use [PIM](https://learn.microsoft.com/en-us/entra/id-governance/privileged-identity-management/pim-getting-started) so the humans stay time-bound too.

The end state is boring in the best way: no password vault entry to manage, and no standing privilege left behind because nobody had time to clean it up. Just one identity model for the workload and one privilege model for the people who manage it. That is what the security team actually wants, even if they make you fill out a form to say it.

Share this article

[Share on X](https://twitter.com/intent/tweet?url=https%3A%2F%2Fadamtheautomator.com%2Fsecure-azure-managed-identities%2F&text=How%20to%20Secure%20Azure%20Service%20Accounts%20with%20Managed%20Identities)[Share on Facebook](https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fadamtheautomator.com%2Fsecure-azure-managed-identities%2F)[Share on LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fadamtheautomator.com%2Fsecure-azure-managed-identities%2F)

## Related Posts

![](https://adamtheautomator.com/wp-content/uploads/2026/08/featured_image-3.webp)

### [Build an Azure Home Lab for Certs Without Overspending](/azure-home-lab-certification-practice/)

Build a nested Azure Hyper-V home lab with budget alerts, a domain controller, and Azure Arc mapped to AZ-900, AZ-104, and AZ-305 exams.

![](https://adamtheautomator.com/wp-content/uploads/2026/04/featured_image-8.webp)

### [Avoid Entra ID Lockouts: Migrate Legacy MFA Policies](/avoid-entra-id-lockouts-migrate-legacy-mfa/)

Learn how to migrate legacy MFA and SSPR policies to the unified Entra ID Authentication Methods policy, including audit, NPS extension fixes, and validation.

![](https://adamtheautomator.com/wp-content/uploads/2026/02/featured_image-17.webp)

### [Control Traffic with Network Security Groups](/control-traffic-network-security-groups/)

Create and manage Azure NSG rules, service tags, and application security groups to control inbound and outbound traffic using Azure CLI.

## Categories

*   [IT Ops](/category/it-ops/)
*   [Cloud](/category/cloud/)
*   [DevOps](/category/devops/)
*   [Home Ops](/category/home-ops/)
*   [Information Security](/category/infosec/)
*   [Software Development](/category/software-development/)

## Site

*   [Home](/)
*   [Tutorials](/tutorials/)
*   [Instructors](/author/)
*   [Advertising](/advertising/)
*   [Recommended Resources](/resources/)
*   [About Adam](/about-adam/)

Copyright 2026© ATA Learning | [Privacy Policy](/privacy/)
