AD CS server setup (CES/CEP)
Windows-server-side preparation for CertAutoPilot's AD CS integration: install the CA and the CES/CEP role services with username/password authentication, verify the IIS endpoints, create and publish an enrollment template, and set up a least-privilege service account. Once the server side is ready, configure the CertAutoPilot side on Microsoft AD CS.
Prerequisites
- Windows Server 2019 or 2022 (Standard or Datacenter).
- Active Directory Domain Services configured and running; the CA server is domain-joined.
- Administrator access to the server.
- A valid TLS certificate for IIS (self-signed is acceptable for testing).
Architecture
CertAutoPilot ──HTTPS──► IIS ──► CES (Certificate Enrollment Web Service)
│
CEP ◄──────┘ (Certificate Enrollment Policy)
│
▼
Active Directory
Certificate Services
CertAutoPilot communicates with two Microsoft web services, both hosted on IIS:
- CEP (Certificate Enrollment Policy) — discovers the certificate templates available to the caller (MS-XCEP).
- CES (Certificate Enrollment Service) — submits certificate requests (MS-WSTEP).
Authentication is WS-Security UsernameToken inside the SOAP message, over HTTPS.
Step 1 — Install AD CS
Add the role
Open Server Manager → Add Roles and Features:
- Select Role-based or feature-based installation and pick your server.
- Check Active Directory Certificate Services; add required features when prompted.
- Under Role Services, select:
- Certification Authority (required)
- Certificate Enrollment Web Service (CES)
- Certificate Enrollment Policy Web Service (CEP)
- Complete the wizard.
Configure the Certification Authority
Click the notification flag in Server Manager → Configure Active Directory Certificate Services:
- Credentials — use a Domain Admin account.
- Role Services — select Certification Authority.
- Setup Type — Enterprise CA (integrates with AD).
- CA Type — Root CA for standalone environments, or Subordinate CA if you have an existing PKI.
- Private Key — create a new private key.
- Cryptography — RSA 2048 or higher, SHA256.
- CA Name — pick a meaningful name (e.g.
contoso-ca). - Validity Period — 5–10 years for a Root CA.
Step 2 — Configure CES and CEP
Return to Server Manager → Configure Active Directory Certificate Services, once for each role service:
CES:
- Role Services — Certificate Enrollment Web Service.
- CA for CES — the CA you just created.
- Authentication Type — User name and password.
- Select the IIS SSL certificate if prompted.
CEP:
- Role Services — Certificate Enrollment Policy Web Service.
- Authentication Type — User name and password.
- Select the same SSL certificate.
The authentication type must be User name and password on both CES and CEP for CertAutoPilot's username/password profile — the client authenticates with a WS-Security UsernameToken inside the SOAP message.
After both are configured, verify in IIS Manager:
Default Web Site
├── <CA-Name>_CES_UsernamePassword ← CES endpoint
└── ADPolicyProvider_CEP_UsernamePassword ← CEP endpoint
Step 3 — Verify IIS
SSL binding
IIS Manager → Default Web Site → Bindings: ensure an HTTPS binding exists on port 443 and the certificate matches the server hostname. Or via PowerShell:
netsh http show sslcert ipport=0.0.0.0:443
Authentication settings
The CES and CEP applications must keep Anonymous Authentication enabled (the default). WCF performs the real authentication at the message level via WS-Security — not at the IIS/HTTP level.
Get-WebConfigurationProperty -PSPath "IIS:\Sites\Default Web Site\<CA-Name>_CES_UsernamePassword" `
-Filter "system.webServer/security/authentication/anonymousAuthentication" -Name enabled
# Should return: True
Do not disable Anonymous Authentication on the UsernamePassword CES/CEP applications. If IIS challenges the request before WCF sees it, enrollment breaks with opaque 401 errors.
Note the endpoint URLs
You will paste these into the CertAutoPilot profile:
| Service | URL pattern |
|---|---|
| CES | https://<server>/<CA-Name>_CES_UsernamePassword/service.svc |
| CEP | https://<server>/ADPolicyProvider_CEP_UsernamePassword/service.svc |
CertAutoPilot automatically appends the /CES or /CEP suffix to URLs ending in service.svc, so pasting the base service URL is fine.
Step 4 — Create a certificate template
Duplicate and configure
On the CA server, open Server Manager → Tools → Certificate Templates Console (certtmpl.msc), right-click an existing template (e.g. Web Server) → Duplicate Template, then set:
General tab
- Template display name, e.g.
CertAutoPilot Web Server. - Template name, e.g.
certautopilot-web-server(no spaces). - Validity period 1–2 years; renewal period e.g. 6 weeks.
Subject Name tab
- Select Supply in the request.
"Supply in the request" is mandatory. It lets CertAutoPilot put the subject (CN) and SANs into the CSR. With "Build from Active Directory" the CA rejects CSRs that carry subject information.
Cryptography tab
- Provider Category: Key Storage Provider.
- Algorithm: RSA, minimum key size 2048.
Many AD CS templates do not accept ECDSA keys. If you need ECDSA, the template's cryptography settings must explicitly allow it; otherwise issue RSA 2048/3072/4096 certificates from this template.
Security tab
- Add the service account CertAutoPilot will use and grant Read and Enroll.
Extensions tab
- Application Policies: include Server Authentication (
1.3.6.1.5.5.7.3.1). - Key Usage: Digital Signature, Key Encipherment.
Publish the template
- Open the Certification Authority console (
certsrv.msc). - Expand your CA → right-click Certificate Templates → New → Certificate Template to Issue.
- Select the new template and click OK.
Verify:
certutil -CATemplates | findstr "certautopilot"
Service account
Create a dedicated, least-privilege enrollment account — never use a Domain Admin:
New-ADUser -Name "svc-certautopilot" `
-UserPrincipalName "svc-certautopilot@contoso.local" `
-Path "OU=Service Accounts,DC=contoso,DC=local" `
-AccountPassword (Read-Host -AsSecureString "Password") `
-Enabled $true `
-PasswordNeverExpires $true `
-CannotChangePassword $true
Then grant it Read and Enroll on the template (certtmpl.msc → template → Security tab).
Next: configure CertAutoPilot
With the server side done, create the AD CS provider profile in CertAutoPilot (endpoints, service-account credentials, TLS trust) and sync templates — see Microsoft AD CS — then issue a certificate via the issuance walkthrough.
Server-side troubleshooting
Symptoms as seen from CertAutoPilot's connection test / template sync, with server-side causes:
Connection test fails
| Error | Cause | Solution |
|---|---|---|
| TLS validation failed | IIS SSL certificate not trusted | Add the issuing CA cert to the profile's TLS trust (or skip-verify for lab testing) |
| Endpoint unreachable | Network/firewall issue | Verify port 443 is open and IIS is running |
| Authentication failed (HTTP 401) | Wrong credentials | Verify username format (DOMAIN\user) and password |
| Authentication failed (HTTP 403) | User lacks permissions | Grant Enroll on the template to the service account |
Template sync fails
| Error | Cause | Solution |
|---|---|---|
InvalidSecurity | WS-Security header rejected | Verify CES/CEP were configured with the UsernamePassword binding |
| Empty policies / template missing | Template not enrollable by the caller | See the 3-step checklist below |
| SOAP fault | CEP service error | Check the Windows Event Log on the CA server |
A newly added template not appearing after Sync almost always needs all three of the following — duplicating a template alone does nothing. Work through them in order, then re-Sync:
-
Publish it to the CA —
certsrv.msc→ CA → Certificate Templates → right-click → New → Certificate Template to Issue. (Duplicating ≠ publishing.) -
Grant Enroll (not just Read) to the service account — Template → Security → allow Enroll. CEP returns only templates the caller can enrol, so Read alone is not enough.
-
Refresh the CEP policy cache — the policy web service caches its template list in memory. Recycle the CEP/CES app pool (least disruptive; only the enrollment front-end blips for a few seconds — the CA engine, issued certs, and CRLs are untouched):
Restart-WebAppPool -Name "<CEP/CES app pool>" # e.g. WSEnrollmentPolicyServeriisresetalso works. With multiple DCs, allow AD replication too (repadmin /syncall). Full checklist: New template doesn't appear after Sync.
If the template's Issuance Requirements tab requires CA certificate manager approval, requests land in Pending instead of being issued immediately. CertAutoPilot polls for these and completes them once an operator approves the request in certsrv.msc → Pending Requests. For fully automated issuance, leave approval disabled on the template.
Certificate issuance fails
| Error | Cause | Solution |
|---|---|---|
Denied by Policy Module | Template rejects the request | Check template settings (key type, subject-name policy) |
The request is invalid | CSR format issue | Use an RSA 2048 key type |
| Template not found | Template not published | Publish the template via the CA console |
CES tracing
For deep diagnostics, enable verbose WCF tracing on the CES application:
# Enable CES verbose tracing
$wc = "C:\Windows\SystemData\CES\<AppName>\web.config"
(Get-Content $wc) -replace 'switchValue="Off"', 'switchValue="Verbose"' | Set-Content $wc
iisreset
# After reproducing the issue:
Get-Content "C:\Windows\SystemData\CES\<AppName>\Traces\Traces-EnrollmentServer.xml" |
Select-String "error|invalid|fault" -CaseSensitive:$false
# Disable tracing afterward:
(Get-Content $wc) -replace 'switchValue="Verbose"', 'switchValue="Off"' | Set-Content $wc
iisreset
Security best practices
- Dedicated service account for enrollment — never Domain Admin.
- Minimum permissions — Enroll on specific templates only; restrict template access to required users/groups.
- A properly trusted TLS certificate on IIS in production — avoid self-signed.
- Enable auditing on the CA to track all certificate issuance.
- Rotate the service-account password regularly and update the CertAutoPilot profile when you do.