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:
- Identify the application owner so credential changes are coordinated (see APP-01).
- Confirm the application runtime supports certificate authentication. Most modern SDKs (MSAL, Microsoft Graph SDKs) support it directly.
- Choose a certificate source. Azure Key Vault is preferred for production; self-signed certificates are acceptable for development and testing.
- Plan a maintenance window for the cutover in case rollback is needed.
Time Estimate
| Task | Duration |
|---|---|
| Inventory apps using client secrets | 30-60 minutes |
| Per-application certificate migration | 30-60 minutes |
| Testing and validation per app | 15-30 minutes |
| Remove legacy secrets after validation | 5-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
- Navigate to the Microsoft Entra admin center (https://entra.microsoft.com).
- Go to Identity > Applications > App registrations and select the application.
- Open Certificates & secrets > Certificates.
- Click Upload certificate and select the
.cerpublic key file. - 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:
- Return to Certificates & secrets > Client secrets.
- Delete each client secret the application no longer uses.
- 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:
- Confirm the app code was updated to load the certificate, not the secret.
- Verify the runtime identity can read the private key from Key Vault or the local store.
- 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:
- Export the public key only, as a
.cerfile. - 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:
- Check whether workload identity federation is an option instead (see APP-10). Federation removes credentials entirely and is preferred where the runtime supports it.
- 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:
- Use Azure Key Vault with auto-renewal to avoid manual tracking.
- Add a monitored expiration alert for certificates managed outside Key Vault.
- 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)