I am creating a certificate inside Azure Key Vault and then attempting to export it with private key as a PFX.
# Create new Certificate in Key Vault
$policy = New-AzKeyVaultCertificatePolicy -SecretContentType "application/x-pkcs12" -SubjectName "CN=contoso" -IssuerName "Self" -ValidityInMonths 12 -ReuseKeyOnRenewal -KeySize 4096 -KeyType 'RSA-HSM';
Add-AzKeyVaultCertificate -VaultName $VaultName -Name $ADServicePrincipalCertificateName -CertificatePolicy $policy;
# From https://learn.microsoft.com/en-us/powershell/module/az.keyvault/get-azkeyvaultcertificate?view=azps-5.8.0
# Export new Key Vault Certificate as PFX
$securePassword = "fBoFXYD%dg^Q" | ConvertTo-SecureString -AsPlainText -Force; # This is a throwaway password
$certificate = Get-AzKeyVaultCertificate -VaultName $VaultName -Name $ADServicePrincipalCertificateName;
$secret = Get-AzKeyVaultSecret -VaultName $vaultName -Name $certificate.Name -AsPlainText;
$secretByte = [Convert]::FromBase64String($secret)
$x509Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($secretByte, "", "Exportable,PersistKeySet")
$type = [System.Security.Cryptography.X509Certificates.X509ContentType]::Pfx
$pfxFileByte = $x509Cert.Export($type, $securePassword);
[System.IO.File]::WriteAllBytes("C:\Repos\Certificate.pfx", $pfxFileByte)
Get-PnPAzureCertificate -Path "C:\Repos\Certificate.pfx" -Password $securePassword
However, the PFX file is not valid
Error with Get-PnPAzureCertificate
Error with Certificate Import
Any ideas? Using Import-AzKeyVaultCertificate is not an option because there's a bug with it in environments that have policies that forces key lengths
Also, might be worth mentioning that I am using PowerShell 7
According to my test, we need to change keytype as RSA when we create cert policy.
For example
$VaultName=""
$ADServicePrincipalCertificateName=""
$policy = New-AzKeyVaultCertificatePolicy -SecretContentType "application/x-pkcs12" `
-SubjectName "CN=contoso.com" -IssuerName "Self" `
-ValidityInMonths 12 -ReuseKeyOnRenewal `
-KeySize 4096 -KeyType 'RSA';
Add-AzKeyVaultCertificate -VaultName $VaultName -Name $ADServicePrincipalCertificateName -CertificatePolicy $policy;
Start-Sleep -Seconds 30
# From https://learn.microsoft.com/en-us/powershell/module/az.keyvault/get-azkeyvaultcertificate?view=azps-5.8.0
# Export new Key Vault Certificate as PFX
$securePassword = "fBoFXYD%dg^Q" | ConvertTo-SecureString -AsPlainText -Force; # This is a throwaway password
$certificate = Get-AzKeyVaultCertificate -VaultName $VaultName -Name $ADServicePrincipalCertificateName;
$secret = Get-AzKeyVaultSecret -VaultName $vaultName -Name $certificate.Name -AsPlainText;
$secretByte = [Convert]::FromBase64String($secret)
$x509Cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($secretByte, "", "Exportable,PersistKeySet")
$type = [System.Security.Cryptography.X509Certificates.X509ContentType]::Pfx
$pfxFileByte = $x509Cert.Export($type, $securePassword);
[System.IO.File]::WriteAllBytes("E:\Certificate.pfx", $pfxFileByte)
Get-PnPAzureCertificate -Path "E:\Certificate.pfx" -Password $securePassword
Related
I have a powershell script that is attempting to list all the expired secrets of my Azure Key Vault. Unfortunately I'm struggling to do this.
This is how I retrieve sercrets. But what do I need to add to get the expiration of all secrets? Then delete those that are expired? I'm guessing I'll need to set an access policy.
Select-AzSubscription -Subscription "My subscriptsion"
Set-AzKeyVaultAccessPolicy -VaultName "testKeyVaultPwsh" -UserPrincipalName "mystuff#domain.com" -PermissionsToSecrets get,set,delete
#Retrieve secret
$secret = Get-AzKeyVaultSecret -VaultName "testKeyVaultPwsh" -Name "ExamplePassword" -AsPlainText
You can delete the expired secrets using below commands .(Make sure
you have get,set,delete access policies set and given proper
permissions )
I have tried in my environment and able to delete expired secrets sussessfully.
After checking expiry using
$exp =Get-AzKeyVaultSecret -VaultName $vaultname -Name $secretname | Select-Object Name,Expires
$exp
I created secrets and have secrets expired.
Commands:
$vaultname= “<keyvaultname>”
$secrets= Get-AzKeyVaultSecret -VaultName $vaultname
$secretnames =$secrets.Name
$current_date=Get-Date
Foreach($secretname in $secretnames)
{
$exp =Get-AzKeyVaultSecret -VaultName $vaultname -Name $secretname | Select-Object Expires
$keyvaultsecretvexpirydate =[datetime]($exp.Expires)
$timediff=NEW-TIMESPAN -Start $current_date -End $keyvaultsecretvexpirydate
$days_until_expiration=$timediff.Days
Write-Output “days_until_expiration of secret named $secretname is :$days_until_expiration”
Write-Output “ ”
if ($days_until_expiration -eq 0)
{
Write-Output "Secret named $secretname got expired “
Write-Output “removing expired secret : $secretname”
Write-Output “ ”
Remove-AzKeyVaultSecret -VaultName $vaultname -Name $secretname
}
}
Confirm to delete by typing Y and refresh the secrets page to see the expired secret being removed/deleted.
References:
KeyVaultSecretExpirationAlerts |github
remove-azkeyvaultsecret | microsoftdocs
As you can see from the code below I can upload on certificate at a time, but the problem is it wipes out all of the existing certificates when doing so.
$Tenant_ID = '00000000-0000-0000-0000-000000000000'
$Subscription_ID = '00000000-0000-0000-0000-000000000000'
$Azure_PassWord = (Get-StoredCredential -Target 'Domain' -Type Generic -AsCredentialObject).Password
$UserName = "$($env:USERNAME)#Google.com"
$EncryptedPassword = ConvertTo-SecureString $Azure_PassWord -AsPlainText -Force
$Credential = New-Object System.Management.Automation.PsCredential($UserName,$EncryptedPassword)
$AzureConnection = (Connect-AzAccount -Credential $Credential -Tenant $Tenant_ID -Subscription $Subscription_ID -WarningAction 'Ignore').context
$AzureContext = (Set-AzContext -SubscriptionName $Subscription_ID -DefaultProfile $AzureConnection)
$Application_ID = '00000000-0000-0000-0000-000000000000'
$PFX_FileName = "Azure_Dev_V2"
$Cert_Password = "123456"
$Cert_Password = ConvertTo-SecureString -String $Cert_Password -Force -AsPlainText
$CurrentDate = Get-Date
$EndDate = $CurrentDate.AddYears(10)
$certificatePath = "C:\FilePath\Certificates\Certs\$($PFX_FileName).pfx" # OR Get-ChildItem -Path cert:\localmachine\my\$($Certificate_Thumbprint)
$cert = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2($certificatePath, $Cert_Password)
$keyValue = [System.Convert]::ToBase64String($cert.GetRawCertData())
$Azure_App_Registration = Get-AzADApplication -ApplicationId $Application_ID -DefaultProfile $AzureContext
New-AzADAppCredential -ApplicationObject $Azure_App_Registration -CertValue $keyValue -EndDate $EndDate -StartDate $CurrentDate
Connect-AzAccount -Subscription $Subscription_ID -ApplicationId $Azure_App_Registration.AppId -Tenant $Tenant_ID -CertificateThumbprint $cert.Thumbprint | Out-Null
Get-AzADAppCredential -ApplicationId $Azure_App_Registration.AppId | Where-Object {$_.DisplayName -match "CN=Azure_Dev_V2"}
In the Azure portal multiple certificates can be uploaded manually, and they will not delete the existing certificates.
EDIT: If bulk upload is not possible then how would I go about making sure the existing certificates that are in the Azure AD App Registration cert store do not get deleted ?
Thanks in Advance.
I'm not able to read the value of one of my secrets in Key Vault. I'm logged in with my Azure account and I have full permission to the selected Key Vault.
I'm able to retrieve a list of available secrets using the following command:
$keyVaultValue = (Get-AzKeyVaultSecret -VaultName 'name-of-key-vault')
And then see the content when I write:
Write-Output $keyVaultValue
But when I ask for a specific key it just returns null:
$keyVaultValue = (Get-AzKeyVaultSecret -VaultName 'name-of-key-vault' -Name 'my-secret-name').SecretValueText
I've checked the name and subscription ID and everything is correct. I can easily read the value from the portal, but no from powershell on my Windows PC.
Any suggestions?
SecretValueText is deprecated, You can use the following syntax the retrieve the value as plain text:
$keyVaultValue = Get-AzKeyVaultSecret -VaultName 'name-of-key-vault' -Name 'my-secret-name'
$keyVaultValue.SecretValue | ConvertFrom-SecureString -AsPlainText
More information and examples can be found here.
If you want to show all key-vault secrets name and their key values then you can use this in powershell
$secrets=Get-AzKeyVaultSecret -VaultName 'key-vault-name'
$secrets | % {Write-Output "$($_.name) $($(Get-AzKeyVaultSecret -VaultName $_.VaultName -Name $_.Name).SecretValue | ConvertFrom-SecureString -AsPlainText)" }
Try using this function:
function GetSecretValue
{
param(
[String]$keyvaultName,
[String]$secretName
)
Write-Host "Retrieving secret $secretName from $keyvaultName... " -NoNewline
if ((Get-Command Get-AzKeyVaultSecret).ParameterSets.Parameters.Name -contains "AsPlainText")
{
# Newer Get-AzKeyVaultSecret version requires -AsPlainText parameter
$secretValue = Get-AzKeyVaultSecret -VaultName $keyvaultName -Name $secretName -AsPlainText
}
else
{
$secretValue = (Get-AzKeyVaultSecret -VaultName $keyvaultName -Name $secretName).SecretValueText
}
Write-Host "ok"
return $secretValue
}
Usage example:
$keyVaultValue = GetSecretValue "name-of-key-vault" "my-secret-name"
I generated a pfx blob using this script :
$appId = Read-Host "Enter application ID of service principal"
$adApp = (Get-AzureRmADApplication -ApplicationId $appId)[0]
$spnId = (Get-AzureRmADServicePrincipal -ServicePrincipalName $adApp.IdentifierUris[0])[0].Id.Guid
$endDate = (Get-Date).AddYears(1)
$certSelfSigned = New-SelfSignedCertificateEx -Subject "CN=$spnId" -StoreLocation CurrentUser -NotAfter $endDate -Exportable -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider"
$publicKey = [System.Convert]::ToBase64String($certSelfSigned.GetRawCertData())
New-AzureRmADSpCredential -ServicePrincipalObjectId $spnId -CertValue $publicKey -EndDate $certSelfSigned.GetExpirationDateString()
# TEST: Login-AzureRmAccount -ServicePrincipal -CertificateThumbprint $certSelfSigned.Thumbprint -ApplicationId $appId -TenantId <guid>
$storeLocation = [Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser
$storeName = [Security.Cryptography.X509Certificates.StoreName]::My
$store = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Store #($storeName, $storeLocation)
$store.Open([Security.Cryptography.X509Certificates.OpenFlags]::OpenExistingOnly)
$findType = [System.Security.Cryptography.X509Certificates.X509FindType]::FindByThumbprint
$cert = $store.Certificates.Find($findType, $certSelfSigned.Thumbprint, $false)
$pfxBlob = [System.Convert]::ToBase64String($cert.Export([Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12))
$store.Close()
"THUMBPRINT: $($certSelfSigned.Thumbprint)"
"PFX BLOB: `n$pfxBlob"
I copied the pfx blob and made a .pfx file and in azure portal when I create a new certificate for an automation account and upload the file I created before it gives me internal server error.
What is the correct format of .pfx file and what is the password that I will be using to set and how will I use a thumbprint?
So that our Azure Web Apps can access Azure Key Vault, we use certificates and application registrations with service principals.
After generating a certificate, we use the following Azure PowerShell to create an application registration and service principal and then give the service principal access to the Azure Key Vault. The Web App then loads this certificate and uses it to authenticate with Azure Key Vault. It all works fine.
$subscriptionId = Read-Host -Prompt 'SubscriptionId'
Select-AzureRmSubscription -SubscriptionId $subscriptionId
$resourceGroupName = Read-Host -Prompt 'Resource group name'
$vaultName = Read-Host -Prompt 'Vault name'
$certificateName = Read-Host -Prompt 'Certificate name'
$applicationName = Read-Host -Prompt 'Application name'
$certificatePath = Join-Path (Get-Location) "$certificateName.cer"
$certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$certificate.Import($certificatePath)
$rawCertData = [System.Convert]::ToBase64String($certificate.GetRawCertData())
$now = [System.DateTime]::UtcNow
$application = New-AzureRmADApplication -DisplayName $applicationName -HomePage "https://$applicationName" -IdentifierUris "https://$applicationName" -CertValue $rawCertData -StartDate $now -EndDate $now.AddYears(1)
$servicePrincipal = New-AzureRmADServicePrincipal -ApplicationId $application.ApplicationId
Set-AzureRmKeyVaultAccessPolicy -ResourceGroupName $resourceGroupName -VaultName $vaultName -ServicePrincipalName "https://$applicationName" -PermissionsToSecrets get
The problem is this line:
$application = New-AzureRmADApplication -DisplayName $applicationName -HomePage "https://$applicationName" -IdentifierUris "https://$applicationName" -CertValue $rawCertData -StartDate $now -EndDate $now.AddYears(1)
It sets the StartDate and EndDate to the current date and the current date plus 1 year. In hindsight I think it should have been the certificate start and end date:
$application = New-AzureRmADApplication -DisplayName $applicationName -HomePage "https://$applicationName" -IdentifierUris "https://$applicationName" -CertValue $rawCertData -StartDate` $certificate.NotBefore -EndDate $certificate.NotAfter
My question is - what will happen after $now.AddYears(1)? The certificate was created with a 3 year expiry but the application registration/service principal was created with an earlier EndDate - but what does that mean?
From the docs, it's the effective end date for the credential so I would assume the credential would stop working at that time.
https://learn.microsoft.com/en-us/powershell/module/azurerm.resources/new-azurermadapplication?view=azurermps-5.1.1
You can use New-AzureRmADAppCredential to roll the secret before that time.
https://learn.microsoft.com/en-us/powershell/module/azurerm.resources/new-azurermadappcredential?view=azurermps-5.1.1