In the November 2023 – What’s New in Microsoft Entra Identity & Security w/ Microsoft Security CxE identity episode, a public preview feature of Entra Workload ID premium license was presented (link) which was actually announced on November 9th (link). I really love the idea of restricting application key credentials to a predefined list of Certificate Authorities, this is why I thought to write some words about it.
TL;DR
– You can generate a report on current keyCredentials usage (with certificate Issuer data) using the PowerShell script below (Graph Powershell used here) [no extra license needed]
– First, you create a certificateBasedApplicationConfigurations object
– Then you can modify the defaultAppManagementPolicy or create an appManagementPolicy and apply it directly to one or more application objects (for the latter, tutorial below)
– These configurations require Entra Workload ID premium license
Reporting on application key credentials
The linked announcements are highlighting how to set the defaultAppManagementPolicy, but before setting this, you may want to know which applications are using certificates to authenticate and which CA issued these certs. This way, you can first change the certificates to the ones you trust, then you can set up the restriction(s). The following script lists these applications and the Issuer of each certificate (for the sake of simplicity, I use the Invoke-MgGraphRequest command)
#https://learn.microsoft.com/en-us/graph/api/resources/keycredential?view=graph-rest-1.0
Connect-MgGraph
##region keyauthapps
$applications_url= 'https://graph.microsoft.com/beta/applications?$top=100'
$obj_applications = $null
while ($applications_url -ne $null){
$response = (Invoke-MgGraphRequest -Method GET -Uri $applications_url)
$obj_applications += $response.value
$applications_url = $response.'@odata.nextLink'
}
#filter apps using keycredentials
$keyauthApps = $obj_applications | ? {$_.keycredentials -ne $null}
#read keycredentialsinfo
$KeyAuthApps_creds =foreach ($app in $keyauthApps){
Invoke-MgGraphRequest -Method GET -Uri https://graph.microsoft.com/beta/applications/$($app.id)?select=keycredentials
}
##region end
##region build report - apps
$report_Apps = foreach ($cred in $KeyAuthApps_creds.keycredentials){
$tmp_appReference = $null
$tmp_appReference = $keyauthApps.Where({$_.keycredentials.keyId -eq $cred.keyId})
[pscustomobject]@{
KeyIdentifier = $cred.customKeyIdentifier
KeyDisplayName = $cred.displayname
KeyStartDateTime = $cred.startDateTime
KeyEndDateTime = $cred.endDateTime
KeyUsage = $cred.usage
KeyType = $cred.type
Issuer = ([system.security.cryptography.x509certificates.x509certificate2]([convert]::FromBase64String($cred.key))).Issuer
EntityID = $tmp_appReference.id
EntityAppId = $tmp_appReference.appid
EntityType = "application"
EntityDisplayName = $tmp_appReference.displayname
}
}
##region end
$report_Apps | Out-GridView
The result will look like this (yes, I use self-signed certificates in my demo environment 🙈):
Note: the Issuer field may not be 100% reliable as it can be inserted manually when creating the self-signed certificate. The following method will show each certificate in the trust chain ($cred variable comes from the foreach loop above):
$tmp_cert = ([system.security.cryptography.x509certificates.x509certificate2]([convert]::FromBase64String($cred.key)))
$certChain = [System.Security.Cryptography.X509Certificates.X509Chain]::new()
$certChain.Build($tmp_cert)
$certChain.ChainElements.certificate
Building the Trusted Certificate Authority policy
To restrict application keyCredentials, the following should be kept in mind (annoncement link again):
– The policy applies only to new credentials, it won’t disable current keys
– At least one root CA needs to be declared and a chain can consist of a max of 10 objects
– First, you create a certificateBasedApplicationConfigurations object (~the trusted cert chain)
– Next, you can modify the defaultAppManagementPolicy to restrict all keyCredentials to this/these trusted CAs (as demonstrated on the linked page)
– OR you can create a separate appManagementPolicy to restrict the trusted CA THEN this policy can be applied directly to one or more applications (steps below)
Creating the certificateBasedApplicationConfigurations object
In this example, I’m going to use Graph Explorer to create the object. As a Windows user, I will simply export my issuing CA’s (F12SUBCA01) certificate and it root CA’s (ROOTCA01) certificate to a Base-64 encoded CER file using the certlm.msc MMC snap-in, open them in Notepad and copy the contents to the Graph Explorer call’s Request body.
Find the issuing CA’s cert, then right-click – All Tasks – Export:
Select “Base-64 encoded X.509 (.CER)” as export file format.
Repeate the same steps for each certificate in the chain.
Now, open the cer files with notepad, remove the ‘—–BEGIN CERTIFICATE—–‘ and ‘—–END CERTIFICATE—–‘ lines and every line-breaks
Or you can use PowerShell:
$cert = get-childitem Cert:\LocalMachine\ca\ | ? {$_.Subject -match "F12SUBCA01"}
[convert]::ToBase64String($cert.RawData)
These values will be used in the payload sent to Microsoft Graph.
CAUTION! Use the beta endpoint for now as it is a preview feature. If you accidentally use the v1.0 endpoint, you will encouter issues (example below)
METHOD: POST
ENDPOINT: beta
URI: https://graph.microsoft.com/beta/certificateAuthoritites/certificateBasedApplicationConfigurations
REQUEST BODY:
{
"displayName": "F12 Cert Chain",
"description": "Allowed App certificates issued by F12SUBCA ",
"trustedCertificateAuthorities": [{
"isRootAuthority": true,
"certificate": "<rootCA base64 certificate data>"
},
{
"isRootAuthority": false,
"certificate": "<subCA base64 certificate data>"
}]
}
If everything was inserted correctly, the response includes an id, take a note of it. If you did not manage to take it, no problem, you can query these configurations as follows:
METHOD: GET
ENDPOINT: beta
URI: https://graph.microsoft.com/beta/directory/certificateAuthorities/certificateBasedApplicationConfigurations
Note: when you dig further, the CA information can be queried for each configuration id, for example (you can omit the ‘?$select=isRootAuthority,issuer’ part if you want to check the certificate data too:
METHOD: GET
ENDPOINT: beta
URI: https://graph.microsoft.com/beta/directory/certificateAuthorities/certificateBasedApplicationConfigurations/<configurationID>/trustedCertificateAuthorities?$select=isRootAuthority,issuer
Creating the appManagementPolicy object
Now that we have the CA configuration, the next step is to create the appManagementPolicy object (if you are not going to apply it in the defaultAppManagementPolicy). The appManagementPolicy can contain restrictions for passwordCredentials and KeyCredentials. In this example, I’m going to create a policy that prohibits passwordCredentials and restricts key credentials to the trusted CA configuration defined above.
METHOD: POST
ENDPOINT: BETA
URI: https://graph.microsoft.com/v1.0/policies/appManagementPolicies
REQUEST BODY:
{
“displayName”: “F12 AppManagementPolicy – F12SUBCA allowed only”,
“description”: “This policy restricts application credentials to certificates issued by F12SUBCA and disables password addition “,
“isEnabled”: true,
“restrictions”: {
“passwordCredentials”: [
{
“restrictionType”: “passwordAddition”,
“maxLifetime”: null
}
],
“keyCredentials”: [
{
“restrictionType”: “trustedCertificateAuthority”,
“certificateBasedApplicationConfigurationIds”: [
“0d60f78e-9916-4db2-9cee-5c8e470a19e9”
]
}
]
}
}
Take a note of the id given in the response as it will be used in the final step.
NOTE: if you accidentally use the v1.0 endpoint, you will encounter issues like this:
Applying the policy to an application
Finally, the policy needs to be applied to an application, as follows:
METHOD: POST
ENDPOINT: BETA
URI:https://graph.microsoft.com/beta/applications/<objectID of application>/appManagementPolicies/$ref
REQUEST BODY:
{
"@odata.id": "https://graph.microsoft.com/beta/policies/appmanagementpolicies/<appManagementPolicyID>"
}
The result for this application:
Closing words: it is a bit cumbersome to configure these settings, but the result is purely satisfying 😊 I hope, once it goes GA it will get some graphical interface to ease the process.