We are linking personal developers certificates to a certain service principal.
When a developer will leave our team, we will remove that credential from the service principal.
This works perfectly, but it's kind of a hassle because the name of the developer is not linked to the credentials.
I have noticed that their is a customIdentifierKey property on the credentials... but I cannot find how to set the customIdentifierKey.
Anyone knows how to do this?
New-AzureRmADAppCredential -ApplicationId $appId -CertValue $keyValue -EndDate $cert.NotAfter -StartDate $cert.NotBefore
You can use the Azure AD v2 cmdlets to set and get custom key identifiers.
Here I am adding a certificate:
New-AzureADApplicationKeyCredential -ObjectId 2648416a-aaaa-4bc0-9190-aaaab6165710 -CustomKeyIdentifier 'Your key name' -StartDate '2017/06/01' -EndDate '2018/06/01' -Type AsymmetricX509Cert -Usage Verify -Value $keyValue
Assuming your $keyValue contains an X509 certificate. If it is a symmetric key, you can use Symmetric as the Type.
The custom key identifier is stored as bytes, encoded in ASCII.
So when you get one, you need to run it through a decode:
$cred = Get-AzureADApplicationKeyCredential -ObjectId 2648416a-aaaa-4bc0-9190-aaaab6165710
[System.Text.Encoding]::ASCII.GetString($cred.CustomKeyIdentifier)
Interestingly, if you set an identifier on a PasswordCredential (client secret) through Azure Portal, it encodes it in Unicode.
Related
Using powershell commands i want to reset the Service Principal client secret.
I followed the below steps from the article https://learn.microsoft.com/en-us/powershell/azure/create-azure-service-principal-azureps?view=azps-5.8.0
but it didnot reset the password
Remove-AzADSpCredential -DisplayName ServicePrincipalName
$newCredential = New-AzADSpCredential -ServicePrincipalName ServicePrincipalName
can you tell what i am doing wrong. I just want to reset the secret and have new one
I executed the above command and then i went to the app registration of that service principal and there i went to certificates & secrets i see it has not createed new secret.
Using bash i am able to reset the password by executing the below command but i want it to be done using powershell command
az ad sp credential reset --name
I went to the app registration of that service principal and there I went to certificates & secrets I see it has not created new secret.
Well, actually the command New-AzADSpCredential did create a new secret for you.
Firstly, you need to know the relationship between App Registration(AD App) and Service principal, see Application and service principal objects in Azure Active Directory.
In short, the service principal is the local representation for the AD App in a specific tenant. When you create the secret for the service principal, it will not appear in the Certificates & secrets blade, you can just get it with Get-AzADSpCredential.
If you want to reset the secret that you can find in the portal, you need to reset the sceret for the AD App(i.e. App Registration) via Remove-AzADAppCredential and New-AzADAppCredential.
You could refer to the sample below, it resets a secret with value ce96a0ed-5ae8-4a5a-9b3c-630da9ea3023, it is valid for one year, you can find it in the portal.
$obj = (Get-AzADApplication -DisplayName joyappv2).ObjectId
Remove-AzADAppCredential -ObjectId $obj -Force
$azurePassword = ConvertTo-SecureString "ce96a0ed-5ae8-4a5a-9b3c-630da9ea3023" -AsPlainText -Force
$date = Get-Date
$newCredential = New-AzADAppCredential -ObjectId $obj -Password $azurePassword -StartDate $date -EndDate $date.AddYears(1)
Note: You could not get the secret value again after creating it, so please store it when creating.
I'm adding a new certificate to an existing App Registration in Azure AD using the following command:
New-AzureADApplicationKeyCredential -ObjectId $AppObjectId -CustomKeyIdentifier $base64Thumbprint -Type AsymmetricX509Cert -Usage Verify -Value $base64Value -StartDate $cer.GetEffectiveDateString() -EndDate $validTo
This works OK and I can see the cert added in the Portal.
Should this certificate not also be visible via https://login.microsoftonline.com/{tenant}/discovery/keys?appid={Application(client)ID}
I've also tried adding the certificate info via Set-AzureADApplication & directly via the Portal. Each time I can see the certificate under "Certificates and Secrets" as well as in the App Manifest. No matter what I do I can't see the public cert in the JWKS endpoint.
My assumption on this comes from the following:
https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens
"If your app has custom signing keys as a result of using the claims-mapping feature, you must append an appid query parameter containing the app ID to get a jwks_uri pointing to your app's signing key information, which should be used for validation. For example: https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration?appid=6731de76-14a6-49ae-97bc-6eba6914391e contains a jwks_uri of https://login.microsoftonline.com/{tenant}/discovery/keys?appid=6731de76-14a6-49ae-97bc-6eba6914391e."
Any help would be much appreciated.
As far as I understand, the keys you add to the app are only used for authenticating your app to Azure AD.
Thus there is no need to advertise those keys in the public endpoint, as only Azure AD itself needs to use those public keys to verify assertions sent by your app.
Seems like you set the keyusage to Verify. If you want to use it for signing the token you need to set it to Sign and use a symmetric key:
New-AzureADApplicationKeyCredential -ObjectId $AppId -CustomKeyIdentifier "Test" -StartDate "11/7/2016" -Type "Symmetric" -Usage "Sign" -Value "123"
I have a service principal that I've creating using below powershell.
$sp3 = New-AzureRmADServicePrincipal `
-DisplayName "<service-principal-name>" `
-CertValue $certValue3 `
-EndDate ([System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($cert3.Certificate.GetExpirationDateString(), [System.TimeZoneInfo]::Local.Id, 'GMT Standard Time'))
where certValue3 is Base64String RawCertData. This service principal works fine and I am able to get a token when using the cert.
Once service principal is created in Azure AD, how do I see thumbprint of the certificate associated with the service principal using Powershell?
I've tried this, but I get Forbidden when I try to execute Get-AzureADApplicationKeyCredential
I also checked the manifest in Azure Portal under the service principal that gets created under Azure Active Directory → App Registrations → <service-principal-name> → Manifest, but the keyCredentials node is empty
"keyCredentials": [],
Please note that when I create an application using New-AzureRmADApplication followed by credential New-AzureRmADAppCredential and then New-AzureRmADServicePrincipal, then I see the keyCredentials with customKeyIdentifier set to the certificate thumbprint. Sample script below -
$adapp = New-AzureRmADApplication -DisplayName "<application-name>" `
-HomePage "<home-page-url>" `
-IdentifierUris "<identifier-url>" `
-CertValue $certValue `
-StartDate ([System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($cert.Certificate.GetEffectiveDateString(), [System.TimeZoneInfo]::Local.Id, 'GMT Standard Time')) `
-EndDate ([System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($cert.Certificate.GetExpirationDateString(), [System.TimeZoneInfo]::Local.Id, 'GMT Standard Time'))
New-AzureRmADAppCredential -ApplicationId $adapp.ApplicationId -CertValue $certValue2
$sp2 = New-AzureRmADServicePrincipal -ApplicationId $adapp.ApplicationId -DisplayName "<application-name>"
How to get thumbprint of the certificate associated with a service principal in Azure AD using powershell when the service principal is created independently without AzureRmADApplication and AzureRmADAppCredential?
According to my test, we can use the following Azure AD Graph API to get the key credentials of the sp. The customKeyIdentifier in KeyCredential is the thumbprint of the certificate
GET https://graph.windows.net/<your teanant id>/servicePrincipals/<your sp object id>/keyCredentials?api-version=1.6
For example
Create sp and get thumbprint
$tenantId ="<tenant id>"
#use the goabl admin account to login
Connect-AzureRmAccount -Tenant $tenantId
$certificateObject = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$certificateObject.Import("E:\Cert\examplecert.pfx","Password0123!", [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::DefaultKeySet)
Write-Host "the thumbrint of cert"
$certificateObject.Thumbprint
$keyValue = [System.Convert]::ToBase64String($certificateObject.GetRawCertData())
$sp =New-AzureRmADServicePrincipal -DisplayName "jimtestsample" -CertValue $keyValue -EndDate $endDate
$context=Get-AzureRmContext
$token=$context.TokenCache.ReadItems() |Where-Object { ($_.TenantId -eq $tenantId) -and ($_.Resource -eq "https://graph.windows.net/") }
$accesstoken=$token.AccessToken
$url = "https://graph.windows.net/$tenantId/servicePrincipals/"+$sp.Id+"/keyCredentials?api-version=1.6"
$keyCreds = Invoke-RestMethod -Uri $url -Method Get -Headers #{"Authorization" = "Bearer $accesstoken"}
Write-Host "--------------------------------------------"
$keyCreds.value | Select-Object customKeyIdentifier
I test your command, it should work. When using New-AzADServicePrincipal to create the service principal, it will create an AD App(i.e. App Registration) for you automatically, and the certificate will also appear in the Certificates & secrets of your AD App.
In my sample, I use the new Az module, for the old AzureRm module which you used, it should also work(Not completely sure, I recommend you to use the new Az module, because the AzureRm module has been deprecated and will not be updated). And make sure you are looking into the correct AD App in the portal, because the DisplayName of the AD App could be repeated.
$cert=New-SelfSignedCertificate -Subject "CN=TodoListDaemonWithCert" -CertStoreLocation "Cert:\CurrentUser\My" -KeyExportPolicy Exportable -KeySpec Signature
$bin = $cert.RawData
$base64Value = [System.Convert]::ToBase64String($bin)
New-AzADServicePrincipal -DisplayName joy134 -CertValue $base64Value
Check in the portal:
Then you can use this way you have tried, to fix the Forbidden error, your account should at least be the Owner of the AD App, or if your account has an admin role in the tenant e.g. Application administrator, Groups administrator, it will also work.
$CustomKeyIdentifier = (Get-AzureADApplicationKeyCredential -ObjectId "<object-id>").CustomKeyIdentifier
$Thumbprint = [System.Convert]::ToBase64String($CustomKeyIdentifier)
Besides, you should note the different command combinations will lead to different results, see this link. So when you test it, I recommend you to use different values of the parameters.
I'm currently attempting to deploy a Service Fabric cluster using the instructions provided here. I've successfully created a certificate using Let's Encrypt and am able to successfully handle all the instructions except for obtaining the certificateIssuerThumbprint value, as indicated as required in the parameters file at the top of this link.
Looking at the certificate details in my Certificate Manager, I don't see a field providing this value. I read through the Chain of Trust page for Let's Encrypt on which I'd expect to find such a value, but I'm not seeing it.
How would I go about looking up what this certificate issuer thumbprint value is?
Thank you!
$secret = Get-AzKeyVaultSecret -VaultName $vault -SecretName $secretName -Version $version
$certBytes = [Convert]::FromBase64String($secret.SecretValueText)
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certBytes, $null, 'Exportable')
$certChain = [System.Security.Cryptography.X509Certificates.X509Chain]::new()
$certChain.Build($cert)
$certificateIssuerThumbprint = ($certChain.ChainElements.Certificate | Where-Object {$_.Subject -eq $cert.Issuer}).Thumbprint
I'm far from an expert on certificates, but here's what I think needs to be done:
In certificate manager, if you simply double click and open the certificate > Certification Path tab, you should see your certificate at the bottom (as a leaf node), and in the Details tab you will see your certificate's thumbprint
There should be a certificate above your certificate - I believe this is the issuer certificate. If you double click that issuer certificate > Details, I think that's the thumbprint you need
#mperian's answer is absolutely spot-on if the certificate lives in an Azure Key Vault.
In my case, the certificates are installed to the stores on the various machines. Building on their excellent answer, here's the Powershell to do the same locally without use of Azure Key Vault.
$thumbprint = ""
$store = "My"
$cert = Get-ChildItem -Path "Cert:\LocalMachine\$store" | Where-Object {$_.Thumbprint -match $thumbprint}
$certChain = [System.Security.Cryptography.X509Certificates.X509Chain]::new()
$certChain.Build($cert)
$certIssuerThumbprint = ($certChain.ChainElements.Certificate | Where-Object {$_.Subject -eq $cert.Issuer}).Thumbprint
You should be able to see that value after you upload it to Keyvault using the script in the link you provided
https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-create-cluster-using-cert-cn#upload-the-certificate-to-a-key-vault
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser -Force
$SubscriptionId = "<subscription ID>"
# Sign in to your Azure account and select your subscription
Login-AzAccount -SubscriptionId $SubscriptionId
$region = "southcentralus"
$KeyVaultResourceGroupName = "mykeyvaultgroup"
$VaultName = "mykeyvault"
$certFilename = "C:\users\sfuser\myclustercert.pfx"
$certname = "myclustercert"
$Password = "P#ssw0rd!123"
# Create new Resource Group
New-AzResourceGroup -Name $KeyVaultResourceGroupName -Location $region
# Create the new key vault
$newKeyVault = New-AzKeyVault -VaultName $VaultName -ResourceGroupName $KeyVaultResourceGroupName -Location $region -EnabledForDeployment
$resourceId = $newKeyVault.ResourceId
# Add the certificate to the key vault.
$PasswordSec = ConvertTo-SecureString -String $Password -AsPlainText -Force
$KVSecret = Import-AzureKeyVaultCertificate -VaultName $vaultName -Name $certName -FilePath $certFilename -Password $PasswordSec
$CertificateThumbprint = $KVSecret.Thumbprint
$CertificateURL = $KVSecret.SecretId
$SourceVault = $resourceId
$CommName = $KVSecret.Certificate.SubjectName.Name
Write-Host "CertificateThumbprint :" $CertificateThumbprint
Write-Host "CertificateURL :" $CertificateURL
Write-Host "SourceVault :" $SourceVault
Write-Host "Common Name :" $CommName
From Create an SF cluster using certificates declared by CN:
"Note
The 'certificateIssuerThumbprint' field allows specifying the expected issuers of certificates with a given subject common name. This field accepts a comma-separated enumeration of SHA1 thumbprints. Note this is a strengthening of the certificate validation - in the case when the issuer is not specified or empty, the certificate will be accepted for authentication if its chain can be built, and ends up in a root trusted by the validator. If the issuer is specified, the certificate will be accepted if the thumbprint of its direct issuer matches any of the values specified in this field - irrespective of whether the root is trusted or not. Please note that a PKI may use different certification authorities to issue certificates for the same subject, and so it is important to specify all expected issuer thumbprints for a given subject.
Specifying the issuer is considered a best practice; while omitting it will continue to work - for certificates chaining up to a trusted root - this behavior has limitations and may be phased out in the near future. Also note that clusters deployed in Azure, and secured with X509 certificates issued by a private PKI and declared by subject may not be able to be validated by the Azure Service Fabric service (for cluster-to-service communication), if the PKI's Certificate Policy is not discoverable, available and accessible."
Note that upon renewing (or re-keying) a certificate, the issuer may well change. A PKI would typically publish all its active issuers in a Certification Practice Statement (CPS) (here is LetsEncrypt's - unfortunately it doesn't seem to list the issuer certificates.)
If you're internal to Microsoft, you would probably know which API to use to retrieve authorized issuers; if you aren't, please contact the PKI of your choice for guidance.
Access policies via groups on Azure Key Vault don't seem to work.
If I create a new key vault
New-AzureRmKeyVault -VaultName $vaultName
And check the keys (which there aren't any of currently)
Get-AzureKeyVaultKey -VaultName $vaultName
That works.
If I add access to a group that the current user is a member of
$group = (Get-AzureRmADGroup -SearchString 'All Developers')[0].Id
Set-AzureRmKeyVaultAccessPolicy -VaultName $vaultName -ResourceGroupName $resourceGroupName -ObjectId $group -PermissionsToKeys all -PermissionsToSecrets all
And remove direct access
Remove-AzureRmKeyVaultAccessPolicy -VaultName $vaultName -ResourceGroupName $resourceGroupName -UserPrincipalName $upn
The list operation now fails
Get-AzureRmKeyVault -VaultName $vaultName -ResourceGroupName $resourceGroupName
Get-AzureKeyVaultKey : Operation "list" is not allowed
How can I permission by group?
I discovered today that it works for users in permissioned group objects. Doesn't work for service principals in those groups.
In other words, if I authenticate using a client id and client secret, the associated service principal must have an access policy directly set on the key vault. If I permission a security group, a user in that group can in fact access the key vault. I guess this has something to do with how the JWT includes security groups in it with users, but not service principals...
The reason that adding an access policy to a group is that it isn't supported. If you look at the help for Set-AzureRmKeyVaultAccessPolicy there is this for ObjectId
-ObjectId <Guid>
Specifies the object ID of the user or service principal in Azure Active Directory for which to grant permissions.
Required? true
Position? named
Default value none
Accept pipeline input? true(ByPropertyName)
Accept wildcard characters? false
As you can see ObjectId only supports either Service principals or users.
This is reflected in the parameters of the source code for Set-AzureRmKeyVaultAccessPolicy and further up the chain the REST API when posting to
https://management.azure.com/subscriptions/{subscription-id}/resourceGroups/{resource-group-name}/providers/Microsoft.KeyVault/vaults/{vault-name}?api-version={api-version}
The payload contains the objectId parameter which is defined as
Specifies the object ID of a user or service principal in the Azure Active Directory tenant for the vault. The ID must be specified as a GUID.
I would imagine that this functionality will be added at some point in future, but at the moment it isn't possible.
This Access Denied / 403 Forbidden error can also happen when an app has made requests to a Key Vault before it was added to the Azure Active Directory Group.
Perhaps this has something to do with caching of service principal information on the App Service instance? I was unable to find documentation of this.
Solution: restart the App Service.