I have a VSTS library variable groups connected to my key-vaults in Azure:
More about it you can read here:
https://learn.microsoft.com/en-us/azure/devops/pipelines/library/variable-groups?view=vsts&tabs=yaml
In key vaults in Azure I have a list of secrets and list of certificates.
Example key vault secrets:
AppInsightsInstrumentationKey
CacheConnectionString
Example certificate:
GlobalCertificate
Now I can access as variables in releasing these variables, by simple syntax:
$(GlobalCertificate)
$(AppInsightsInstrumentationKey)
$(CacheConnectionString)
My goal is to read thumprint of certificate localted in variable $(GlobalCertificate). What's the way to get it?
I know this is old but I found this article searching for the same thing and haven't been able to find a solution elsewhere.
I've been able to sort it out with Powershell but it's bizarre what's required considering we've already uploaded the PFX into the key vault. I also save my pfx passwords into keyvault but if you don't, substitute the variable in the $pwd line with your own value.
In the Azure DevOps Pipeline, create a Powershell task. Script is:
#Convert the Secure password that's presented as plain text back into a secure string
$pwd = ConvertTo-SecureString -String $(GlobalCertificate-Password) -Force -AsPlainText
#Create PFX file from Certificate Variable
New-Item Temp-Certificate.pfx -Value $(GlobalCertificate)
#Import the PFX certificate from the newly created file and password. Read the thumbprint into variable
$Thumbprint = (Import-PfxCertificate -CertStoreLocation Cert:\CurrentUser\My -FilePath Temp-Certificate.pfx -Password $pwd).Thumbprint
Write-Host $Thumbprint
#Rest of Script below or set environment variable for rest of Pipeline
Write-Host "##vso[task.setvariable variable=Thumbprint]$Thumbprint"
Related
I am trying to automate VM creation in azure.
I want to prompt users to fill in credentials and then store them in my azure key vault as a secret. the problem is it automatically transfers the password to a secure string thus I can't store the value...
In fact Azure expects you to pass a SecureString to the KeyVault with Set-AzKeyVaultSecret. So you don't need to convert it to plain text.
Set-AzKeyVaultSecret in Docs
# Read in Credentials (Password will be of type SecureString)
$Credential = Get-Credential
# Save password in your key vault
Set-AzKeyVaultSecret -Name "MySecret" -VaultName "MyKeyVaultName" -SecretValue $Credential.Password
And to make it more complete. Here's how you can retrieve it as plain text.
# Plain password
$Credential = Get-Credential
$Credential.GetNetworkCredential().Password
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.
I got this problem:
I need to connect to an azure subscrition from a powershell script used on a build pipeline, but for security requirements i can't write user and password on the code, so i have a pfx certificate with the credentials.
Right now i'm using the task named dowload secure file, to put the certificate on the build. Then i'm trying to access the certificate from the powershell code.
I already test the code on my machine, but when i'm trying to use it on the build pipeline i cannot access the certificate with this
and i got an error like this
Logging in...
D:\a\1\s\Scripts\fileName.ps1 : The Script does not work :The term 'cert.secureFilePath' is not recognized
as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was
included, verify that the path is correct and try again.
$tenantId = "xxxxxxxxxxx"
$appId = "zzzzz"
$cert = %DOWNLOADSECUREFILE_SECUREFILEPATH%
$certThumbprint = $cert.Thumbprint
Write-Host "Logging in...";
Login-AzureRmAccount `
-ServicePrincipal `
-TenantId $tenantId `
-ApplicationId $appId `
-CertificateThumbprint $certThumbprint
Tasks used on the build pipeline
The full path of the downloaded Secure file is stored to the $env:DOWNLOADSECUREFILE_SECUREFILEPATH environment variable. For more information about Download Secure File task please refer to this document.
We could get the certThumbprint with following code
$CertificatePath = "$env:DOWNLOADSECUREFILE_SECUREFILEPATH"
$sSecStrPassword = "xxxxx"
$certificateObject = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$certificateObject.Import($CertificatePath, $sSecStrPassword, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::DefaultKeySet)
$thumbprint = $certificateObject.Thumbprint
If we don't want to use to user and password in the code directly. We could use the Azure Pipeline library. And we could reference it in the code.
If you want to encrypt and securely store the value, choose the "lock" icon at the end of the row. When you're finished adding variables, choose Save
You access the value of the variables in a linked variable group in exactly the same way as variables you define within the pipeline itself. For example, to access the value of a variable named customer in a variable group linked to the pipeline, use $(customer) in a task parameter or a script. However, secret variables (encrypted variables and key vault variables) cannot be accessed directly in scripts - instead they must be passed as arguments to a task
If I add a Variable named sSecStrPassword in the library. Then the code could be changed as following:
function GetThumbprintPFX {
param([string] $CertificatePath, [string]$Password)
$certificateObject = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$certificateObject.Import($CertificatePath, $Password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::DefaultKeySet)
$thumbprint = $certificateObject.Thumbprint
return $thumbprint
}
$thumbprint = GetThumbprintPFX -CertificatePath $env:DOWNLOADSECUREFILE_SECUREFILEPATH -Password '$(sSecStrPassword)'
Write-Host "$thumbprint"
Test Result:
For more information about Variable groups, please refer to this link. And Azure Key Vault is another choice for security requirements.
Update:
The following is the detail steps to use the pfx file in the Azure Devops pipeline.
prepare a .pfx file.
Add a download secure file task and upload the pfx file.
create a variable group and add a variable named sSecStrPassword
link the variable to the build
Add powershell script task and add the following script in it.
# Write your powershell commands here.
Write-Host $env:DOWNLOADSECUREFILE_SECUREFILEPATH
function GetThumbprintPFX {
param([string] $CertificatePath, [string]$Password)
$certificateObject = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
$certificateObject.Import($CertificatePath, $Password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::DefaultKeySet)
$thumbprint = $certificateObject.Thumbprint
return $thumbprint
}
$thumbprint = GetThumbprintPFX -CertificatePath $env:DOWNLOADSECUREFILE_SECUREFILEPATH -Password '$(sSecStrPassword)'
Write-Host "$thumbprint"
queue the build and check the result.
We bought a certificate via Azure and would like to use it on same VM.
We just need .pfx file.
We tried almost everything and we are getting next error:
"You do not have permission to get the service prinicipal information
needed to assign a Key Vault to your certificate. Please login with an
account which is either the owner of the subscription or an admin of
the Active Directory to configure Key Vault settings."
But we have permissions...
#Sasha, there are not a lot of details to go on here and I hate to state the obvious given you've tried everything, but the error message is pretty clear - "You do not have permission to get the service principal information needed".
Some things to clarify and check:
Did you buy an Azure "App Service Certificate"?
Is the certificate in 'issued' status?
Are you logged in as the subscription owner or did the owner give you admin access to their subscription? The latter is not good enough, I believe.
Did you complete the three-step validation process?
If you did all of that, your certificate is now stored in an Azure Key Vault. When you create an Azure Key Vault, there is an advanced access policy option to "Enable Access to Azure Virtual Machines for deployment" (see image). Its help info reads, "Specifies whether Azure Virtual Machines are permitted to retrieve certificates stored as secrets from the key vault."
That said, since you want a .pfx file, below is a sample PowerShell script extracted from MSDN blogs to do just that. Provide appropriate values for the four "$" parameters below and save the script as copyasc.ps1.
$appServiceCertificateName = ""
$resourceGroupName = ""
$azureLoginEmailId = ""
$subscriptionId = ""
Login-AzureRmAccount
Set-AzureRmContext -SubscriptionId $subscriptionId
$ascResource = Get-AzureRmResource -ResourceName $appServiceCertificateName -ResourceGroupName $resourceGroupName -ResourceType "Microsoft.CertificateRegistration/certificateOrders" -ApiVersion "2015-08-01"
$keyVaultId = ""
$keyVaultSecretName = ""
$certificateProperties=Get-Member -InputObject $ascResource.Properties.certificates[0] -MemberType NoteProperty
$certificateName = $certificateProperties[0].Name
$keyVaultId = $ascResource.Properties.certificates[0].$certificateName.KeyVaultId
$keyVaultSecretName = $ascResource.Properties.certificates[0].$certificateName.KeyVaultSecretName
$keyVaultIdParts = $keyVaultId.Split("/")
$keyVaultName = $keyVaultIdParts[$keyVaultIdParts.Length - 1]
$keyVaultResourceGroupName = $keyVaultIdParts[$keyVaultIdParts.Length - 5]
Set-AzureRmKeyVaultAccessPolicy -ResourceGroupName $keyVaultResourceGroupName -VaultName $keyVaultName -UserPrincipalName $azureLoginEmailId -PermissionsToSecrets get
$secret = Get-AzureKeyVaultSecret -VaultName $keyVaultName -Name $keyVaultSecretName
$pfxCertObject=New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList #([Convert]::FromBase64String($secret.SecretValueText),"", [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
$pfxPassword = -join ((65..90) + (97..122) + (48..57) | Get-Random -Count 50 | % {[char]$_})
$currentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath
[Environment]::CurrentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath
[io.file]::WriteAllBytes(".\appservicecertificate.pfx", $pfxCertObject.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, $pfxPassword))
Write-Host "Created an App Service Certificate copy at: $currentDirectory\appservicecertificate.pfx"
Write-Warning "For security reasons, do not store the PFX password. Use it directly from the console as required."
Write-Host "PFX password: $pfxPassword"
Type the following commands in PowerShell console to execute the script:
Powershell –ExecutionPolicy Bypass
.\copyasc.ps1
Once the script is executed, you would see a new file in the current directory called ‘appservicecertificate.pfx’. This is a password protected PFX, the PowerShell console would display the corresponding password.
I am trying to define an ARM template for my resource group. Ultimately I'm trying to replicate what I have to do manually by navigating to the SSL certificates tab for an App Service within the portal.
I've uploaded a PFX file to the Secrets tab of my KeyVault. I've granted Get access to the global RM service principal.
At the moment this is what my Microsoft.Web/certificates resource looks like in my template. It is just defined as a resource at the top level of the resource group, and not as a sub-resource of a website or anything like that:
{
"type":"Microsoft.Web/certificates",
"name": "signingCredentials",
"location": "[parameters('region')]",
"apiVersion": "2015-08-01",
"properties": {
"keyVaultId": "<My KeyVault ID>",
"keyVaultSecretName": "<My Secret Name>"
}
}
When I attempt to deploy this template I receive the message:
The parameter KeyVault Certificate has an invalid value
I haven't been able to find any documentation on this parameter and what value it would be expecting. I'm assuming it's missing from the properties section in the resource. So far anything I've found on the subject only references keyVaultId and keyVaultSecretName.
What am I doing wrong? Is what I'm trying to accomplish even possible?
The problem does not appear to be caused by my template, but something with how the certificate was uploaded to the KeyVault through the UI. This article provided me a script to upload the file directly to the KeyVault using powershell.
$pfxFilePath = "F:\KeyVault\PrivateCertificate.pfx"
$pwd = "[2+)t^BgfYZ2C0WAu__gw["
$flag = [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable
$collection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
$collection.Import($pfxFilePath, $pwd, $flag)
$pkcs12ContentType = [System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12
$clearBytes = $collection.Export($pkcs12ContentType)
$fileContentEncoded = [System.Convert]::ToBase64String($clearBytes)
$secret = ConvertTo-SecureString -String $fileContentEncoded -AsPlainText –Force
$secretContentType = 'application/x-pkcs12'
Set-AzureKeyVaultSecret -VaultName akurmitestvault -Name keyVaultCert -SecretValue $Secret -ContentType $secretContentType # Change the Key Vault name and secret name
Using the Get-AzureKeyVault script from Jambor's answer, I am unable to see any difference between the certificate uploaded in the UI. I even changed the content type of my uploaded certificate from Certificate to application/x-pcks2 and it still did not work. Seems like it might possibly a bug in the UI, or just a difference in how the powershell script handles it.
The parameter KeyVault Certificate has an invalid value
It seems that this issue is not caused by your template. We can refer to this article to check it. From the error message, it shows me that the certification name is incorrect. We can use Get-AzureKeyVaultSecret to get its name. The following is details:
As above screenshot, the value "kvcertificate" is the value we expected.