Azure Function Powershell using Ms-Graph and certificate authentication - powershell

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.

Related

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

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.

Powershell Script for looping through Azure Key Vault Issuance Policy

I've a requirement - I need to get report of all certificate policies (Issuance Policy) and consolidate the report. Please see the 2nd image - these are the properties I'm looking in the report.
Solution using any technology is fine, mostly looking for - PowerShell, Azure Function etc.
According to my test, if you want to get the Azure key vault, you use the PowerShell command Get-AzKeyVaultCertificatePolicy to get the information of the policy.
For example
Set access policy
Set-AzKeyVaultAccessPolicy -VaultName "<>"-ResourceGroupName "<>"-UserPrincipalName "<>" -PermissionsToCertificates get,list
Get policy
Get-AzKeyVaultCertificatePolicy -VaultName "<>" -Name "<cert name>"
Besides, if you want to use Azure function to get the policy, please refer to the following steps
Enable MSI for the Azure Function
Set access policy
Set-AzKeyVaultAccessPolicy -VaultName "<>"-ResourceGroupName "<>" -ObjectId "<the object id you copy>" -PermissionsToCertificates get,list
Code(C#)
//install package Azure.Identity Azure.Security.KeyVault.Certificates
CertificateClient client = new CertificateClient(new Uri("https://norasvault.vault.azure.net/"), new DefaultAzureCredential());
Response<CertificatePolicy> result =await client.GetCertificatePolicyAsync("yangtest");
// create the report
// the result.value cantians the properties of CertificatePolicy
For more details, please refer to https://learn.microsoft.com/en-us/dotnet/api/azure.security.keyvault.certificates.certificatepolicy?view=azure-dotnet

How to use Get-AzKeyVaultSecret in Powershell Azure Function 2.x

I'm setting up a Powershell Azure Function that needs keys from an Azure KeyVault. Most of the keys can be retrieved by using the #Microsoft.KeyVault(SecretUri='MySecretUriWithVersion') method.
One of the keys changes frequently. Hence the SecretUri cannot be used.
All keys are stored in the same KeyVault and the Function has a MSI that can read, list and change all keys.
I'm working with a refresh token that needs to be updated. This value is renewed every time my code runs and needs to be updated in the keyvault
Connect-AzAccount -Identity
#Works
Get-AzKeyVault -VaultName $VaultName -ResourceGroupName $rgName
#Not working
Get-AzKeyVaultSecret -VaultName $VaultName -Name $KeyName
Expected output: The code retrieves the key.
Actual output: ERROR: Operation returned an invalid status code
'Unauthorized' Microsoft.Azure.WebJobs.Script.Rpc.RpcException :
Result: ERROR: Operation returned an invalid status code
'Unauthorized' Exception: Operation returned an invalid status code
'Unauthorized' Stack: at
Microsoft.Azure.KeyVault.KeyVaultClient.GetSecretWithHttpMessagesAsync(String
vaultBaseUrl, String secretName, String secretVersion, Dictionary`2
customHeaders, CancellationToken cancellationToken)
dlet.ProcessRecord()
Taken from Microsoft: https://learn.microsoft.com/en-us/azure/key-vault/quick-create-powershell
Have you tried dot notation on retrieving those keys?
(Get-AzKeyVaultSecret -vaultName $VaultName -name $KeyName).SecretValueText
If that doesn't work, you may look at this github issue regarding ManagedAppServices: https://github.com/Azure/azure-powershell/issues/8983
Seems to be the same issue you're having.
There is now a new method for this.
$secret = Get-AzKeyVaultSecret -VaultName "<your-unique-keyvault-name>" -Name "ExamplePassword"
$ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret.SecretValue)
try {
$secretValueText = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr)
} finally {
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)
}
Write-Output $secretValueText
Refer to: https://learn.microsoft.com/en-us/azure/key-vault/secrets/quick-create-powershell
The original error is fixed in Azure Functions now.
It is still necessary to retrieve keys that are updated frequently in key vault. To do that, I use this:
(Get-AzKeyVaultSecret MyVaultName -Name MySecretName).secretvalue | ConvertFrom-SecureString -AsPlainText
Also, please refer to this link if you face any issues due to secretValueText being deprecated.

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 an Azure Website with PowerShell and FTP

I need to write a PowerShell script that automatically creates an Azure Website and deploy the content of a local file system. Seems that Azure PowerShell SDK doesn't provide a way to copy files to a website so we want to use FTP as a deploy method.
To get the correct FTP endpoints and credentials the only way that I have found is to call an Azure Management Rest API: Get a Site’s Publish Profile.
But this API as other Azure Management API requires a certificate. I have found the following tutorial
Building Real-World Cloud Apps with Windows Azure that explain how to get the certificate:
$s = Get-AzureSubscription -Current
$thumbprint = $s.Certificate.Thumbprint
Unfortunately seems that with the current SDK $s.Certificate is always null, this property doesn't exists. If I manually set the certificate thumbprint everything works as expected.
Do you have an idea on how to get the correct subscription certificate? Or do you have an easy alternative to deploy local files to an Azure website?
It seems that now you can access the certificate thumbprint using
$thumbprint = $s.DefaultAccount
instead of
#$thumbprint = $s.Certificate.Thumbprint
Seems that the DefaultAccount has exactly the same value as the certificate thumbprint.
Just for reference here is my complete script to obtain a publishing profile for a given website:
Function get-AzureWebSitePublishXml
{
Param(
[Parameter(Mandatory = $true)]
[String]$WebsiteName
)
# Get the current subscription
$s = Get-AzureSubscription -Current
if (!$s) {throw "Cannot get Windows Azure subscription."}
#$thumbprint = $s.Certificate.Thumbprint #this code doesn't work anymore
$thumbprint = $s.DefaultAccount
if (!$thumbprint) { throw "Cannot get subscription cert thumbprint."}
# Get the certificate of the current subscription from your local cert store
$cert = Get-ChildItem Cert:\CurrentUser\My\$thumbprint
if (!$cert) {throw "Cannot find subscription cert in Cert: drive."}
$website = Get-AzureWebsite -Name $WebsiteName
if (!$website) {throw "Cannot get Windows Azure website: $WebsiteName."}
# Compose the REST API URI from which you will get the publish settings info
$uri = "https://management.core.windows.net:8443/{0}/services/WebSpaces/{1}/sites/{2}/publishxml" -f `
$s.SubscriptionId, $website.WebSpace, $Website.Name
# Get the publish settings info from the REST API
$publishSettings = Invoke-RestMethod -Uri $uri -Certificate $cert -Headers #{"x-ms-version" = "2013-06-01"}
if (!$publishSettings) {throw "Cannot get Windows Azure website publishSettings."}
return $publishSettings
}
NOTE: this only works when you have connected to azure using Import-AzurePublishSettingsFile
Can anyone confirm that is safe to use DefaultAccount property?
UPDATE
If you use Kudu API to upload your site, like this, you don't need any certificate or publishing profile. You should read the user name and password using Get-AzureWebsite and the hostname is just yourwebsitename.scm.azurewebsites.net (note the scm segment). I suggest to use Kudu because is far more reliable and fast.