I am trying to copy a certificate from one key vault into another without persisting it on local machine. I looks like Azure KeyVault CLI only supports file-based certificate import like this:
# download cert
az keyvault certificate download --file $certFileName --vault-name $sourceAkv -n $certName
# import cert
az keyvault certificate import --file $certFileName --vault-name $destAkv -n $certName
Is there any way to pass an object or string instead? In Azure Powershell module this is possible:
Import-AzureKeyVaultCertificate -VaultName $DestinationVaultName -Name $CertificateName -CertificateString $secretText.SecretValueText
Thoughts?
I found something like this can work in PowerShell to export the certificate and key as an object, then import it into another keyvault without having to save it as a temporary PFX file.
$CertName = 'mycert'
$SrcVault = 'mysourcekeyvault'
$DstVault = 'mydestinationkeyvault'
$cert = Get-AzKeyVaultCertificate -VaultName $SrcVault -Name $CertName
$secret = Get-AzKeyVaultSecret -VaultName $SrcVault -Name $cert.Name
$secretValueText = '';
$ssPtr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secret.SecretValue)
try {
$secretValueText = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($ssPtr)
}
finally {
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($ssPtr)
}
$secretByte = [Convert]::FromBase64String($secretValueText)
$x509Cert = new-object System.Security.Cryptography.X509Certificates.X509Certificate2
$x509Cert.Import($secretByte, "", "Exportable,PersistKeySet")
Import-AzKeyVaultCertificate -VaultName $DstVault -Name $CertName -CertificateCollection $x509Cert
It seems that there is no way to just import the certificate context to the Azure Keyvault as you say. It only has the parameter dependant on the certificate file.
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
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
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?
I'm building a set of scripts and templates to create a Service Fabric cluster in Azure. I've got a script that creates a key vault and a self-signed certificate and successfully uploads it to the vault. Another script creates the cluster but it's hitting an error at the point that the certs are linked to the VMs. The error from the New-AzureRmResourceGroupDeployment command is:-
{
"status": "Failed",
"error": {
"code": "ResourceDeploymentFailure",
"message": "The resource operation completed with terminal provisioning state 'Failed'.",
"details": [
{
"code": "KeyVaultAccessForbidden",
"message": "Key Vault https://VAULT-NAME.vault.azure.net/secrets/clusterCert/SECRET-ID either has not been enabled for deployment or the vault id provided, /subscriptions/SUBSCRIPTION-ID/resourceGroups/jg-sf/providers/Microsoft.KeyVault/vaults/VAULTNAME, does not match the Key Vault's true resource id."
}
]
}
}
VAULT-NAME, SUBSCRIPTION-ID and SECRET-ID are all correct. The key vault has been created with the parameter "enabledForTemplateDeployment": true, as evidenced in the following screenshot.
My scripts and templates can be seen in GitHub - https://github.com/goochjs/azure-testbed.
How do I diagnose the issue?
Thanks,
Jeremy.
How do you create the key vault, I use the following script to create key vault and get CertificateURL.
New-AzureRmKeyVault -VaultName $KeyVaultName -ResourceGroupName $ResourceGroup -Location $Location -sku standard -EnabledForDeployment
#Creates a new selfsigned cert and exports a pfx cert to a directory on disk
$NewCert = New-SelfSignedCertificate -CertStoreLocation Cert:\CurrentUser\My -DnsName $CertDNSName
Export-PfxCertificate -FilePath $CertFileFullPath -Password $SecurePassword -Cert $NewCert
Import-PfxCertificate -FilePath $CertFileFullPath -Password $SecurePassword -CertStoreLocation Cert:\LocalMachine\My
#Reads the content of the certificate and converts it into a json format
$Bytes = [System.IO.File]::ReadAllBytes($CertFileFullPath)
$Base64 = [System.Convert]::ToBase64String($Bytes)
$JSONBlob = #{
data = $Base64
dataType = 'pfx'
password = $Password
} | ConvertTo-Json
$ContentBytes = [System.Text.Encoding]::UTF8.GetBytes($JSONBlob)
$Content = [System.Convert]::ToBase64String($ContentBytes)
#Converts the json content a secure string
$SecretValue = ConvertTo-SecureString -String $Content -AsPlainText -Force
#Creates a new secret in Azure Key Vault
$NewSecret = Set-AzureKeyVaultSecret -VaultName $KeyVaultName -Name $KeyVaultSecretName -SecretValue $SecretValue -Verbose
#Writes out the information you need for creating a secure cluster
Write-Host
Write-Host "Resource Id: "$(Get-AzureRmKeyVault -VaultName $KeyVaultName).ResourceId
Write-Host "Secret URL : "$NewSecret.Id
Write-Host "Thumbprint : "$NewCert.Thumbprint
More information about this, please refer to this blog.
I suggest you could check your Resource Id format. The correct format is like /subscriptions/***************/resourceGroups/westus-mykeyvault/providers/Microsoft.KeyVault/vaults/shuisfsvault. You could create SF cluster on Azure Portal firstly.
If it still does not work, I suggest you could check your key vault, do you give enough permission to it?
Note: For test, you could give all permission to the user.