How To Issue SmartCard Certificates With ECMS Agent

Prerequisites

  1. Setup IIS
  2. Create Certificate Templates In CA

Introduction

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

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. Fist 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 fist 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 Key" -testTemplate "ADCS Test Template" $subscriptionID "YOUR EZCMS SUBSCRIPTION ID"
param ($iisAppPoolName = "ezcaPool", $iisAppName = "ezca", $directoryPath = "C:\ezca",
$gMSAName, $certificateSubject, $appInsights,  $testTemplate = "EZCATestTemplate", $subscriptionID)
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).Replace('$SUBSCRIPTION_ID$',$subscriptionID)
$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" }