How to get thumbprint of the certificate associated with a service principal using Powershell? - azure

I have a certificate associated with a service principal in Azure AD. How can I get the certificate name or thumbprint associated with it using powershell?
I have tried Get-AzureRmADServicePrincipalCredential, Get-AzureRmADSpCredential and Get-AzureADServicePrincipalKeyCredential commands but they return Key Identifier not thumbprint.
Basically I want to recognize which certificate is associated with the principal before revoking it.

As #Stanley Gong mentioned, you can use MS Graph to get it.
Here is another way, try the command as below, the $Thumbprint is that you want.
Note the <object-id> is the object id of your AD App(App registration), not the service principal(Enterprise application), they are different.
$CustomKeyIdentifier = (Get-AzureADApplicationKeyCredential -ObjectId "<object-id>").CustomKeyIdentifier
$Thumbprint = [System.Convert]::ToBase64String($CustomKeyIdentifier)

Try the PS command below to get cert thumbprint via Microsoft Graph API :
$clientId = "<your Azure AD App ID>"
$clientSec="<your Azure AD App Secret>"
$appObjId = "<object ID of the app that you want to query>"
$tenant = "<your tenant ID>"
$body=#{
    "grant_type"="client_credentials";
    "resource"="https://graph.microsoft.com/";
    "client_id"= $clientId;
    "client_secret" = $clientSec
}
$accessToken=(Invoke-RestMethod -Uri "https://login.windows.net/$tenant/oauth2/token" -Method POST -Body $body ).access_token
$keyCreds = Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/applications/$appObjId/keyCredentials" -Method Get -Headers #{"Authorization" = "Bearer $accessToken"}
$keyCreds.value.customKeyIdentifier
Result:
my certs on portal :
query result :
Pls note that make sure your app which you used for getting token with permission below so it can call Microsoft graph API to query your apps :

Related

How to manage the Azure APIM developer portal delegation with Azure PowerShell

I want to enable the Azure APIM developer portal sign-in & sign-up delegation and to generate a "Delegation Validation Key". This is straightforward with the Azure portal:
I want to achieve the same thing but with Azure PowerShell as part of a bigger deployment pipeline.
I cannot find any documentation on how to do that.
Thanks
AFAIK, We can not achieve the above requirement using powershell , Here are the details (MICROSOFT DOCUMENTATION) for what we can configure through powershell for APIM .
Instead of that we can configure the above requirement using git , Please refer this MICRSOFT DOCUMENTATION for more details & the list of cmdlets for APIM .
An additional option is to use an HTTP call against the resource. The call can be made with the PowerShell script as well.
This can be done as follows:
Get an Azure access token - you should have a Service Principal with sufficient permissions for the resource we are going to deal with.
$tokenUri = "https://login.microsoftonline.com/${tenantId}/oauth2/token"
$form = #{
grant_type = 'client_credentials'
resource = 'https://management.core.windows.net/'
client_id = $spClientId
client_secret = $spClientSecret
}
$response = Invoke-RestMethod -Uri $tokenUri -Method Post -Body $form
$azureToken = $response.access_token
Send an HTTP request against the APIM service
$url = "https://management.azure.com/subscriptions/${subscriptionId}/resourceGroups/${apiManagementRg}/providers/Microsoft.ApiManagement/service/${apiManagementName}/portalsettings/delegation?api-version=2020-12-01"
$headers = #{ 'Authorization' = "Bearer ${azureToken}" }
$body = #"
{
"properties": {
"url": "$delegationUrl",
"validationKey": "$validationKey",
"subscriptions": {
"enabled": false
},
"userRegistration": {
"enabled": true
}
}
}
"#
$delegationResponse = Invoke-RestMethod -Method 'Put' -Body $body -Uri $url -Headers $headers

How to get Key Vault Secret under Web App's (with a user-assigned managed identity) Kudu powershell environment?

If I have a web app which has a system-assigned managed identity and the web app has been added to a Key Vault's Access Policies, I can use the following code the get secret value from the Key Vault under Kudu
powershell Environment:
function GetSecret {
param (
[parameter(Mandatory=$True, Position=1)] [String] $keyVaultSecretUri
)
$apiVersion="2017-09-01"
$resourceURI = "https://vault.azure.net"
$tokenResponse = Invoke-RestMethod `
-Method Get `
-Headers #{"Secret"="$env:MSI_SECRET";"Content-Type"="application/json"} `
-Uri "${env:MSI_ENDPOINT}?resource=${resourceURI}&api-version=${apiVersion}"
$accessToken = $tokenResponse.access_token
$headers = #{'Authorization'="Bearer $accessToken"}
$keyVaultApiVersion="7.1"
$secret=Invoke-RestMethod -Method Get -Headers $headers -Uri "${keyVaultSecretUri}?api-version=${keyVaultApiVersion}"
return $secret
}
GetSecret -keyVaultSecretUri $SecreteUri
But if I give the web app a user-assigned managed identity (without system-assigned managed identity) and add that managed identity to the Key Vault's Access Policies (with enough permissions), the above code doesn't work.
Actually even the following three lines gets a runtime exception:
$apiVersion="2017-09-01"
$resourceURI = "https://vault.azure.net"
$tokenResponse = Invoke-RestMethod `
-Method Get `
-Headers #{"Secret"="$env:MSI_SECRET";"Content-Type"="application/json"} `
-Uri "${env:MSI_ENDPOINT}?resource=${resourceURI}&api-version=${apiVersion}"
The exception is (CorrelationId is hidden):
Invoke-RestMethod : {"StatusCode":400,"Message":"No MSI found for specified
ClientId/ResourceId.","CorrelationId":"0000000-0000-0000-0000-000000000000"}
At line:1 char:18
+ $tokenResponse = Invoke-RestMethod `
+ ~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:Htt
pWebRequest) [Invoke-RestMethod], WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShe
ll.Commands.InvokeRestMethodCommand
So how to get Key Vault Secret under Web App's (with a user-assigned managed identity) Kudu powershell environment??
(Probably the Headers for user-assigned identity web app is wrong)
PS: This answer How can I give access to key vault to a user assigned identity? doesn't resolve my question.
I actually wrote an article on this topic just a while ago: https://joonasw.net/view/get-managed-identity-access-token-in-azure-app-service-through-kudu.
There I link to the docs for the REST protocol that Managed Identity uses: https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?tabs=dotnet#using-the-rest-protocol.
If you use a user-assigned identity, you must identify which identity you want to use.
Since an App Service etc. can have multiple user-assigned identities.
In the docs they give the following options:
You only need to specify one of these if I recall correctly.
Tested this script and got a token for the user-assigned identity:
$resource = "https://vault.azure.net"
$clientId = "00000000-0000-0000-0000-000000000000"
$endpoint = $env:IDENTITY_ENDPOINT
$header = $env:IDENTITY_HEADER
$apiVersion = "2019-08-01"
$headers = #{ 'X-Identity-Header' = $header }
$url = "$($endpoint)?api-version=$apiVersion&resource=$resource&client_id=$clientId"
$response = Invoke-RestMethod -Method Get -Uri $url -Headers $headers
$response.access_token

I would like to give admin consent to API permissions through powershell script

I have a code in Az module of powershell to create appID, app secret and assign API permission. How do I grant admin consent to all the API permissions that I assigned to the AzApp?
...
$context = Get-AzContext
$ResourceAppIdURI = "https://graph.windows.net/"
$token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $ResourceAppIdURI).AccessToken
$headers = #{ }
$headers.Add("Content-Type", "application/json")
$headers.Add("Accept", "application/json")
$headers.Add("Authorization", "Bearer $($token)")
$objectID = $myApp.ObjectId
$url = "https://graph.windows.net/$tenant/applications/{0}?api-version=1.6" -f $objectID
Write-Host "URL: " $url
$postData = "{`"requiredResourceAccess`":[
{`"resourceAppId`":`"00000003-0000-0000-c000-000000000000`",
`"resourceAccess`":[
{`"id`":`"e1fe6dd8-ba31-4d61-89e7-88639da4683d`",`"type`":`"Scope`"},
{`"id`":`"7ab1d382-f21e-4acd-a863-ba3e13f7da61`",`"type`":`"Role`"},
{`"id`":`"5b567255-7703-4780-807c-7be8301ae99b`",`"type`":`"Role`"},
{`"id`":`"e2a3a72e-5f79-4c64-b1b1-878b674786c9`",`"type`":`"Role`"},
{`"id`":`"df021288-bdef-4463-88db-98f22de89214`",`"type`":`"Role`"}
]
}]
}";
Invoke-RestMethod -Uri $url -Method "PATCH" -Headers $headers -Body $postData
Write-Host "App created..."
Write-Host "AppID: " $myApp.ApplicationId
Write-Host "App Secret: " $secret
Write-Host "TenantID: " $tenant.Id
There is no API exposed by Microsoft to grant admin consent for Azure AD application / service principal. You can vote this post on User Voice.
There is a workaround:
Call Microsoft Graph API Create a delegated permission grant and Grant an appRoleAssignment to a service principal in Powershell.
A sample for your reference:
$context = Get-AzContext
$ResourceAppIdURI = "https://graph.windows.net/"
$ResourceGraphURI = "https://graph.microsoft.com/"
$token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $ResourceAppIdURI).AccessToken
$graphToken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, $ResourceGraphURI).AccessToken
$clientID = "d154cc56-f1a2-4906-9f26-bfb4756f9c20"
$resourceID = "08a1faff-51c1-4cbb-81c4-1bc11286da76"
$scopes = "Sites.Read.All User.Read User.Read.All User.ReadBasic.All"
$body = #{
clientId = $clientID
consentType = "AllPrincipals"
principalId = $null
resourceId = $resourceID
scope = $scopes
startTime = "2019-10-19T10:37:00Z"
expiryTime = "2020-10-19T10:37:00Z"
}
$apiUrl = "https://graph.microsoft.com/beta/oauth2PermissionGrants"
Invoke-RestMethod -Uri $apiUrl -Headers #{Authorization = "Bearer $($graphToken)" } -Method POST -Body $($body | convertto-json) -ContentType "application/json"
$principalId = "d154cc56-f1a2-4906-9f26-bfb4756f9c20"
$body1 = #{
principalId = $principalId
resourceId = $resourceID
appRoleId = "df021288-bdef-4463-88db-98f22de89214"
}
$apiUrl1 = "https://graph.microsoft.com/beta/servicePrincipals/$($principalId)/appRoleAssignedTo"
Invoke-RestMethod -Uri $apiUrl1 -Headers #{Authorization = "Bearer $($graphToken)" } -Method POST -Body $($body1 | convertto-json) -ContentType "application/json"
For the first call https://graph.microsoft.com/beta/oauth2PermissionGrants:
clientID is the object id of the service principal (not Azure AD application), you can find it using Get-AzADServicePrincipal. You can also find it on Azure Portal - Azure Active Directory - Enterprise Applications, search for the name of your Azure AD application.
resouceID is the object id of Microsoft Graph service principal. You can find under Enterprise applications (search for "00000003-0000-0000-c000-000000000000").
scopes are the delegated permissions you want to grant admin consent.
For the second call https://graph.microsoft.com/beta/servicePrincipals/$($principalId)/appRoleAssignedTo:
principalId is the same as clientID mentioned above.
appRoleId is the application permission id.
Actually, the Azure AD PowerShell module provides a cmdlet equivalent for Application Permissions : New-AzureADServiceAppRoleAssignment.
Even if it's poorly documented, the command adds the requested application permissions (and grant admin consent if you have the right to do so) to your AAD Application (through the service principal).
# If it's not the case, declare your AAD Application as a service principal (Enterprise Application)
$aadappsp = New-AzureADServicePrincipal -AppId "AAD_APPLICATION_ID"
# Id of the application permission (role)
$roleId = "2a8d57a5-4090-4a41-bf1c-3c621d2ccad3" # TermStore.Read.All
# Object Id of the concerned Service Principal (could be Graph or SharePoint for example)
# (Not the Application Id like "00000003-0000-0ff1-ce00-000000000000" for SharePoint)
$aadSpObjectId = "c30e8a24-ff90-464e-aed3-7c39a7bdc280"
# Register the application permission
New-AzureADServiceAppRoleAssignment -ObjectId $aadappsp.ObjectId -Id $roleId -PrincipalId $aadappsp.ObjectId -ResourceId $aadSpObjectId
It's using a dedicated endpoint, so don't be surprised if you have this display once the command correctly executed:
(permissions added through PowerShell appear as "Other permissions granted for...")
To avoid that, you have to first add them through interface or with New-AzureADApplication (to register the permissions as "configured") and New-AzureADServicePrincipal (to grant admin consent properly for your organization).
Sadly, there's no cmdlet for granting admin consent on Delegated Permissions, so the answer provided by #Allen Wu still works in this case (just update the URIs to use v1.0 version instead of beta).

Is it possible to update URL is availability test in application insights through powershell on a schedule task/frequency

I have a number of environments in azure which utilize on-premise Restful services for one of our customers. We currently have application insights configured within a resource group, and an availability test configured to ping a URL at a specified frequency, configured with an insights alert (email when goes down)
An access token is embedded into the URL which needs to be updated frequently. Is it possible to update the URL highlighted programmatically to replace the token (Scheduled/automated basis )
Just wondering what technologies could be used to update an availability URL on a scheduled basis (every two weeks)
Azure functions?
Some sort of PowerShell script as a scheduled task?
ARM templates using the example here https://learn.microsoft.com/en-us/azure/azure-monitor/app/powershell#add-an-availability-test
Any advice on how to proceed with this task efficiently and using the most appropriate technologies would be appreciated.
I have to say seems there is no PowerShell module provided to modify the url of App Insight webtest , but we can do it via REST API . Try the PowerShell below :
$clientId = "<your Azure AD application ID>"
$clientSec="<your Azure AD application secret>"
$appInsightName ="<your app insight name>"
$webtestName="<your webtest name>"
$subscriptionId = "<your subscription ID>"
$resourceGroupName = "<your resource group name that your app insight in>"
$tenant = "<your tenant name/ID>"
$newUrl = "<the new URL>"
#get access token to fetch details of webtest
$body=#{
    "grant_type"="client_credentials";
    "resource"="https://management.azure.com/";
    "client_id"= $clientId;
    "client_secret" = $clientSec
}
$accessToken=(Invoke-RestMethod -Uri "https://login.windows.net/$tenant/oauth2/token" -Method POST -Body $body ).access_token
$uri = "https://management.azure.com/subscriptions/{0}/resourcegroups/{1}/providers/microsoft.insights/webtests/{2}-{3}?api-version=2015-05-01"
$uri = $uri.Replace("{0}",$subscriptionId).Replace("{1}",$resourceGroupName).Replace("{2}",$webtestName).Replace("{3}",$appInsightName)
$webtestResult = Invoke-RestMethod -Uri $uri -Method GET -Headers #{"Authorization"="Bearer $accessToken"}
#modify the url of webtest
$webTestConf = [xml]#($webtestResult.properties.Configuration.WebTest)
$webTestConf.WebTest.Items.Request.Url = $newUrl
#structure request json to update webtest
$locations = $webtestResult.properties.Locations | ConvertTo-Json
$Configuration = $webTestConf.WebTest.OuterXml | ConvertTo-Json
$Configuration = $Configuration.Replace("\u003c","<").replace("\u003e",">")
$location = $webtestResult.location
$tags = $webtestResult.tags| ConvertTo-Json
$name = $webtestResult.properties.Name
$kind = $webtestResult.properties.Kind
$json = #"
{
"location":"$location",
"tags":$tags,
"properties":{
"Name":"$name",
"Enabled": true,
"Frequency": 300,
"Timeout": 120,
"Locations":$locations,
"Configuration":{"webtest":$Configuration},
"Kind":"$kind"
}
}
"#
Invoke-RestMethod -Uri $uri -Method PUT -Body $json -Headers #{"Authorization"="Bearer $accessToken";"Content-Type"="application/json"}
Except for Azure function, you can use Azure automation powershell Runbook with scheduled task to meet your requirement .
Btw, this powershell demo uses service principle to connect to your Azure subscription, make sure your Azure ad application has permission to modify your app insight. If you have anything unclear , pls feel free to let me know . This issue shall not be passed !

Azure AD Access Token Without ADAL

I am trying to edit a user's AD profile on the server side which requires an access token. I can do this with the native app example which uses only a client id and secret. The docs mention that this is possible with only http requests (see Get Access Token), but I can't find any example or way to do this.
You can use OAuth2 to request an access token. Here is an example on how you use OAuth2 with Azure AD. It's written in PowerShell Script.
$tenantID = "<the Tenant ID of your Azure AD>"
$loginEndpoint = "https://login.windows.net/"
$graphResourceURI = "https://graph.windows.net/"
$clientId = "<the client id of your AD application>"
$key = "<the client secret of your AD application>"
# the URL for requesting access token.
$tokenURL = $loginEndpoint+$tenantID+"/oauth2/token"
# the token request body.
$body = "grant_type=client_credentials&client_id="+$clientId `
+"&client_secret="+[system.uri]::EscapeDataString($key) `
+"&resource="+[system.uri]::EscapeDataString($graphResourceURI)
# the token request headers.
$headers = #{"Content-Type"="application/x-www-form-urlencoded"}
$authenticationResult = Invoke-RestMethod -Method POST `
-Uri $tokenURL -Headers $headers -Body $body
$authenticationResult.access_token
The AD application you use here must be "Web application and/or web API", because a Native AD application does not have client secret.
I got this to work using Jack's answer but with a couple of changes. Here is the complete working example:
$tenantID = "<the name of your tenant of your Azure AD>"
$loginEndpoint = "https://login.windows.net/"
$graphResourceURI = "https://graph.windows.net/"
$clientId = "<the client id of your AD application>"
$key = "<the client secret of your AD application>"
# the URL for requesting access token.
$tokenURL = $loginEndpoint+$tenantID+"/oauth2/token"
# the token request body.
$body = "grant_type=client_credentials&client_id="+$clientId `
+"&client_secret="+[system.uri]::EscapeDataString($key) `
+"&resource="+[system.uri]::EscapeDataString($graphResourceURI)
# the token request headers.
$headers = #{"Content-Type"="application/x-www-form-urlencoded"}
$authenticationResult = Invoke-RestMethod -Method POST `
-Uri $tokenURL -Headers $headers -Body $body
$authenticationResult.access_token

Resources