Azure AD - Cannot set Application Registration Key Credential with Type "Sign" - powershell

I'm trying to set a custom signing key for an Azure AD Application Registration. However, I get a confusing error message and cannot complete the request.
I tried to set the credential using multiple strategies:
PowerShell New-AzureADApplicationKeyCredential command
Microsoft Graph API
Manipulating the Application Registrations Manifest directly in Azure Portal
Microsoft Graph returns a simple "Bad Request", whereas PowerShell and Azure Portal are more specific in their responses:
"The value for the property "usage" in one of your credentials is invalid. Acceptable values are Sign, Verify."
The interesting thing about this error is that I am specifying the usage as "Sign".
PowerShell code snippet:
$appObjectID = $appRegistration.ObjectId
$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$cer.Import("<path-to-certificate>")
$bin = $cer.GetRawCertData()
$base64Value = [System.Convert]::ToBase64String($bin)
$bin = $cer.GetCertHash()
$base64Thumbprint = [System.Convert]::ToBase64String($bin)
New-AzureADApplicationKeyCredential `
-ObjectId $appObjectID `
-CustomKeyIdentifier $base64Thumbprint `
-Type AsymmetricX509Cert `
-Usage Sign `
-Value $base64Value `
-StartDate $cer.GetEffectiveDateString() `
-EndDate $cer.NotAfter.ToString()
Error message:
Code: Request_BadRequest
Message: The value for the property "usage" in one of your credentials is invalid. Acceptable values are Sign, Verify.
RequestId: <id>
DateTimeStamp: <timestamp>
Details: PropertyName - keyCredentials.keyId, PropertyErrorCode - InvalidKeyUsage
HttpStatusCode: BadRequest
HttpStatusDescription: Bad Request
HttpResponseStatus: Completed`
This is based on the documentation: MS Docs: New-AzureADApplicationKeyCredential. However, I think there is a mistake in this documentation, since they use a randomly generated GUID as input for the parameter ObjectID, which should be the ObjectID of the Application Registration I want to add the new key credential to. So I replaced this keyId with the ObjectId of my Application Registration. (If I directly use the code from MS Docs, I get a "Request_ResourceNotFound" error because the command can't find the Application Registration with this random GUID in Azure AD.)
Things I have tried:
Change -Usage Sign to -Usage "Sign"
Adding a "Verify" credential to the App (works as expected) with this command
When I try to directly modify the Manifest in Azure Portal, I basically get the same error message:
Failed to update <app-name> application. Error detail: The value for the property "usage" in one of your credentials is invalid. Acceptable values are Sign, Verify.
Screenshot from error in Azure Portal
Is there maybe a issue that some parameters cannot be used this way when setting a "Sign" credential?
Thanks in advance for any help and regards!

Thanks to Ash (see his comment to my initial question) I found the solution in this article. I followed the tutorial and could set the "Sign" Key Credential using Graph API after also including a "Verify" Key Credential and a corresponding Password Credential into the request body.

Related

Azure Function Powershell using Ms-Graph and certificate authentication

I want to run an Azure function against AAD to query some users there. Authentications should happen via certificate as shown in the code snippet. I keep googling around but cannot find the proper way of doing it. The code shown below ends up in an exection - how do I need to parse the cert coming from Azure Key Vault?
...
$tenant_id = "something-else"
$app_reg_clientid = "something"
$cert = Get-AzKeyVaultCertificate -VaultName "my-kv" -Name "my-kv-cert"
Connect-MgGraph -ClientId $app_reg_clientid -TenantId $tenant_id -Certificate $cert
...
ERROR: Cannot bind parameter 'Certificate'. Cannot convert the "Microsoft.Azure.Commands.KeyVault.Models.PSKeyVaultCertificate" value of type "Microsoft.Azure.Commands.KeyVault.Models.PSKeyVaultCertificate" to type "System.Security.Cryptography.X509Certificates.X509Certificate2". Exception ...
I think this summarizes the things: https://briantjackett.com/2018/07/25/azure-functions-calling-azure-ad-application-with-certificate-authentication/
Also I am missing a lot of steps in your post when comparing against the official documentation: https://learn.microsoft.com/en-us/powershell/microsoftgraph/app-only?view=graph-powershell-1.0&tabs=azure-portal
The official docs use the subjectname from the certificate in the parameter: -CertificateName
You are using; Well I don't know exactly, but if i'm not mistaken; You are using the thumbprint which is pulled from the Keyvault for parameter: -Certificate
I think you should double back and check all the steps from the official docs for your flow.

Getting "Bad request" error or "NoRegisteredProviderFound" while deploying Key Vault Certificate (self signed) into Web App

Created Key-Vault & provided the authorization to the RP Service Principal (application registered at AzureAD) by executing the Power Shell command. Key-Vault details is given below -
Vault Name : MyKeyVaultTest
Resource ID: /subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/ providers/Microsoft.KeyVault/vaults/MyKeyVaultTest
Access Policies :
Tenant ID : d29bcd12-3280-4f37-b8f2-6e9e2f581472
Object ID : daccd2fd-835a-4c03-8336-c5fcf481f3cc
Application ID : 172f36fc-a098-47a1-9c83-04016d3e9781
Permissions to Keys : Get, List, Update, Create, Import, Delete, Recover, Backup, Restore, Decrypt, Encrypt, UnwrapKey, WrapKey, Verify, Sign, Purge
Permissions to Secrets : Get, List, Set, Delete, Recover, Backup, Restore, Purge
Permissions to Certificates : Get, List, Update, Create, Import, Delete, ManageContacts, ManageIssuers, GetIssuers, ListIssuers, SetIssuers, DeleteIssuers
Permissions to (Key Vault Managed) Storage :
Created a self signed Certificate using below mentioned Power Shell script -
$cert = New-SelfSignedCertificate -certstorelocation cert:\localmachine\my -dnsname XXXXXXXtechmahindra.onmicrosoft.com
$pwd = ConvertTo-SecureString -String ‘XXXXXX#1234#’ -Force -AsPlainText
$path = 'cert:\localmachine\my\' + $cert.thumbprint
Export-PfxCertificate -cert $path -FilePath c:\temp\cert.pfx -Password $pwd
Added same certificate to Key-Vault and got the Secret named "mykeyvaulttestwebappPK" having content type "application/x-pkcs12.
Then enable ARM Client and executing below mentioned script to deploy Key Vault Certificate into Web App named "MyKeyVaultTestWebApp" which is giving error. Script and Errors are given below -
1. Script without changing the API version:
ARMClient.exe PUT /subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.Web/certificates/keyvaultcertificate?api-version=2016-03-01 "{'Location':'SouthCentralUS','Properties':{'KeyVaultId':'/subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.KeyVault/vaults/MyKeyVaultTest', 'KeyVaultSecretName':'mykeyvaulttestwebappPK', 'serverFarmId':'/subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.Web/serverfarms/MyKeyVaultTestWebAppServicePlan'}}"
"Code": "BadRequest",
"Message": "The service does not have access to '/subscriptions/*****-*****-*****-*****-**********/resourcegroups/rg-scotia-scale-test/providers/microsoft.keyvault/vaults/mykeyvaulttest' Key Vault. Please make sure that you have granted necessary permissions to the service to perform the request operation."
2. Script with the Serverfarm’s API version:
ARMClient.exe PUT /subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.Web/certificates/keyvaultcertificate?api-version=2016-09-01 "{'Location':'SouthCentralUS','Properties':{'KeyVaultId':'/subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.KeyVault/vaults/MyKeyVaultTest', 'KeyVaultSecretName':'mykeyvaulttestwebappPK', 'serverFarmId':'/subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.Web/serverfarms/MyKeyVaultTestWebAppServicePlan'}}"
"code": "NoRegisteredProviderFound",
"message": "No registered resource provider found for location 'SouthCentralUS' and API version '2016-09-01' for type 'certificates'.
3. Script with the Key-Vault’s API version:
ARMClient.exe PUT /subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.Web/certificates/keyvaultcertificate?api-version=2015-06-01 "{'Location':'SouthCentralUS','Properties':{'KeyVaultId':'/subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.KeyVault/vaults/MyKeyVaultTest', 'KeyVaultSecretName':'mykeyvaulttestwebappPK', 'serverFarmId':'/subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.Web/serverfarms/MyKeyVaultTestWebAppServicePlan'}}"
"Code": "BadRequest",
"Message": "The service does not have access to '/subscriptions/*****-*****-*****-*****-**********/resourcegroups/rg-scotia-scale-test/providers/microsoft.keyvault/vaults/mykeyvaulttest' Key Vault. Please make sure that you have granted necessary permissions to the service to perform the request operation."
[N.B.: Referred "https://blogs.msdn.microsoft.com/appserviceteam/2016/05/24/deploying-azure-web-app-certificate-through-key-vault/" used to implement the changes]
According to your error message, I guess you may not enable the 'Microsoft.Web' Resource Provider directly access the azure key Vault.
So you will face you could have the enough permission to access to the key vault error.
I suggest you could follow below powershell codes to enable the permission.
Then you could set the certificate in azure web app.
Codes like this:
Login-AzureRmAccount
Set-AzureRmContext -SubscriptionId AZURE_SUBSCRIPTION_ID
Set-AzureRmKeyVaultAccessPolicy -VaultName KEY_VAULT_NAME -ServicePrincipalName abfa0a7c-a6b6-4736-8310-5855508787cd -PermissionsToSecrets get
Then you could call this codes to add the certificate:
ARMClient.exe PUT /subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.Web/certificates/keyvaultcertificate?api-version=2016-03-01 "{'Location':'SouthCentralUS','Properties':{'KeyVaultId':'/subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.KeyVault/vaults/MyKeyVaultTest', 'KeyVaultSecretName':'mykeyvaulttestwebappPK', 'serverFarmId':'/subscriptions/*****-*****-*****-*****-**********/resourceGroups/XXX-YYY-ZZZ/providers/Microsoft.Web/serverfarms/MyKeyVaultTestWebAppServicePlan'}}"
Result:

Error when using CmdLet New-AzureRmADAppCredential to create new credential with certificates

I am trying to use the New-AzureRmADAppCredential cmdlet. I am trying to create a new credential using the following syntax:
New-SelfSignedCertificateEx -Subject "CN=$ClientId" -KeySpec "Exchange" -FriendlyName "$ClientId"
$start = (Get-Date).ToUniversalTime()
$end = $start.AddDays(4)
New-AzureRmADAppCredential -ApplicationId $application.ObjectId -CertValue $keyValue -StartDate $start -EndDate $end
I've noticed that if I try to create a new credential with a certificate, it failed on a specific apps with the following error:
New-AzureRmADAppCredential : Update to existing credential with KeyId 'keyid' is not allowed.
This app has 2 credentials, one is a password and the other is a certificate. The keyid belong to the certificate credential. The weird part is that on other app it worked fine, even if the app has multiple certificate credentials. I've tried to look at the documentation, but couldn't find anything useful.
So, my question is - why this error happens? and how I can solve this?
Update: By looking in the code of the cmdlet, it seems like it always updating the whole list, so I think it might be something related to permission, but I am not sure.
Thanks,
Omer
Yeah, New-AzureRmADAppCredential isn't strong enough, if AAD App has keys, it will update the latest key in the key list and of course won't work(Update to existing credential with KeyId is not allowed), I think it's a bug; if no key existed, it will create a new key. You can use New-AzureADApplicationPasswordCredential instead.
Ok, so we found out this happens because the first certificate was uploaded to Azure AD by modifying the application manifest. After deleting it and adding it again using powershell everything worked...

Create Azure AD ClientCredentials Key from PowerShell

In the Azure Portal I can create an Application, Key and Permissions to the Graph API.
I can get a Token using:
AuthenticationContext ac = new AuthenticationContext("https://login.windows.net/graphDir1.onmicrosoft.com");
ClientCredential cc = new ClientCredential("b3b1fc59-84b8-4400-a715-ea8a7e40f4fe", "FStnXT1QON84B5o38aEmFdlNhEnYtzJ91Gg/JH/Jxiw=");
AuthenticationResult authResult = ac.AcquireToken("https://graph.windows.net", cc);
Using the Azure Active Directory Module for Windows PowerShell I can create a new Symmetric Key.
New-MsolServicePrincipalCredential -AppPrincipalId ??? -Type Symmetric
Using the key returned from this in the code above returns the error:
AdalServiceException: AADSTS70002: Error validating credentials. AADSTS50012: Invalid client secret is provided.
This used to work with a previous version of ADAL using instead of ClientCredential, SymmetricKeyCredential but that class no longer exists.
Is there a way to generate a key from PowerShell that works with the code above?
Please try using Password as the key type:
New-MsolServicePrincipalCredential -AppPrincipalId $appId `
-Type Password `
-StartDate ([DateTime]::Now.AddMinutes(-5)) `
-EndDate ([DateTime]::Now.AddMonths(1)) `
-Value "$newPassword"
Hope this helps

Add-AzureAccount : Index was out of range. Must be a non-negative and less than the size of the collection

On 4th of August a new version of the Azure powershell module (0.8.7.1) was released. In it is the ability to create credentials which you could then pass to the Add-AzureAccount function. Add-AzureAccount allows you to pull in an account to work with in the current PowerShell session.
$userName = "buildmaster#someaccount.onmicrosoft.com"
$securePassword = ConvertTo-SecureString -String "somepassword." -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($userName, $securePassword)
Add-AzureAccount -Credential $cred
This allowed me to get away from a popup window or messing with a settings file.
It seems to have stopped working! Both Add-AzureAccount (which pops up a window) and the credential based way. They now return an index was out of range issue.
Add-AzureAccount : Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
At S:\QA\Azure Scripts\cm-azure-helpers.psm1:1128 char:5
+ Add-AzureAccount
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Add-AzureAccount], ArgumentOutOfRangeException
+ FullyQualifiedErrorId : Microsoft.WindowsAzure.Commands.Profile.AddAzureAccount
Digging deeper with Fiddler shows that the OAuth call to the back end service seems to work. I get a token returned. But then I also get a 302 in the middle of the process stating that the page has moved. I don't know if that redirect was there when it was working previously or not.
Has anyone else experienced the Add-AzureAccount function just stop working like this? And more importantly - have you found a way around it?
Update - More info
I have now tried on several boxes under different azure accounts and seem to have the same results. I get a valid auth token returned with a redirect in the middle (not sure if that is an issue or not) and then get the index was out of range.
I have done this with the following variations:
PS:3 Azure Module: 0.8.6
PS:3 Azure Module: 0.8.7
PS:4 Azure Module: 0.8.6
PS:4 Azure Module: 0.8.7
I know exactly what caused this error for me, and how I worked around it (I thought I was the only one who had seen this :))
What had happened is that I had accidentally added a bogus/empty subscription to my account. And this empty subscription had been set to my "default" subscription.
Run "get-azuresubscription -default" to see what your default subscription is. You can then "remove" any junk subscriptions using "remove-azuresubscription" command.
You can then of course set a new azure subscription for your "default" using PS.
I actually reported this to the Azure PowerShell team now to get a better error message during this scenario.
Hopefully this solved your problem, it's possible other errors manifest the same error message.
If you do a fiddler trace, you should see that right after the login call (where PowerShell passes in your username/password, there should be 1 or multiple calls to GET /subscriptions.
Check the response to see whether there is anything suspicious there. Like, any of them return an empty body, empty array, subscription with id, name, etc..
I had a similar problem recently. The "fix" was for me was to delete the files at C:\Users[username]AppData\Roaming\Windows Azure Powershell (esp. the WindowsAzureProfile.xml file). The next time I ran Add-AzureAccount, the necessary files were created and all was well.
Please use:
Add-AzureRmAccount -SubscriptionId "id";
for login