Using Azure Blob Storage as a highly-available CDP and AIA location for your internal PKI

I inherited a Windows PKI setup that had the Root CA installed on a Windows Server 2008 R2 Domain Controller, with the root certificate signed with a SHA1 hash. That DC was in the process of being decommissioned, and I also wanted to move to a better PKI design.

I’d previously set up 2-tier Windows PKI infrastructures with offline Root CAs, so I knew that this was the route I was going to take again (note that this is for an SMB environment).

There are plenty of good guides on configuring a 2-tier Windows PKI. In my opinion the best of the crop at the time of writing is probably Timothy Gruber’s 7-part guide to deploying a PKI on Windows Server 2016.

I would, however, highly recommend reading up on the topic before blindly following a guide. PKI is a complex topic, and you want to make the correct decisions up-front to avoid issues later on. Some additional recommended reading:

There are many recommendations around where to publish/advertise the AIA and CDP. Some of these include:

  • In the default location – LDAP and locally via HTTP on the CA server
  • To an internally-hosted web server, and then reverse-proxy connections from the Internet
  • To an externally-hosted web server

I’d already used Azure Blob Storage to store some other small files, so I thought I’d have a go at seeing if it’s able to be used for AIA and CDP storage. As it turns out, it’s quite easy to do, and you don’t even need to mess around with double-escaping like you would need to if you hosted on IIS or an Azure Web App:

TLDR; The CA saves the CRL files to the default location of C:\Windows\System32\CertSrv\CertEnroll, and AzCopy then copies them up to an Azure Blob Storage account that’s configured with a custom domain of

Here are the requirements to get this all set up:

  1. CDP and AIA on Enterprise/issuing CA configured to save to the default C: location, and also advertise availability at
  2. AzCopy installed on the Enterprise CA
  3. Allow outbound HTTPS/443 from the Enterprise CA to Azure Blob Storage
  4. An Azure Storage Account with blob storage configured for HTTP access. I’d recommend at least Zone Redundant Storage for availability.
  5. A custom domain name for the above storage account
  6. A folder in the blob storage named ‘pki’ (not necessary, but you’ll need to adjust the script if you don’t use this folder)
  7. A SAS key with read/write/change access to blob storage only (don’t assign more access than necessary)
  8. A scheduled task running hourly as NETWORK SERVICE to call the below PowerShell script
  9. Ensure that NETWORK SERVICE has modify permissions to the log location (default is %ProgramData%\ScriptLogs\Invoke-UpdateAzureBlobPKIStorage.log)

You’ll need to manually copy your offline root CA certificate and CRL to the blob storage location. This script is designed to copy the much more frequent CRLs and Delta CRLs from your Enterprise CA to blob storage.

As it turns out, AzCopy is perfect for this because it supports the /XO parameter to only copy new files. That allows us to schedule the script to run hourly without incurring additional data transfer costs for files that already exist in the storage account.

I wrote a PowerShell script that does the following:

  1. Checks that AzCopy is installed
  2. Determines if the C:\Windows\System32\CertSrv\CertEnroll folder exists
  3. Copies only changed files with extension .CRL to to the blob storage account
  4. Logs successful and failed transfers to %ProgramData%\ScriptLogs\Invoke-UpdateAzureBlobPKIStorage.log

You can find the script on my Github repo here:


Use pkiview.msc on a domain-joined machine to check the status of your CDP and AIA


Generating a SAS with least-privilege for AzCopy to use. Note that you’ll need to set Allowed Protocols to HTTPS and HTTP, not HTTPS only


The script’s archive log, showing the successful transfer of the CRL and Delta CRL

As always, use this at your own risk and your mileage may vary. Please drop me a comment below if you have any questions, feedback, or run into issues with the script.

8 thoughts on “Using Azure Blob Storage as a highly-available CDP and AIA location for your internal PKI

  1. Can you elaborate on the adjustments you need to make on the Extensions tab of the Certification Authority Properties? I’ve got the Blob setup and the script working to copy files to the Blob. However, when a client does revocation checks, it successfully contacts my Blob for the Base CRL check, but then fails the CRL Delta check by attempting to contact my internal server.


    • Hi Tony. It has been a while and unfortunately I no longer have access to that setup due to a change of jobs. I made sure that I removed all references to the internal AIA and CDP, and replaced them with the blob storage URL.


  2. Hello Daniel,

    Thanks for the amazing script! Always stay hungry and stay foolish 😉

    I think I keep running in a minor challenge with the creation of Log files using the default values.
    Im always getting:
    “Remove-Item : Cannot find path ‘C:\windows\Temp\AzCopy-PKI.log’ because it does not exist.
    At line:84 char:5”

    The error wont come when I create a File called “AzCopy-PKI.log” but on the second run the error comes again.
    I don’t understand how I actually get the script to create the log file in the first place as it wont do so.
    Do you might can point me to the right direction?

    PS. I used your idea with the Blob Storage and used an Azure CDN to publish my CRL and following Timothy Grubers approach (just put the issuing CA into Azure and connected a Azure CDN to publish my CRL)


      • I think I found the underlying issue – I tried it with AZCop v10 – which seems to be fundamental new designed. E.g. AZCopy with /XO switch doesnt work anymore (and as far I know no good alternative has been added yet) I will go back to Azcopy v8 and check again with your script 🙂

        Thanks again!


  3. Came across an issue when migrating my existing PKI to Blob Storage and thought it might help some of the people who are killing their Server 2008 R2 boxes at the moment.

    My CRL had the url CertEnroll which of course doesn’t work due to lowercase requirements on Blob Container names.

    Using the Azure CDN I was able to re-write /CertEnroll to /certenroll for pennies a month which allowed me to mothball my old Windows webserver (when combined with your script).



  4. Hi Daniel, thanks for this informative post.

    We’re in a situation which requires a similar solution. Do you have any thoughts on offloading an OCSP responder to Azure? We’re considering dropping OCSP entirely in favour of purely CRL checking because we cannot think of a way to relocate this from the Enterprise CA.



Leave a Reply to Daniel S Cancel reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s