We're headed to GridSecCon 2024, October 22-25 in Minneapolis, MN! Learn more here
Schedule a Demo
Blog January 11, 2018 Backups, Database, Hardware Security Modules, Hotfixes, Maintenance, Offline CA, PKI

Backing up ADCS Certificate Authorities (Part 2 of 2)

by Mark B. Cooper

In my last blog post (Backing up ADCS Certificate Authorities Part 1) I covered the inner workings of how ADCS and the Jet database works to maintain the CA data. In this post I am going to go over a comprehensive PowerShell script that I wrote to perform a full backup of all necessary ADCS components. In addition, this backup will ensure the CA performs the necessary log maintenance and truncation that I indicated was vital in Part 1.

Person sitting at a laptop while viewing the PKI Spotlight Dashboard.

Expand Your PKI Visibility

Discover why seeing is securing with revolutionary PKI monitoring and alerting.

Learn More About PKI Spotlight®

A customer recently tasked me with improving my old batch backup script. The batch file lacked any command arguments, diagnostic reporting, event monitoring and script statuses. To properly implement this in an enterprise, customers needed a stronger backup script.

This script is capable of backing up the following data:

  • ADCS Certificate Authority database
  • CA certificates, including previously renewed CA certificates
  • CA Configuration data stored in the registry
  • Thales nCipher HSM configuration and key files
  • List of published templates available on the CA

Details about the script

  • The script is not signed at this point, you can either sign it or temporarily change the execution level to allow it to run
  • The first time you use the script, you need to register the script so that it creates the event log source CABackup in the Application Log. The syntax is “.\cabackup.ps1 -Register $True”. You will need to be a local admin
  • There are a few switches to use as arguments. The most important might be the “EventLogging” so information goes into the Application Event Log, source CABackup.
    • Event IDs to watch:
      • Event 1, Backup Started
      • Event 2, Backup Completed Successfully,
      • Events 3,4 (Error) are problems with aspects in backing up the CA and should be alerted on
  • Argument BackupFolder allows you to specify where backups go, by default it is c:\cabackups

CABackup.ps1

[CmdletBinding()]
Param(
[Parameter(Mandatory=$False,Position=1)]
[string]$BackupFolder=”c:\CABackups”,
#Specifies the destiniation backup folder
[Parameter(Mandatory=$False,Position=2)]
[bool]$ThalesHSM,
#Determines if Thales HSM Files should be backedup
[Parameter(Mandatory=$False,Position=3)]
[bool]$Diagnostic,
#Enables diagnostic logging
[Parameter(Mandatory=$False,Position=4)]
[bool]$EventLogging=$true,
#Enables Event Log Entries
[Parameter(Mandatory=$False,Position=5)]
[bool]$Register
#Used during install to register the eventlog source
)

Scripted by: Mark B. Cooper
PKI Solutions Inc.
www.pkisolutions.com
#
Version: 1.2
Date: October 18, 2019

function WriteDebugLog ([string]$msg)
{
$(Get-Date -format ‘MM-dd-yy hh:mm:ss’) +”: ” + $msg | Out-File -FilePath $logfile -Append
if ($Diagnostic)
{
Write-Host $msg
}
}
function WriteEventLog ([string]$msg, [int]$EventID,[bool]$Error)
{
if ($EventLogging)
{
if ($Error)
{
Write-EventLog -LogName Application -Source “CABackup” -EventId $EventID -EntryType Error -Message $msg -Category 0
}
else
{
Write-EventLog -LogName Application -Source “CABackup” -EventId $EventID -EntryType Information -Message $msg -Category 0
}
}
}
cls
Set-PSDebug -Trace 0
Revision and Log detail tracking purposes only
$ScriptVersion=”1.0″
Log and temp files
$logfile = “$BackupFolder\Backup-Log-$(Get-Date -format ‘yyyy-MM-dd’).log”
if ($Register)
{
New-EventLog -LogName “Application” -Source “CABackup”
Exit
}
if (Test-Path $BackupFolder)
{}
else
{
New-Item $BackupFolder -ItemType Directory | Out-Null
}
WriteDebugLog “Script Starting -Version $ScriptVersion”
Write-Host “Starting Certification Authority Backup…”
WriteEventLog “Starting Certification Authority Backup” 1
WriteDebugLog “Removing Backup Folder Contents”
Remove-Item $BackupFolder* -Recurse
if(!$?)
{
WriteDebugLog “Error removing old backup folder contents. Error: ” + $error[0]
Write-Host “Unable to empty the target backup folder. Script is ending”
WriteEventLog “Unable to empty the target backup folder. Script is ending” 3 $true
Exit
}
WriteDebugLog “Backup Folder Prepared”
WriteDebugLog “Backing Up CA Database”
Backup-CARoleService -path $BackupFolder -DatabaseOnly
if(!$?)
{
WriteDebugLog “Error Performing CA Database Backup. Error: ” + $error[0]
Write-Host “Unable to perform CA Database Backup. Script is ending”
WriteEventLog “Unable to perform CA Database Backup. Script is ending” 4 $true
Exit
}
WriteDebugLog “CA Database backup completed”
WriteDebugLog “Copying CA Certificates”
Copy-Item $env:windir\System32\Certsrv\CertEnroll*.crt $BackupFolder
if(!$?)
{
WriteDebugLog “Error Copying CA Certificate Files. Error: ” + $error[0]
#Not considered a critical error, so backup will continue
}
else
{
WriteDebugLog “CA certificates backup completed.”
}
WriteDebugLog “Copying CAPolicy.inf”
if (Test-Path $env:windir\capolicy.inf) {
Copy-Item $env:windir\capolicy.inf $BackupFolder
if(!$?)
{
WriteDebugLog “Error Copying CAPolicy File. Error: ” + $error[0]
#Not considered a critical error, so backup will continue
}
else
{
WriteDebugLog “CAPolicy.inf backup completed.”
}
}
WriteDebugLog “Exporting CA Registry Configuration”
&’reg.exe’ “export” “HKLM\system\currentcontrolset\services\certsvc\configuration” $BackupFolder\caregistry.reg
if ($ThalesHSM)
{
WriteDebugLog “Backing up Thales HSM Files”
Get-ChildItem $env:nfast_kmdata -Directory | Where-Object{$_.Name -ne “tmp”} | Copy-Item -Destination $BackupFolder\HSM -Recurse -Force
if(!$?)
{
WriteDebugLog “Error Copying Thales HSM Files. Error: ” + $error[0]
#Not considered a critical error, so backup will continue
}
}
WriteDebugLog “Checking CA Type to determine if an Issuing CA”
$activeConfig = get-itemproperty -path “HKLM:\System\CurrentControlSet\Services\CertSvc\configuration” -Name active
$activeConfig = $activeConfig.Active
$CAType = get-itemproperty -path HKLM:\System\CurrentControlSet\Services\CertSvc\configuration\$activeConfig -Name CAType
if ($CAType.CAType -eq “1”)
{
WriteDebugLog “CA is an Issuing CA – Dumping list of templates”
certutil –catemplates > $BackupFolder\CATemplates.txt
}
WriteDebugLog “Backup Completed.”
Write-Host “Certification Authority Backup COMPLETED”
WriteEventLog “Certification Authority Backup COMPLETED” 2

Download CA Backup Script

    Related Resources

    • Blog Image of a person sitting at a desk working on a laptop with PKI Spotlight on the screen.
      October 4, 2024

      Announcing the October 2024 PKI Spotlight® Release

      PKI, PKI Spotlight
    • Blog
      August 16, 2024

      To Revoke or Not to Revoke: Balancing Security with Performance and Operational Complexity

      CA, Certificate Authority, Certificate Revocation List, CRL, OCSP, PKI, VPN
    • Blog A representation of PKI and digital certificate with a key lying on a blue circuit board
      August 1, 2024

      PKI Insights Recap – Past, Present, and Future of PKI with Brian Komar

      PKI, PKI Insights

    Mark B. Cooper

    President & Founder at PKI Solutions, Leading PKI Cybersecurity Subject Matter Expert, Author, Speaker, Trainer, Microsoft Certified Master.

    View All Posts by Mark B. Cooper

    Comments

    • Just updated the script to account for an issue where the installation of nCipher KeySafe can cause the backup of the KMDATA folder can fail.

    • Thanks for an excellent article and script. If we wanted to setup a scheduled task for this script to run every few months, would it be able to work under local system, or does it need real user credentials?

      • We always recommend a service account as it can be tracked and audited. The account would need Backup Operator rights.

      • Unfortunately no, there are many nuances to performing a restore. Other than just removing templates, restoring database, adding templates, there is a lot to do with restoring missing certificates (if any) that occurred after the backup was performed. Also, given the very seldom need for restore/recovery, it’s not a common request.

    • I loved the article and the script. i also admire how you used event logs to log the events of this backup cycle. Kudos

    • Since you are using the -DatabaseOnly option for BackupCARoleService, I don’t see how this script backs up the CA’s private key.

      • That is correct. Backing up your CA key repeatedly and daily/weekly is unnecessary. You should back up and securely store your CA key separately from any normal backup process. The CA key doesn’t change frequently (generally every several years or more).

    • Hello Mark,

      Thanks for posting

      Any thoughts about adding a switch to backup the relevant files and any registry keys for other HSMs for example Thales Luna 7?
      If not I will look to add myself to your original script, just thought I would ask first as it would be a once addition for the most popular HSMs?

      Thanks very much

    • Sorry for the delay as we were conversing internally. We have made a one-off script for some of our Luna-based customers but haven’t made a master script with arguments to specify which HSM the backup should be performed for. So if you come up with a good example you’d like to share, go for it!

    • That would be a nice addition indeed.
      @Ernest: I use Luna SA HSMs via KSP to secure ADCS CA’s private key, so if I can help, I will 🙂

    • Something like this should make it

      if ($SafeNetHSM)
      {
      WriteDebugLog “Backing up SafeNet HSM Files”
      Copy-Item $env:ChrystokiConfigurationPath $BackupFolder\HSM -Recurse
      if(!$?)
      {
      WriteDebugLog “Error Copying SafeNet HSM Files. Error: ” + $error[0]
      #Not considered a critical error, so backup will continue
      }
      }

    • You can add
      If ([System.Diagnostics.EventLog]::SourceExists(‘CABackup’) -eq $False) {
      New-EventLog -LogName Application -Source ‘CABackup’
      }

      For Add Source Application for log.

    • Question, how long is kept this backup? I did not understand the script, it will overrite the oldest ones every X days, etc, I want to know that

    • How about adding -v to “certutil -v -catemplates” get more info on templates other than just the name?

      • As the templates themselves are stored in AD and are backed up as part of your AD backup strategy, they are not regularly backed up as part of a CA process. The intent was to make sure we backed up a list of what templates were installed on the CA so that we could properly recover the CA by re-installing the templates in the future. If you wish to add the verbose flag (-v) to collect additional information about templates, you certainly can.

    • also, while Im here. 🙂 our DB is getting quite large. 1.5gb. I’ve now written a script to regularly revoke expired certs. Next step is to delete those revoked certs. (( We don’t archive private certs.. https://learn.microsoft.com/en-us/answers/questions/47333/safe-to-delete-expired-ca-cert
      Will our DB auto shrink\compact in size after deleting a heap of revoked certs or would I need to do some jet optimising?
      Is there any real benefit in this exercise? Will the DB function faster?

      • The database will not compact/shrink on its own after deleting records in the database. The Jet database will keep the deleted space as “white space” for future record storage. If you remove a significant amount of records that you would rather recovery as free space, then you will need to defrag the database. I am not sure why you would revoke an expired certificate, as an expired certificate is just untrusted as a revoked certificate. If you have a specific use case that is another story, but it is likely an unnecessary step.

    • I ran Copy-Item $env:ChrystokiConfigurationPath $BackupFolder\HSM -Recurse in my backup script.

      It copes the \program file\safenet\Lunaclient folder to the back up.

      When I copied it to a new server and replaced the \program file\safenet\Lunaclient with it it would not see the partion on the HSM.

      Did I miss a step?

      • There are additional steps needed on Luna clients to be able to access a partition when you “move” client from one machine to another. So it’s not so much as missing a step in the backup, its a missing step in your recovety.

    Leave a Reply

    Your email address will not be published. Required fields are marked *