APP-09: Workload Identity Federation & Certificate Credentials

Overview

Client secrets are the weakest link in application authentication. They are frequently compromised through accidental commits to source code, exposure in application logs, phishing attacks targeting developers, or insecure sharing via email and chat. Once a secret leaks, it stays valid until it expires or is manually revoked, giving an attacker persistent access that bypasses MFA entirely.

Certificate credentials remove this class of risk. They use a cryptographic key pair where the private key remains secured on your infrastructure and never needs to be transmitted or shared. Microsoft's Baseline Security Mode now blocks password-based credentials on applications, so migrating away from client secrets also keeps you aligned with the platform's own direction.

This control assesses whether your applications authenticate with certificate credentials rather than client secrets. The expected state is:

  • Applications use certificate credentials instead of client secrets.
  • Client secrets are only used during certificate migration periods.
  • No applications rely solely on client secrets for authentication.

Control ID: APP-09 Category: Workload Identity & Applications Baseline Level: Level 1 (Recommended Secure) Severity: Medium License Required: None. Microsoft Entra ID (any tier), included with all Microsoft 365 subscriptions. Azure Key Vault is recommended but optional.

This is an advisory, manual control. TrueConfig identifies applications that rely on client secrets and flags them for migration. It does not auto-remediate, because removing an active secret before its replacement is wired in would break the application. You migrate each application deliberately, then remove the old secret once certificate authentication is confirmed working.


Prerequisites

Required Roles

  • Application Administrator - Can manage credentials for most applications
  • Cloud Application Administrator - Can manage credentials (excluding app proxy)
  • Application Owner - Can manage credentials for owned applications
  • Global Administrator - Full access, use only when a scoped role is not available

Required Licenses

  • Microsoft Entra ID, any tier
  • Azure Key Vault (optional, recommended for storing and rotating certificates)

Pre-Migration Requirements

Before migrating an application:

  1. Identify the application owner so credential changes are coordinated (see APP-01).
  2. Confirm the application runtime supports certificate authentication. Most modern SDKs (MSAL, Microsoft Graph SDKs) support it directly.
  3. Choose a certificate source. Azure Key Vault is preferred for production; self-signed certificates are acceptable for development and testing.
  4. Plan a maintenance window for the cutover in case rollback is needed.

Time Estimate

TaskDuration
Inventory apps using client secrets30-60 minutes
Per-application certificate migration30-60 minutes
Testing and validation per app15-30 minutes
Remove legacy secrets after validation5-10 minutes per app

Step-by-Step Instructions

Step 1: Inventory Applications Using Client Secrets

Identify which applications hold password credentials (client secrets) versus key credentials (certificates).

Connect-MgGraph -Scopes "Application.Read.All"

$apps = Get-MgApplication -All -Property DisplayName, AppId, Id, PasswordCredentials, KeyCredentials

$report = foreach ($app in $apps) {
    [PSCustomObject]@{
        DisplayName    = $app.DisplayName
        AppId          = $app.AppId
        SecretCount    = $app.PasswordCredentials.Count
        CertCount      = $app.KeyCredentials.Count
        SecretsOnly    = ($app.PasswordCredentials.Count -gt 0 -and $app.KeyCredentials.Count -eq 0)
    }
}

$report | Where-Object SecretsOnly | Sort-Object DisplayName | Format-Table -AutoSize
$report | Export-Csv "app-credential-inventory.csv" -NoTypeInformation

Applications where SecretsOnly is true are the priority. They authenticate exclusively with client secrets and have no certificate fallback.

Step 2: Generate a Certificate

Option A: Azure Key Vault (recommended for production)

$vaultName = "your-keyvault-name"
$certName  = "app-auth-cert"

$policy = New-AzKeyVaultCertificatePolicy `
    -SubjectName "CN=MyApp-Auth" `
    -IssuerName "Self" `
    -ValidityInMonths 12 `
    -ReuseKeyOnRenewal

Add-AzKeyVaultCertificate -VaultName $vaultName -Name $certName -CertificatePolicy $policy

Key Vault handles storage, access control, and renewal, and the private key never leaves the vault.

Option B: Self-signed certificate (development and testing)

$cert = New-SelfSignedCertificate `
    -Subject "CN=MyApp-Auth-Cert" `
    -CertStoreLocation "Cert:\CurrentUser\My" `
    -KeyExportPolicy Exportable `
    -KeySpec Signature `
    -KeyLength 2048 `
    -KeyAlgorithm RSA `
    -HashAlgorithm SHA256 `
    -NotAfter (Get-Date).AddYears(1)

# Public key for upload to Entra ID
Export-Certificate -Cert $cert -FilePath ".\MyApp-Auth-Cert.cer"

Step 3: Upload the Certificate to the Application

  1. Navigate to the Microsoft Entra admin center (https://entra.microsoft.com).
  2. Go to Identity > Applications > App registrations and select the application.
  3. Open Certificates & secrets > Certificates.
  4. Click Upload certificate and select the .cer public key file.
  5. Click Add.

Only the public key is uploaded. The private key stays in Key Vault or your local certificate store.

Step 4: Update the Application to Use Certificate Authentication

Reconfigure the application code to authenticate with the certificate. With MSAL, this means supplying the certificate instead of a client secret when building the confidential client.

Test the change in a non-production environment first. Both the certificate and the old secret can remain on the app registration during this phase, so the application keeps working if you need to roll back.

Step 5: Remove Legacy Client Secrets

Once certificate authentication is confirmed working in production:

  1. Return to Certificates & secrets > Client secrets.
  2. Delete each client secret the application no longer uses.
  3. Re-run the Step 1 inventory to confirm the application now shows a certificate and zero secrets.
Connect-MgGraph -Scopes "Application.ReadWrite.All"
Remove-MgApplicationPassword -ApplicationId "<app-object-id>" -KeyId "<secret-key-id>"

Do not remove a secret until you have verified the certificate is in use. Removing an active secret first is the most common cause of an outage during this migration.


Verification Checklist

  • Every application using client secrets has been inventoried.
  • Priority applications (secrets only, no certificate) have been identified.
  • A certificate has been generated and stored securely for each migrated app.
  • The certificate public key is uploaded to the app registration.
  • The application authenticates successfully with the certificate in production.
  • Legacy client secrets have been removed after validation.
  • A certificate renewal schedule is documented (or Key Vault auto-renewal is enabled).
  • TrueConfig no longer flags the application under APP-09.

Troubleshooting

Issue: Application fails to authenticate after switching to the certificate

Cause: The application code still references the client secret, or the certificate private key is not accessible to the runtime.

Solution:

  1. Confirm the app code was updated to load the certificate, not the secret.
  2. Verify the runtime identity can read the private key from Key Vault or the local store.
  3. Keep the old secret in place until the certificate path is confirmed, then remove it.

Issue: Certificate upload is rejected

Cause: The file contains a private key or is not in X.509 format.

Solution:

  1. Export the public key only, as a .cer file.
  2. Confirm the certificate is valid and not expired:
    $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2(".\MyApp-Auth-Cert.cer")
    $cert | Format-List Subject, Issuer, NotBefore, NotAfter
    

Issue: The application runtime does not support certificate authentication

Cause: Some legacy or third-party applications only accept client secrets.

Solution:

  1. Check whether workload identity federation is an option instead (see APP-10). Federation removes credentials entirely and is preferred where the runtime supports it.
  2. If neither certificates nor federation are supported, keep the secret lifetime short (12 months or less, see APP-02) and document the exception.

Issue: Certificate expired and the application stopped working

Cause: No renewal process was in place.

Solution:

  1. Use Azure Key Vault with auto-renewal to avoid manual tracking.
  2. Add a monitored expiration alert for certificates managed outside Key Vault.
  3. Register the renewed certificate before the current one expires so there is no gap.

Cost Considerations

There is no additional Microsoft licensing cost for this control. Certificate credentials work on any Microsoft Entra ID tier.

The cost is operational:

  • Certificate lifecycle management. Certificates expire and must be renewed. Azure Key Vault reduces this overhead through automated renewal at a small per-operation cost. Self-managed certificates require a tracked renewal process.
  • One-time migration effort. Each application needs a code change and a test cycle. Budget roughly one to two hours per application.
  • Avoided cost. A leaked long-lived client secret can lead to tenant compromise. The migration effort is small relative to the incident response cost of a credential breach.

Related Controls

  • APP-02: Enforce Application Credential Expiration (limit secret lifetime where secrets remain)
  • APP-05: Service Principal Credential Hygiene (rotate and shorten service principal credentials)
  • APP-10: Workload Identity Federation Adoption (eliminate credentials entirely where supported)

Related Resources