Skip to main content

Deployment Security & ACR Automation — Consolidated Enterprise Guidance

Prepared by: Microsoft Cloud Solution Architecture
Date: April 2026
Audience: Enterprise Platform & Security Teams
Context: Zero Trust CI/CD, Workload Identity Federation, Managed Identity Adoption


Table of Contents

  1. Executive Summary
  2. Question 1 — Enforce Deployments from Azure DevOps / GitHub Using Federated Identities Only
  3. Question 2 — Automate Azure Container Registry Connections Using Managed Identities
  4. Architecture — Secure CI/CD Identity Model
  5. Comparison Table — Service Principal vs Federated Identity vs Managed Identity
  6. Decision Matrix — Identity Type Selection by Use Case
  7. Governance & Enforcement Controls
  8. Migration Rollout Plan
  9. Risks of Inaction
  10. Microsoft Learn Reference Links

1. Executive Summary

The recommended strategic direction is fully aligned with Microsoft Zero Trust and credential reduction best practices:

Strategic DirectionImplementation
Eliminate long-lived secretsReplace secret-based service principals with Workload Identity Federation (OIDC)
Enforce trusted CI/CD onlyOnly allow deployments from authorized Azure DevOps / GitHub pipelines
Use Managed Identities for runtimeAll Azure-hosted workloads authenticate via managed identities
Automate ACR authenticationUse managed identities or federated identities for container image pull/push
Govern with policy + RBACAzure Policy + Entra Conditional Access + PIM for layered enforcement

What is Workload Identity Federation?

Workload Identity Federation (WIF) allows CI/CD pipelines to exchange OIDC tokens for Azure access tokens without storing any secrets. This is the Microsoft-recommended approach for Azure DevOps and GitHub Actions deployments.

Key Benefits:

  • No password or secret rotation needed
  • Short-lived tokens (minutes, not months/years)
  • Strong trust boundary tied to specific repos/branches/environments
  • Pipeline identity traceability in audit logs
  • Immediate revocation by removing federated credential

Reference: Workload Identity Federation is now GA for Azure Pipelines


2. Question 1 — Enforce Deployments from Azure DevOps / GitHub Using Federated Identities Only

Customer Question

"How can we enforce that deployments come only from authorized Azure DevOps or GitHub pipelines, using federated identities, and exclude traditional service principals?"

Use Workload Identity Federation between:

Azure DevOps / GitHub  ←──OIDC──→  Microsoft Entra ID  ←──RBAC──→  Azure Resources

This allows pipelines to authenticate without stored client secrets, using the OIDC protocol.

Step-by-Step: Azure DevOps with Workload Identity Federation

1. Create or Convert Service Connection

For new connections (recommended):

  1. In Azure DevOps: Project SettingsService connectionsNew service connection
  2. Select Azure Resource Manager
  3. Choose Workload identity federation (automatic) — this is now the default
  4. Azure DevOps automatically:
    • Creates an app registration in Entra ID
    • Configures the federated credential
    • Assigns the RBAC role at the selected scope

For existing connections — convert to federation:

  1. Go to Project SettingsService connections
  2. Select the existing service connection
  3. Click Convert to switch from secret-based to workload identity federation
  4. The conversion is reversible within 7 days

Reference: Connect to Azure with ARM service connection

2. Federation Trust Model

The federated credential establishes trust based on:

FieldPurposeExample
IssuerThe OIDC token providerhttps://vstoken.dev.azure.com/<org-id> (Azure DevOps) or https://token.actions.githubusercontent.com (GitHub)
SubjectIdentifies the specific pipeline/repo/branchsc://<org>/<project>/<service-connection> (Azure DevOps) or repo:<org>/<repo>:ref:refs/heads/main (GitHub)
AudienceExpected token audienceapi://AzureADTokenExchange

This means:

  • Only the specific pipeline in the specific project/repo can request tokens
  • Tokens are short-lived and cannot be extracted or reused
  • If a federated credential is removed, the pipeline immediately loses access

Step-by-Step: GitHub Actions with Workload Identity Federation

1. Create Federated Credential

Option A — App Registration:

# Create app registration
az ad app create --display-name "github-deploy-prod"

# Create service principal
az ad sp create --id <app-id>

# Assign RBAC role (scoped to resource group)
az role assignment create \
--role "Contributor" \
--assignee-object-id <sp-object-id> \
--scope /subscriptions/<sub-id>/resourceGroups/<rg-name> \
--assignee-principal-type ServicePrincipal

# Create federated credential
az ad app federated-credential create \
--id <app-object-id> \
--parameters '{
"name": "github-main-branch",
"issuer": "https://token.actions.githubusercontent.com",
"subject": "repo:<org>/<repo>:ref:refs/heads/main",
"audiences": ["api://AzureADTokenExchange"]
}'

Option B — User-Assigned Managed Identity (if app registration is restricted):

# Create managed identity
az identity create --name "github-deploy-identity" --resource-group <rg>

# Configure federated credential on the managed identity
az identity federated-credential create \
--name "github-main" \
--identity-name "github-deploy-identity" \
--resource-group <rg> \
--issuer "https://token.actions.githubusercontent.com" \
--subject "repo:<org>/<repo>:ref:refs/heads/main" \
--audiences "api://AzureADTokenExchange"

2. GitHub Actions Workflow

name: Deploy to Azure
on:
push:
branches: [main]

permissions:
id-token: write # Required for OIDC
contents: read

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Azure Login (OIDC)
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Deploy infrastructure
uses: azure/arm-deploy@v2
with:
resourceGroupName: my-rg
template: ./infra/main.bicep

Reference: GitHub OIDC with Azure
Reference: Entra workload identities overview

Can Traditional Service Principals Be Excluded?

Yes. The recommended governance pattern:

Identity TypeStatusUse Case
Federated identities (OIDC)AllowedAll CI/CD pipeline deployments
Managed identitiesAllowedAll Azure-hosted runtime workloads
Secret-based service principalsRestricted — phase outLegacy only, with exception process
Shared credentials / manual accountsBlockedNot permitted for deployments

How to Restrict Deployments to Authorized Pipelines Only

Implement a layered enforcement model:

Layer 1 — Scope Isolation

  • Separate production deployment scope into dedicated subscriptions / resource groups
  • Apply management group policies at the appropriate level

Layer 2 — RBAC

  • Grant deployment rights only to:
    • Federated pipeline identities
    • Approved managed identities
  • Remove Contributor from legacy service principals
  • Use least-privilege custom roles where possible
# Example: Grant Contributor to federated identity only at RG scope
az role assignment create \
--role "Contributor" \
--assignee <federated-sp-object-id> \
--scope /subscriptions/<sub>/resourceGroups/<rg> \
--assignee-principal-type ServicePrincipal

Layer 3 — Azure Policy

PolicyEffectPurpose
Allowed locationsDenyRestrict resource creation to approved regions
Required tagsDenyEnforce ownership, cost center, environment tags
Allowed SKUsDenyPrevent over-provisioning
Block public IPsDenyNetwork security baseline
Audit unmanaged identitiesAuditIdentify workloads not using managed identity

Layer 4 — Branch Protection (Source Control)

ControlAzure DevOpsGitHub
PR approvals requiredYes (branch policies)Yes (branch protection rules)
Minimum reviewersConfigurableConfigurable
Required status checksBuild validationRequired checks
No direct push to mainEnforced via policiesEnforced via protection rules
Signed commitsSupportedSupported

Layer 5 — Entra Conditional Access for Workload Identities

Microsoft Entra now supports Conditional Access policies targeting workload identities (service principals):

  • Block access from unexpected locations
  • Block access when risk is detected (leaked credentials, anomalous behavior)
  • Applies to single-tenant service principals registered in your tenant

Reference: Conditional Access for workload identities

Layer 6 — PIM (Privileged Identity Management)

Use Microsoft Entra PIM for:

  • Just-in-time (JIT) elevation for emergency admin access
  • Time-bound role assignments with approval workflows
  • Audit trail for all privilege escalations

Reference: What is Privileged Identity Management?


3. Question 2 — Automate Azure Container Registry Connections Using Managed Identities

Customer Question

"How can we automate Azure Container Registry connections using managed identities instead of service principals?"

For all Azure-hosted workloads pulling or pushing container images, replace service principal credentials with managed identities.

ACR Authentication Methods — Comparison

MethodSecurityRotationRecommended
Admin accountWeak — shared passwordManualNo — disable for production
Service principal + secretMedium — secret can leakManual (1-2 year expiry)No — phase out
Service principal + certificateBetter — cert-basedManual rotationTransitional only
Managed identityStrong — no credentials to manageAutomatic (Azure-managed)Yes — for runtime workloads
Federated identity (OIDC)Strong — short-lived tokensAutomaticYes — for CI/CD pipelines

ACR RBAC Roles

RolePermissionTypical Use
AcrPullPull images onlyRuntime workloads (AKS, App Service, Container Apps)
AcrPushPush + Pull imagesBuild agents, CI/CD pipelines
AcrDeleteDelete imagesCleanup automation only
ContributorFull registry managementRegistry admins only

Principle: Runtime apps should have AcrPull only. Only build/CI pipelines need AcrPush.

Scenario-by-Scenario Implementation

Scenario 1: AKS Pulling Images from ACR

Recommended: Use the AKS–ACR integration with managed identity.

# Option A: Attach ACR during cluster creation
az aks create \
--name myAKSCluster \
--resource-group myRG \
--attach-acr myACR

# Option B: Attach ACR to existing cluster
az aks update \
--name myAKSCluster \
--resource-group myRG \
--attach-acr myACR

This automatically:

  • Creates or uses the kubelet managed identity
  • Assigns AcrPull role to the kubelet identity on the ACR
  • No secrets stored anywhere

For advanced scenarios (cross-subscription ACR):

# Get kubelet identity
KUBELET_ID=$(az aks show -n myAKS -g myRG --query identityProfile.kubeletidentity.objectId -o tsv)

# Assign AcrPull on cross-subscription ACR
az role assignment create \
--role AcrPull \
--assignee-object-id $KUBELET_ID \
--scope /subscriptions/<acr-sub>/resourceGroups/<acr-rg>/providers/Microsoft.ContainerRegistry/registries/<acr-name> \
--assignee-principal-type ServicePrincipal

Reference: AKS + ACR integration

Scenario 2: App Service Pulling Images from ACR

Recommended: Use system-assigned or user-assigned managed identity.

# Enable system-assigned managed identity
az webapp identity assign --name myApp --resource-group myRG

# Get identity principal ID
PRINCIPAL_ID=$(az webapp identity show --name myApp --resource-group myRG --query principalId -o tsv)

# Assign AcrPull
az role assignment create \
--role AcrPull \
--assignee-object-id $PRINCIPAL_ID \
--scope <acr-resource-id> \
--assignee-principal-type ServicePrincipal

# Configure App Service to use managed identity for ACR
az webapp config set \
--name myApp \
--resource-group myRG \
--generic-configurations '{"acrUseManagedIdentityCreds": true}'

Reference: App Service custom container with managed identity

Scenario 3: Container Apps Pulling Images from ACR

Recommended: Use user-assigned managed identity (preferred) or system-assigned.

# Create user-assigned managed identity
az identity create --name acr-pull-identity --resource-group myRG

# Get identity details
IDENTITY_ID=$(az identity show --name acr-pull-identity --resource-group myRG --query id -o tsv)
PRINCIPAL_ID=$(az identity show --name acr-pull-identity --resource-group myRG --query principalId -o tsv)

# Assign AcrPull
az role assignment create \
--role AcrPull \
--assignee-object-id $PRINCIPAL_ID \
--scope <acr-resource-id> \
--assignee-principal-type ServicePrincipal

# Create container app with managed identity image pull
az containerapp create \
--name myApp \
--resource-group myRG \
--environment myEnv \
--image myacr.azurecr.io/myapp:latest \
--registry-server myacr.azurecr.io \
--registry-identity $IDENTITY_ID \
--user-assigned $IDENTITY_ID

Reference: Container Apps managed identity image pull

Scenario 4: Azure DevOps Pipelines Pushing Images to ACR

Recommended: Use federated identity (OIDC) from Azure DevOps, then assign AcrPush.

# Assign AcrPush to the federated pipeline identity
az role assignment create \
--role AcrPush \
--assignee <federated-sp-object-id> \
--scope <acr-resource-id> \
--assignee-principal-type ServicePrincipal

No static SP credentials in service connections. The pipeline uses OIDC to get short-lived tokens.

Scenario 5: GitHub Actions Pushing Images to ACR

name: Build and Push to ACR
on:
push:
branches: [main]

permissions:
id-token: write
contents: read

jobs:
build-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Azure Login (OIDC)
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

- name: Login to ACR
run: az acr login --name myacr

- name: Build and Push
run: |
docker build -t myacr.azurecr.io/myapp:${{ github.sha }} .
docker push myacr.azurecr.io/myapp:${{ github.sha }}

Architecture — ACR Identity Model


4. Architecture — Secure CI/CD Identity Model

End-to-End Zero Trust Deployment Architecture


5. Comparison Table — Service Principal vs Federated Identity vs Managed Identity

FeatureSecret-Based Service PrincipalFederated Identity (OIDC)Managed Identity
Credential typeClient secret or certificateOIDC token (short-lived)Azure-managed (no user access)
Secret storageMust store in DevOps/GitHub/KVNone — tokenized at runtimeNone — Azure manages automatically
Rotation requiredYes — every 1-2 yearsNoNo
Leak riskHigh — secret can be extractedVery low — tokens are ephemeralVery low — no credentials exposed
Scope controlRBACRBAC + federated credential subjectRBAC
AuditabilityMediumHigh — tied to specific pipelineHigh — tied to Azure resource
Use caseLegacy CI/CD, external systemsCI/CD pipelines (ADO, GitHub)Azure-hosted runtime workloads
Entra Conditional AccessYes (workload identity policies)YesLimited (system-assigned)
Microsoft recommendationPhase outRecommended for CI/CDRecommended for runtime

6. Decision Matrix — Identity Type Selection by Use Case

Use CaseRecommended IdentityRBAC RoleNotes
Azure DevOps → Deploy to AzureFederated identity (OIDC)Contributor (scoped)Use automatic service connection
GitHub Actions → Deploy to AzureFederated identity (OIDC)Contributor (scoped)Configure federated credential
Azure DevOps → Push image to ACRFederated identity (OIDC)AcrPushNo static credentials
GitHub Actions → Push image to ACRFederated identity (OIDC)AcrPushNo static credentials
AKS → Pull image from ACRKubelet managed identityAcrPullUse az aks update --attach-acr
App Service → Pull image from ACRSystem-assigned managed identityAcrPullEnable MI on App Service
Container Apps → Pull image from ACRUser-assigned managed identityAcrPullPreferred over system-assigned
Azure Functions → Access StorageSystem-assigned managed identityStorage Blob Data ContributorBuilt-in support
Any workload → Access Key VaultManaged identityKey Vault Secrets UserNo secrets needed
Human admin → Emergency accessPIM JIT elevationScoped role + time-boundRequires MFA + approval
External system → Access AzureService principal (last resort)Minimal RBAC scopeOnly with exception + monitoring

7. Governance & Enforcement Controls

Enterprise Identity Policy — Target State

CategoryAllowedRestrictedBlocked
CI/CD deploymentsFederated identities (OIDC)Secret-based SPs, manual accounts
Runtime workloadsManaged identitiesService principals with secrets
Admin accessPIM JIT with MFAPermanent Contributor/Owner
ACR image pullManaged identityAdmin account, shared SPs
ACR image pushFederated identity (CI/CD)Managed identity (build agent)Admin account

Azure Policy Recommendations

PolicyEffectPurpose
Audit service connections without WIFAuditIdentify legacy secret-based connections
Key Vaults should have soft delete enabledDenyProtect against accidental deletion
Storage accounts should restrict network accessDenyNetwork security
Kubernetes clusters should use managed identitiesAuditIdentify non-MI AKS clusters
App Service should use managed identityAuditIdentify non-MI App Services
ACR should not allow admin userDenyBlock admin account usage

Entra Conditional Access for Workload Identities

Create policies that target service principals:

  1. Block access from unexpected locations — if service principal activity is seen from non-Azure IPs
  2. Block access when risk detected — if Entra ID Protection flags leaked credentials or anomalous patterns
  3. Enforce continuous access evaluation (CAE) — revoke tokens in near real-time when conditions change

Reference: Conditional Access for workload identities
Reference: Securing workload identities


8. Migration Rollout Plan

Phase 1 — Discovery & Inventory (Weeks 1-2)

ActionDetails
Inventory all service principalsList all SPNs, note secret expiry dates, privilege levels, usage frequency
Identify high-risk SPNsSecrets expiring soon, overprivileged, shared across teams
Map CI/CD service connectionsCatalog all Azure DevOps / GitHub service connections and their auth method
Catalog ACR authentication methodsIdentify which workloads use admin account, SP, or managed identity

Phase 2 — Replace CI/CD Credentials (Weeks 3-6)

ActionDetails
Convert Azure DevOps service connectionsUse the built-in Convert button — one-click migration to WIF
Create GitHub federated credentialsConfigure OIDC for each repo/environment that deploys to Azure
Test pipeline deploymentsVerify all pipelines work with federated authentication
Remove old secretsAfter validation, delete legacy client secrets from app registrations

Phase 3 — Replace Runtime Credentials (Weeks 7-10)

ActionDetails
Enable managed identities on AKSaz aks update --attach-acr for each cluster
Enable managed identities on App ServicesAssign system MI + configure ACR to use MI
Enable managed identities on Container AppsCreate user-assigned MI + configure image pull
Replace Key Vault access with MISwitch from SP-based access policies to RBAC + managed identity
Replace Storage access with MISwitch connection strings to DefaultAzureCredential

Phase 4 — Enforce & Govern (Weeks 11-12)

ActionDetails
Deploy Azure PoliciesAudit/deny non-compliant identity usage
Enable Conditional Access for workload identitiesBlock risky or anomalous service principal behavior
Establish exception processFormal process for any remaining secret-based SP with business justification
Enforce: no new secret-based SPNsPolicy + governance review

Rollout Timeline


9. Risks of Inaction

RiskImpactLikelihood
Secret leakageUnauthorized access to production Azure resourcesHigh — secrets in repos, pipelines, logs
Forgotten credentialsExpired secrets cause deployment failuresHigh — common operational issue
Overprivileged SPNsLateral movement if compromisedMedium — often Contributor at subscription level
No accountabilityCannot trace who/what triggered a deploymentMedium — shared SPNs obscure audit trail
Manual rotation burdenOperational overhead, risk of outage during rotationHigh — especially at scale
Compliance gapsFailure to meet Zero Trust or regulatory requirementsMedium — depends on industry

Workload Identity Federation

TopicURL
Azure DevOps — Connect to Azure (WIF)https://learn.microsoft.com/azure/devops/pipelines/library/connect-to-azure
Azure DevOps — WIF GA announcementhttps://devblogs.microsoft.com/devops/workload-identity-federation-for-azure-deployments-is-now-generally-available/
Azure DevOps — Entra workload identity service connectionhttps://learn.microsoft.com/azure/devops/pipelines/library/add-devops-entra-service-connection
GitHub — Connect to Azure with OIDChttps://learn.microsoft.com/azure/developer/github/connect-from-azure-openid-connect
GitHub — Deploy to App Service with GitHub Actionshttps://learn.microsoft.com/azure/app-service/deploy-github-actions
GitHub — Deploy Bicep with GitHub Actionshttps://learn.microsoft.com/azure/azure-resource-manager/bicep/deploy-github-actions
Entra — Workload identities overviewhttps://learn.microsoft.com/entra/workload-id/workload-identities-overview
Entra — Create trust for federated credentialhttps://learn.microsoft.com/entra/workload-id/workload-identity-federation-create-trust
Entra — WIF with Entra-issued tokens (roadmap)https://learn.microsoft.com/azure/devops/release-notes/roadmap/2025/workload-identity-federation

Azure Container Registry + Managed Identity

TopicURL
AKS — ACR integration (managed identity)https://learn.microsoft.com/azure/aks/cluster-container-registry-integration
App Service — ACR with managed identityhttps://learn.microsoft.com/azure/app-service/configure-custom-container
Container Apps — ACR managed identity image pullhttps://learn.microsoft.com/azure/container-apps/managed-identity-image-pull
ACR — Authentication options overviewhttps://learn.microsoft.com/azure/container-registry/container-registry-authentication
ACR — Service principal authenticationhttps://learn.microsoft.com/azure/container-registry/container-registry-auth-service-principal
ACR — Managed identity in ACR Taskshttps://learn.microsoft.com/azure/container-registry/container-registry-tasks-authentication-managed-identity

Identity Governance & Security

TopicURL
Conditional Access for workload identitieshttps://learn.microsoft.com/entra/identity/conditional-access/workload-identity
Conditional Access — Planning guidehttps://learn.microsoft.com/entra/identity/conditional-access/plan-conditional-access
Securing workload identities (ID Protection)https://learn.microsoft.com/entra/id-protection/concept-workload-identity-risk
Privileged Identity Management (PIM)https://learn.microsoft.com/entra/id-governance/privileged-identity-management/pim-configure
PIM deployment planhttps://learn.microsoft.com/entra/id-governance/privileged-identity-management/pim-deployment-plan
Managed identities overviewhttps://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview
Azure RBAC best practiceshttps://learn.microsoft.com/azure/role-based-access-control/best-practices
WAF — Identity and access managementhttps://learn.microsoft.com/azure/well-architected/security/identity-access

Closing Recommendation

The customer's proposal is fully aligned with Microsoft best practices:

  • Federated identities for CI/CD pipelines (Azure DevOps + GitHub)
  • Managed identities for all Azure-hosted runtime workloads
  • Least-privilege RBAC scoped to specific resource groups
  • Azure Policy + Conditional Access guardrails
  • PIM for emergency admin access
  • Phased removal of legacy secret-based service principals

This approach eliminates credential leakage risk, reduces operational overhead, and establishes a strong Zero Trust posture for deployment operations.


Document prepared based on Microsoft Learn documentation as of April 2026. Service capabilities evolve — always verify against the latest Microsoft Entra and Azure DevOps documentation.

📖Learn