How To Setup EZCA ADCS Agent To Automate Microsoft CA Certificate Management

Prerequisites

  1. Setup IIS
  2. Create Certificate Templates In CA

Introduction - How To Manage ADCS Certificates in a web portal With EZCA

For EZCA to connect to your ADCS CAs it is required for a domain joined machine to run the EZCA certificate agent web service. This web service receives authenticated requests from EZCA and then requests the certificate on behalf of EZCA. In this page we will set up the Agent, from registering the gMSA to getting the Agent operational. CA Agent

Setting up the Server

Install IIS Windows feature

In a domain joined PC open an Administrator PowerShell window and run the following command:

Install-WindowsFeature -name Web-Server -IncludeManagementTools

Instal Web deploy

Once IIS is installed, download web-deploy from the official Microsoft site and open the installer.

  1. Once the installer is open, click next on the first page.
  2. Read and accept terms and conditions.
  3. On the next page click “Complete” IIS Setup
  4. Click “Install”

Install .NET Hosting Bundle

  1. Download the latest .NET hosting bundle from Microsoft.
  2. Click Install.

Creating the gMSA

To have a fully password-less infrastructure we recommend having a gMSA (Group Managed Service Accounts) as the domain identity for the EZCA agent. First the domain admin has to create the gMSA by running the following commands (where ezcagMSA is the name of the gMSA. agent.yourdmoain is the DNS name of your agent, and ezcaAgents is the domain group that the agent is part of):

You can add all the agents to the same gMSA by adding them to the group that has access to the password.

Add-KdsRootKey -EffectiveImmediately
#wait 10 hours (this is made by Microsoft to ensure replication, for test environment you can bypass with Add-KdsRootKey –EffectiveTime ((get-date).addhours(-10))   
#Ref https://social.technet.microsoft.com/Forums/ie/en-US/82617035-254f-4078-baa2-7b46abb9bb71/newadserviceaccount-key-does-not-exist?forum=winserver8gen
New-ADServiceAccount -Name ezcagMSA -DNSHostName agent.yourdmoain -KerberosEncryptionType AES256 -PrincipalsAllowedToRetrieveManagedPassword ezcaAgents

Registering the gMSA in the Agent

In each agent we have to register the gMSA, to do this we first have to install the AD-Domain-Services PowerShell Modules and restarting the computer by running:

Get-WindowsFeature AD-Domain-Services
Install-WindowsFeature AD-DOMAIN-SERVICES
Restart-Computer

After the computer is restarted we add the gMSA and test, that is working by running these two commands:

$gmsaName = 'ezcagMSA'
Install-AdServiceAccount $gmsaName 
Test-AdServiceAccount $gmsaName

Creating the Site

Next we have to create the site in IIS, to do this run the following script replacing the variables with your gMSA name and certificate subject name:

You can download the signed version of this script from here

#usage .\InstallIISSite.ps1  -iisAppPoolName "YOURPOOLNAME" -iisAppName = "SITENAME" -directoryPath "PATHTOSITEFILES" -gMSAName 'YOURDOMAIN\ezcagMSA$' -certificateSubject 'YOUR SSL CERTIFICATE SUBJECT' -appInsights "YOUR APP Insights connection string" -testTemplate "ADCS Test Template"
param ($iisAppPoolName = "ezcaPool", $iisAppName = "ezca", $directoryPath = "C:\ezca",
$gMSAName, $certificateSubject, $appInsights,  $testTemplate = "EZCATestTemplate")
Import-Module WebAdministration

if($null -eq $gMSAName -or $gMSAName -eq '')
{
    Write-Host "Error: No gMSA name provided. Please provide a valid gMSA name Format: domain\gMSA$" -ForegroundColor Red
    exit 1
}
if($null -eq $certificateSubject -or  $certificateSubject  -eq '')
{
    Write-Host "Error: No certificate subject provided. Please provide a valid certificate subject name" -ForegroundColor Red
    exit 1
}
$directoryPath = $directoryPath.TrimEnd('\')
$originalPath = Get-Location
#navigate to the app pools root
cd IIS:\AppPools\

#check if the app pool exists
if (!(Test-Path $iisAppPoolName -pathType container))
{
    #create the app pool
    $appPool = New-Item $iisAppPoolName
    $appPool.processModel.userName = $gMSAName 
    $appPool | Set-ItemProperty -Name "managedRuntimeVersion" -Value "" 
    Set-ItemProperty IIS:\AppPools\$iisAppPoolName -name processModel.identityType -Value SpecificUser 
    Set-ItemProperty IIS:\AppPools\$iisAppPoolName -name processModel.userName -Value $gMSAName

}

#navigate to the root of the site
cd IIS:\Sites\

#check if the site exists
if (Test-Path $iisAppName -pathType container)
{
    return
}
$cert = (Get-ChildItem cert:\LocalMachine\My   | where-object { $_.Subject -like "*$certificateSubject*" }  | Select-Object -First 1).Thumbprint
if($null -eq $cert -or $cert -eq '')
{
    Write-Host "Error: No certificate found for the provided certificate subject. Please provide a valid certificate subject name, and make sure your certificate is in the the following cert store: Cert:\LocalMachine\My" -ForegroundColor Red
    exit 1
}
#create the site
Start-IISCommitDelay
$TestSite =New-IISSite -Name $iisAppName -PhysicalPath  $directoryPath  -BindingInformation "*:443:" -CertificateThumbPrint $cert -CertStoreLocation "Cert:\LocalMachine\My" -Protocol https -Passthru
$TestSite.Applications["/"].ApplicationPoolName =$iisAppPoolName
Stop-IISCommitDelay

# Download Site
cd $originalPath 
Invoke-WebRequest -Uri https://download.keytos.io/Downloads/WindowsAgentWeb/EZCAAgent.zip  -OutFile ezcaAgent.zip
Expand-Archive -LiteralPath ezcaAgent.zip -DestinationPath $directoryPath
$webAppSettings = Get-Content -Raw -Path "$($directoryPath)\appsettings.json" 
$webAppSettings = $webAppSettings.Replace('$SUBJECTNAME$', $gMSAName.Split('\')).Replace("EZCATestTemplate",$testTemplate).Replace('$GMSA$', $gMSAName.Replace("\","\\")).Replace('$APPINSIGHTS_CONNECTION_STRING$',$appInsights)
$webAppSettings | Out-File -FilePath "$($directoryPath)\appsettings.json" -Force
Remove-Item -Path ezcaAgent.zip

Creating the Agent Certificate

Once the site is set up, the last step before testing it is creating the gMSA’s agent certificate. This certificate is used to sign each request for the CA to issue the certificate to the agent on behalf of the user/computer requesting the certificate. To do this, an automated task periodically rotates certificates to mitigate the risk of certificate expiration related outages.

This Certificate will have very similar permissions to a PKI administrator. We strongly recommend having the private key of this certificate protected by an HSM. This example will use the native crypto provider to ensure compatibility with most set ups.

  1. First, Download the Agent Certificate Requester Binary.
  2. Once downloaded, replace the variables with your environments information and run the following from a PowerShell window with administrator rights:
    $gmsaName = 'DOMAIN\GMSANAME$'
    $caName = "CA.DNS\CA NAME"
    $pathToBinary = 'c:\ezcaTools\AgentCertificateRequester.exe'
    $templateName = "YOURTEMPLATENAME"
    $cryptoProvider = "Microsoft Enhanced Cryptographic Provider v1.0"
    $appInsightsKey = "" #(Optional) Enter App Insights Connection String to receive alerts on errors during runs
    
    ## Do Not Change Below This Line
    $gmsaShort = $gmsaName.Split('\')[1]
    $logsPath = $pathToBinary.Replace('AgentCertificateRequester.exe', 'logs.txt')
    
    # Construct the arguments for the scheduled task action
    $arguments = "$($pathToBinary) -ca $($caName) --userName $($gmsaShort) -t $($templateName) -c $($cryptoProvider)"
    if (-not [string]::IsNullOrEmpty($appInsightsKey)) {
        $arguments += " -ai $($appInsightsKey)"
    }
    $arguments += " | Out-File -FilePath $($logsPath)"
    
    $action = New-ScheduledTaskAction -Execute 'PowerShell.exe' -Argument $arguments
    $trigger = New-ScheduledTaskTrigger -At 11:00 -Weekly -WeeksInterval 3 -DaysOfWeek Monday
    $principal = New-ScheduledTaskPrincipal -UserID $gmsaName -LogonType Password
    Register-ScheduledTask ezCACertRotation -Action $action -Trigger $trigger -Principal $principal
    
  3. After setting up the task, open task manager and verify that it has successfully run and the certificate has been created.
  4. You can see if any errors occurred by checking Opening Event Viewer and looking in the Windows Logs -> Application for any errors. Event Viewer gMSA Certificate Created

How to Troubleshoot Certificate Creation

If there are some issues creating the certificate, you can download PSExec and run the following commands to run the AgentCertificateRequester.exe as the gMSA:

  1. First we must run powershell as the gMSA:
    .\PsExec.exe -i -u YOURDOMAIN\ezcagMSA$ -p ~ powershell.exe
    
  2. Then you can run the following lines to request the certificate
    $gmsaName = 'DOMAIN\GMSANAME$'
    $caName = "CA.DNS\CA NAME"
    $pathToBinary = 'c:\ezcaTools\AgentCertificateRequester.exe'
    $templateName = "YOURTEMPLATENAME"
    $cryptoProvider = "Microsoft Enhanced Cryptographic Provider v1.0"
    $appInsightsKey = "" #(Optional) Enter App Insights Connection String to receive alerts on errors during runs
    
    ## Do Not Change Below This Line
    $gmsaShort = $gmsaName.Split('\')[1]
    c:\ezcaTools\AgentCertificateRequester.exe --ca $($caName) --userName $($gmsaShort) -t $($templateName)  -c $($cryptoProvider)
    
  3. After that you can validate that the certificate was created in the user store by running the following command:
    Get-ChildItem cert:\CurrentUser\My | where-object { $_.Subject -like "*$($gmsaShort)*" }
    

After this your agent is ready to receive requests from EZCMS and request the certificates on behalf of the users. To verify that the agent is working correctly you can navigate to https://agent.yourdomain/api/health/settings and you should see the following result: { "Success": true, "Message": "Health" }

How to test ADCS Agent CA Connection

You can also validate that the agent can issue test certificates by calling the following endpoint: https://localhost/api/Health/CAConnection?AgentURL=https%3A%2F%2Fmyagent.com&TemplateName=EZCA&CAName=YOURCAFQDN%5CYOURCANAME&AuthCert=asdf where YOURCAFQDN is the FQDN of your CA and YOURCANAME is the name of your CA. If the agent is working correctly you should see the following result: { "Success": true, "Message": "Test certificate was issued successfully" }

Networking Requirements For ADCS Agent

Security is paramount when dealing with PKI and critical services. To ensure a robust defense in depth, we have simplified our agent’s networking needs. Inbound traffic can be restricted to only allow port 443 from our IP addresses. You can find the specific IP addresses for your instance by visiting the /status page of your EZCA instance (e.g., https://portal.ezca.io/status).

For outbound traffic, only access to Entra ID authentication endpoints is required. For government environments and EZCMS, we offer the option of certificate-based authentication, which eliminates the need for outbound access to Microsoft, requiring only outbound access to the CRL endpoint and or OCSP endpoint.