Provide access to private keys -- Commandline vs Powershell

Provide access to private keys -- Commandline vs Powershell

  • Comments 2
  • Likes

On www.microsoft.com we have a number of applications that use certs to  access other web services, the way we do is by installing the certificate with the private key into the local machine store and provide access to the application pool identity to the private key and use the serial number or the thumbprint of the certificate in the web.config of the application. One of the key challenge was to script out the private key access to the application pool identity across the server farm . There are 2 ways to do it

  • Command line - Using Winhttpcertcfg
  • Powershell - Just to explore the new cooler side

 Winhttpcertcfg was primarily for windows 2000/2003 but it works well on windows 2008 & r2 :). You can download it at http://www.microsoft.com/downloads/en/details.aspx?familyid=c42e27ac-3409-40e9-8667-c748e422833f&displaylang=en  and install it or extract contents out of it you only need winhttpcertcfg.exe. Copy it to your utility server . As always I am using server names out of a text file, also using psexec as winhttpcertcfg does not have remoting capabilities.( If  you do not want to do psexec you can use the Powershell way shown in the next section)

for /f %i in (servers.txt) do psexec \\%i  /U domain\uname /P "XXX" \\utilityserver\tools\winhttpcertcfg\winhttpcertcfg.exe -g -c LOCAL_MACHINE\MY -s "certsubjectname" -a "\network service"

where network service is the  name of the application pool identity

You can also install the cert if you have the pfx and give access to the apppool identity in  a single step using the below

for /f %i in (servers.txt) do psexec \\%i /U domain\uname /P "XXX" \\utilityserver\tools\winhttpcertcfg\winhttpcertcfg.exe -i \\certserver\certs\foo.pfx  -c LOCAL_MACHINE\MY  -a "\network service"

Let us do the same using Powershell, it turned out to be a bit more complex following is a script I wrote that takes in a thumbprint and apppool identity that needs access as the parameter.

(Disclaimer : Please use this at your own risk , test once , twice , thrice in your test environment to make sure it produces intended results)

if ($args[0] -eq $null -or $args[1] -eq $null){

      Write-Host "Insufficient parameters"
      Write-Host "Usage:certaccess.ps1 thumbprint username"

      exit}

else {$TP=$args[0]
$uname=$args[1]
$keyname=(((gci cert:\LocalMachine\my | ? {$_.thumbprint -like $tp}).PrivateKey).CspKeyContainerInfo).UniqueKeyContainerName
$keypath = $env:ProgramData + "\Microsoft\Crypto\RSA\MachineKeys\"
$fullpath=$keypath+$keyname
icacls $fullpath /grant $uname`:RX
}

Save the above script as certaccessgrant.ps1. Make sure all the machines you are going to run the script is set up for powershell remoting and has the cert installed. After that

invoke-command -computername (get-content servers.txt) -filepath c:\temp\certaccessgrant.ps1 -argumentlist ‎118630e5ce55a52dwhlklklSWEwe42qbac2bb4b47bf, testuser

where 18630e5ce55a52dwhlklklSWEwe42qbac2bb4b47b is the thumbprint and testuser is the user name that is apppool identity that needs access.

Also if you are dealing with 1 or 2 machines (Windows 2008 & up)  you can go the slowest GUI way of  start --> run -->MMC--> certificates --> local machine --> cert store

Right click the cert , manage private keys and provide access  to the apppool identity on all the machines. In windows 2003 the GUI way is using this tool wsecertificate2.exe details here at http://msdn.microsoft.com/en-us/library/ms824698.aspx.

 


 

Comments
  • Nice function, my question is, how are you obtaining the thumbprint?

    Comment:

    $keypath = $env:ProgramData + "\Microsoft\Crypto\RSA\MachineKeys\"

    There is an error there, you didnt enapsulate $env into " " so it's catching the plus into $keypath.

    Here is how I'm grabbing the thumbprint:

    $certout=certutil -f -importpfx -p $certpassin $certnamein

    scrub for cert name (i was asked to keep this part out)

    ($tp=Get-ChildItem cert:\LocalMachine\MY | Where-Object {$_.Subject -eq $iiscert})

    $keyname=$tp.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName

  • This is an amazing blog. Thank you very much for your help. I have tried the PowerShell script and it works fine for me. I have only one question, which user shall I give the Read permission without compromising my security to the outside world? I have tried 'Authenticated Users' or 'users' and both work for me.  'System Network' didn't work for me.

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment