Azure - Access token request with a certificate - postman - azure

i want to test access to key vault using certificate
Scenario
Second case: Access token request with a certificate
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
I am struggling to supply
client_assertion
An assertion (a JSON web token) that you need to create and sign with the certificate you registered as credentials for your application. Read about certificate credentials to learn how to register your certificate and the format of the assertion.
I dont know why powershell has to bes used, and I dont have pfx, so cant use
https://blogs.aaddevsup.xyz/2020/10/how-to-use-postman-to-perform-a-client-credentials-grant-flow-with-a-certificate/
Is it possible to generate signed JWT using postman?
Note: Certificates in postman added. so that part is taken care

I don't think you can generate client_assertion directly in postman, please use the script below to create a self-assigned certificate, then you can use the script you mentioned to get the token.
$certroopath = "C:\Users\Administrator\Desktop"
$certname = "mycert1"
$certpassword = "P#ssw0rd1234"
$cert = New-SelfSignedCertificate -DnsName "$certname" -CertStoreLocation cert:\CurrentUser\My
$pwd = ConvertTo-SecureString -String $certpassword -Force -AsPlainText
$certwithThumb = "cert:\CurrentUser\my\"+$cert.Thumbprint
$filepath = "$certroopath\$certname.pfx"
Export-PfxCertificate -cert $certwithThumb -FilePath $filepath -Password $pwd

Related

PowerShell Core: Get cert object from PFX file

Using PowerShell on Linux, how do I get an X509Certificate2 object from a PKCS#12 file (aka PFX file) ?
On Windows, it's done like this:
$cert = (Get-PfxData -FilePath "mycert.p12" -Password $secstr).EndEntityCertificates[0]
# Pass cert object to some cmdlet, in this case MS Graph API:
Connect-MgGraph -Certificate $cert .....
The problem is that the PKI module is not available for Linux. I tried to dig into the background for all of this mess, and I think it is a consequence of the shortcuts that .NET Core is taking when it claims to be "cross-platform". (hint: it ain't true cross-platform as Microsoft has decided to rely on OS specific libraries for a lot of the security related stuff, unlike for example the route Java is taking). When the background .NET features are not there then consequently it is not possible for Microsoft to create the parity on PowerShell either.
Apart from my rant, can you answer my question? How would I do it?
Update (solution)
As per Toni's answer this will work on Linux:
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("myfile.p12",$secstr)
(not aware that there's any PowerShell binding for this, calling directly into .Net from PowerShell is not my favorite, but it does the job)
The PKCS#12 format allows a file to include an unlimited number of certificates. I'm assuming that the above will only work when the PKCS#12 file only has one certificate (chain) in it or that the behaviour in case of multiple certificate chains is un-specified. But one certificate (chain) is most typically the case. Or at least the case in my scenario.
The above works for me using Linux and PowerShell 7.2. To be certain I've tested with a .p12 file not created by PowerShell.
On Windows if the certificate is stored in the certificate store you can access the cert by using get-childitem, e.g.:
$cert = Get-ChildItem -Path 'Cert:\LocalMachine\MY' | ?{$_.Thumbprint -eq $thumbprint}
If the certificate is stored plain on the disk I think its the same for Linux and Windows:
#Without Password
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2([path])
#With Password
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2([path],[password])
X509Certificate2 Class is part of the .NET Core, so it works on Linux too.
https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509certificate2?view=netcore-3.1
Alternatively you can also use a password as secret to connect to Azure by using a ServicePrincipal, e.g.:
$tenandId = #fill the Id of your Tenant here
$clientId = #fill in the Id of the ServicePrincipal here
$secret = #fill in the password of the ServicePrincipal
#HashTable used for splatting
$paramsHt = #{}
$body = #{
Grant_Type = 'client_credentials'
Scope = 'https://graph.microsoft.com/.default'
Client_Id = $ClientID
Client_Secret = $Secret
}
#Establish connection and obtain Bearer Token
$con = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token" -Method 'Post' -Body $body
#Get Token issued
$token = $con.access_token
#Add token to HashTable
$paramsHT.add('AccessToken',$token)
#Connect to GraphAPI
Connect-MgGraph #paramsHT
But by doing so you have to handle the token refresh by yourself.

Is there a way to retrieve the client secret of an Azure AD application using PowerShell?

Is there a way to retrieve the Client Secret from Azure AD Application as a plain text by using PowerShell?
I tried with the below commands, but it is returning only the type of the secret, not the actual value.
$objectID = "00000-00000-00000-00000"
$keyID = "00000-00000-00000-00000"
$secret = Get-AzADAppCredential -ObjectId $objectID | Where-Object {$_.KeyId -eq $keyID}
$secret
You cannot retrieve the value of created Client Secret in any way.
Explanation of secretText:
The generated password value is only returned during the initial POST
request to addPassword. There is no way to retrieve this password in
the future.
The only way is add new Client Secret and store the new value securely.
$SecureStringPassword = ConvertTo-SecureString -String "password" -AsPlainText -Force
New-AzADAppCredential -ObjectId 1f89cf81-0146-4f4e-beae-2007d0668416 -Password $SecureStringPassword

How to obtain certificate issuer thumbprint?

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.

Generate a client certificate with key vault

For our point to site VPN, we want to create a root certificate.
So we can create as many client certificates as we want for all the partners that have the need to login in our VPN. (Azure virtual network)
Doing this manually works perfect. We generate a certificate (self signed) that acts as root ca. We are able to do this in powershell like this:
$cert = New-SelfSignedCertificate -Type Custom -KeySpec Signature -Subject "CN=Kratos Point To Site VPN Root Certificate Win10" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\CurrentUser\My" -KeyUsageProperty Sign -KeyUsage CertSign
$clientCert = New-SelfSignedCertificate -Type Custom -KeySpec Signature -Subject "CN=Digicreate Point To Site VPN Client Certificate Win10" -KeyExportPolicy Exportable -HashAlgorithm sha256 -KeyLength 2048 -CertStoreLocation "Cert:\CurrentUser\My" -Signer $cert -TextExtension #("2.5.29.37={text}1.3.6.1.5.5.7.3.2")
However, we prefer to use the key vault for our certificate management. The idea is to create a certificate directly in the key vault by using this command:
Add-AzureKeyVaultCertificate (with the private key not exportable)
Creating the root certificate works perfectly. But I am not able to find how I can sign a new certificate with the 'sign' operations in the key vault.
Do you have a sample on how to this?
Refer to the "Create a certificate manually and get signed by a CA" section in https://blogs.technet.microsoft.com/kv/2016/09/26/get-started-with-azure-key-vault-certificates/
but I would like to create a client certificate based on this root
certificate with azure key vault cmdlets. Is this possible?
Do you mean you want to download the certificate? if yes, we can use this script to download it:
download Private certificate to your D:\cert:
$kvSecret = Get-AzureKeyVaultSecret -VaultName 'jasontest2' -Name 'TestCert01'
$kvSecretBytes = [System.Convert]::FromBase64String($kvSecret.SecretValueText)
$certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$certCollection.Import($kvSecretBytes,$null,[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$protectedCertificateBytes = $certCollection.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, 'test')
$pfxPath = 'D:\cert\test.pfx'
[System.IO.File]::WriteAllBytes($pfxPath, $protectedCertificateBytes)
Download public certificate to your D:\cert:
$cert = Get-AzureKeyVaultCertificate -VaultName 'jasontest2' -Name 'TestCert01'
$filePath ='D:\cert\TestCertificate.cer'
$certBytes = $cert.Certificate.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert)
[System.IO.File]::WriteAllBytes($filePath, $certBytes)
Update:
The $certificateOperation.CertificateSigningRequest is the base4 encoded certificate signing request for the certificate.
Import-AzureKeyVaultCertificate -VaultName $vaultName -Name $certificateName -FilePath C:\test\OutputCertificateFile.cer
More information please refer to this blog.
Update:
We should sign the CertificateSignRequest with the sign operation with your CA server.
Enterprise certificate:
If you are using an enterprise certificate
solution, generate a client certificate with the common name value
format 'name#yourdomain.com', rather than the 'domain name\username'
format. Make sure the client certificate is based on the 'User'
certificate template that has 'Client Authentication' as the first
item in the use list, rather than Smart Card Logon, etc. You can check
the certificate by double-clicking the client certificate and viewing
Details > Enhanced Key Usage.

How do you manually renew a certificate in AzureKeyValut

We have a CA that is not supported by Azure KeyVault. We have created certificates and CSRs using KeyVault and submitted them successfully to the CA and imported the signed cert. We now have some certs that pre-date our use of KeyVault that are up for renewal. Our security team has had new signed certs issued by the CA. But when we import the original signed cert and private key (pfx format) and then try to import the new signed cert it fails with "Pending Certificate not found". What's to proper sequence of bring these certs into KeyVault.
An Azure Key Vault certificate is a versioned object. When you create a new certificate, you are creating a new version. Each version of the certificate is conceptually composed of 2 parts - an asymmetric key, and a blob which ties that asymmetric key to an identity.
When you need to use your own CA, AKV generates an asymmetric key and returns the CSR to the user. The user then uses the CSR to obtain a certificate. This is true for every version of the certificate.
If you current version is expiring, you need to create a new version. You need to follow the same steps as you did when creating the first version. You can optionally choose to use the same asymmetric key when creating a new version.
So going off the comment above I was able to get this to work.
#Password for the pfx file of the original cert
$password = ConvertTo-SecureString -String '<UPDATETHIS>' -AsPlainText -Force
#import the orginal cert with private key
Import-AzureKeyVaultCertificate -VaultName 'VaultName' -Name 'Certname' -FilePath 'PATHTOPFXFILE' -Password $password
#set the policy to allow key reuse if the CA will create a new signed cert from the existing CSR
Set-AzureKeyVaultCertificatePolicy -VaultName 'VaultName' -Name 'Certname' -ReuseKeyOnRenewal $true
#create a cert policy object from the existing cert
$certpolicy = Get-AzureKeyVaultCertificatePolicy -VaultName 'VaultName' -Name 'Certname'
#create a pending cert operation, you can pull a new CSR from this if need be
$certificateOperation = Add-AzureKeyVaultCertificate -VaultName 'VaultName' -Name 'Certname' -CertificatePolicy $certpolicy
#import the new signed cert into KeyVault for issuing
Import-AzureKeyVaultCertificate -VaultName 'VaultName' -Name 'Certname' -FilePath 'PATHTONEWSIGNEDCERTINCRT'

Resources