Repository navigation
Windows Autoenrollment
Version: 2.242 (introduced in 2.207)
Status: ✅ Production Ready
Specs: MS-XCEP, MS-WSTEP
UCM natively serves the Active Directory Certificate Services enrollment protocols, so Windows clients can enroll certificates against UCM exactly as they would against a real AD CS deployment — without installing AD CS at all:
-
MS-XCEP (Certificate Enrollment Policy) —
GetPoliciespolicy discovery: advertises the certificate templates, key requirements, EKUs and enrollment URIs Windows clients use to decide what to enroll and where. -
MS-WSTEP (WS-Trust X.509v3 Token Enrollment) — certificate issuance and renewal: parses a
RequestSecurityToken(RST) SOAP request and returns aRequestSecurityTokenResponseCollectionwith the issued certificate.
This is the protocol pair behind:
- MMC → Request New Certificate (interactive enrollment)
-
certreq/certutilcommand-line enrollment - GPO machine and user autoenrollment — fully unattended certificate deployment at boot/logon, driven by Group Policy
Direction matters: this page covers UCM acting as the enrollment CA for Windows clients. For the opposite direction — UCM submitting CSRs to an existing Microsoft AD CS — see Microsoft CA Integration.
| Requirement | Needed for | Notes |
|---|---|---|
| A UCM CA with a private key | Everything | Selected in the XCEP/WSTEP configuration |
pyspnego with the gssapi backend |
Kerberos binding only | Optional dependency: pip install pyspnego[kerberos] (needs the system Kerberos libraries, e.g. libkrb5-dev, at build time). Username/Password and certificate-renewal bindings work without it |
| A Kerberos keytab + SPN | Kerberos binding only | Generated on the domain controller with ktpass (or ktutil), e.g. for HTTP/ucm.example.com@EXAMPLE.COM
|
| AD Connector configured | Unattended GPO autoenrollment | Lets UCM derive the subject of the deliberately empty CSRs GPO submits — see AD Connector |
| At least one template with Allow autoenrollment | Unattended GPO autoenrollment | See Template flags |
Since v2.208, the Kerberos availability check requires the actual gssapi backend, not just an importable spnego package (which ships transitively with other dependencies) — XCEP no longer advertises, and clients no longer attempt, a Kerberos binding that would fail at request time.
The tab starts with a Setup Checklist tracking what is configured versus what is still needed, separately for manual enrollment (MMC, certreq) and unattended GPO autoenrollment.
Policy Discovery (XCEP):
| Setting | Description | Default |
|---|---|---|
| Enabled | Serve MS-XCEP GetPolicies
|
Off |
| Certificate Authority | CA whose templates are advertised | — |
| Username / Password | Credential for the UsernamePassword binding | — |
Certificate Issuance (WSTEP):
| Setting | Description | Default |
|---|---|---|
| Enabled | Serve MS-WSTEP issuance/renewal | Off |
| Certificate Authority | CA that signs enrolled certificates | — |
| Username / Password | Credential for the UsernamePassword binding | — |
| Validity (days) | Default validity of issued certificates | 365 |
Kerberos / SPNEGO:
| Setting | Description |
|---|---|
| Enabled | Accept Authorization: Negotiate on the Kerberos endpoints |
| Service Principal Name (SPN) | e.g. HTTP/ucm.example.com@EXAMPLE.COM
|
| Keytab | Uploaded keytab file for the SPN above. The tab re-inspects the stored keytab and shows its principal, whether it parses, and whether it matches the configured SPN |
See AD Connector below.
The URL shape follows Microsoft's own AD CS convention of encoding the authentication binding in the path. All endpoints are public protocol endpoints (no UCM session auth) and return 503 when the corresponding protocol is administratively disabled. GET/HEAD reachability probes return an empty 200 (they never trigger an HTTP Basic challenge, which would break real Windows clients expecting message-level auth).
| Endpoint | Authentication |
|---|---|
/ADPolicyProvider_CEP_UsernamePassword/service.svc |
WS-Security UsernameToken (HTTP Basic fallback) |
/ADPolicyProvider_CEP_Kerberos/service.svc |
HTTP Negotiate (Kerberos/SPNEGO) |
| Endpoint | Authentication | Purpose |
|---|---|---|
/ADCertificateService_CES_UsernamePassword/service.svc |
WS-Security UsernameToken (HTTP Basic fallback) | Initial enrollment |
/ADCertificateService_CES_Certificate/service.svc |
XML-DSig-signed RST (existing certificate) | Renewal only |
/ADCertificateService_CES_Kerberos/service.svc |
HTTP Negotiate (Kerberos/SPNEGO) |
Initial enrollment and renewal — GPO autoenrollment's usual path |
The XCEP policy response advertises the UsernamePassword and Certificate CES URIs unconditionally, but the Kerberos CES URI only when Kerberos is actually configured (enabled + SPN + keytab) and the gssapi backend is installed — a client is never pointed at a binding guaranteed to fail.
Three bindings, mirroring real AD CS CES endpoints:
Credentials arrive as a wsse:UsernameToken inside the SOAP message header — not as an HTTP Authorization header. This matches real Windows client behavior: a client configured for the UsernamePassword binding refuses to answer an HTTP Basic challenge (WS_E_SERVER_REQUIRES_BASIC_AUTH). HTTP Basic is still accepted as a fallback (convenient for curl/testing), but the endpoints never challenge for it; authentication failures come back as SOAP faults. The username/password is the single shared credential configured in Settings (stored hashed).
For renewal, the RST itself is WS-Security signed (XML-DSig) with the private key of the client's current certificate — there is no HTTP-level authentication. UCM verifies that:
- the signature covers the embedded CSR,
- the signing certificate matches byte-for-byte a certificate UCM itself issued from the configured CA — matching on serial/subject alone is deliberately not enough, since both are public and could be forged onto a self-signed lookalike,
- the stored certificate is neither revoked nor expired,
- the CSR's subject (and SAN, if present) match the signing certificate,
- the WS-Security signature uses RSA or ECDSA with SHA-256, SHA-384 or SHA-512; other algorithms are refused since v2.241.
Transport-level HTTP authentication per RFC 4559, exactly like IIS Windows Integrated Authentication: Authorization: Negotiate <SPNEGO token>, verified against the uploaded keytab via GSSAPI. This is what unattended GPO autoenrollment uses — the machine (or user) authenticates with its own Kerberos ticket, no credential prompt. Multi-leg SPNEGO exchanges (e.g. a request-MIC round) are supported. Requires the optional pyspnego[kerberos] dependency.
Settings → Active Directory configures a single stored LDAP connection UCM uses to query Active Directory directly. It is deliberately separate from any LDAP provider under SSO — that one is for logging into UCM; this one is for certificate-related AD lookups, and works whether or not SSO is configured.
| Setting | Description |
|---|---|
| Domain Controllers / Port | One domain controller per row, each by its own hostname, tried in order with failover (since v2.233); default port 389 |
| LDAPS / Verify SSL | LDAP over SSL/TLS, with optional custom CA bundle. Naming each DC by its own hostname is what makes Verify SSL usable on a multi-DC domain: a DC certificate names only its own host |
| Base DN | Search base, e.g. DC=example,DC=com
|
| Bind DN / Password | Service account for lookups — the bind password is encrypted at rest. Both are required while the connector is enabled (since v2.233) |
| Health Check Interval | Seconds between real binds to each DC (default 120). An unreachable DC is skipped at enrollment time; the verdict shows on the settings row and against each DC, expires, and never rules out every DC |
| Test Connection | Verifies connectivity and credentials before saving |
Upgrade note (v2.233): an enabled connector saved without a bind password stops answering lookups until credentials are entered in the settings dialog, and an API client must send both when it enables one.
Windows GPO machine autoenrollment deliberately submits a subject-less ("naked") CSR — no CN, no SAN — trusting the CA to build the subject from the directory, the way a real AD CS template configured with "Build from this Active Directory information" does. When a naked CSR arrives on the Kerberos-bound WSTEP endpoint, UCM resolves the authenticated Kerberos principal in AD:
-
Machine principal (e.g.
WIN11$@EXAMPLE.COM) → subject becomesCN=<dNSHostName>of the computer object. Always on (no template opt-in needed). -
User principal → opt-in per template via the Build subject from Active Directory flag: the subject becomes the AD user object's own directory-path DN (e.g.
CN=Jane Doe, CN=Users, DC=example, DC=com), plus theuserPrincipalNameas a UPNotherNameSAN — matching the shape of a real AD CS-issued User certificate. If the ADmailattribute is set, it is added opportunistically as anE=RDN and an rfc822Name SAN; a missing email never blocks enrollment.
If the connector is not configured, no template opted in, or the lookup fails, the naked CSR is rejected with the normal "subject required" error — derivation never fails open. Kerberos principals from a realm other than the connector's own domain are refused (cross-realm tickets must not be resolved against a same-named account in the wrong domain).
Three opt-in flags on certificate templates (Templates → Enrollment) control autoenrollment behavior:
| Flag | Effect |
|---|---|
Allow autoenrollment (autoenroll_enabled) |
Advertises the template with autoEnroll=true in the XCEP policy — the Enroll vs. Autoenroll permission split real AD CS enforces. Without it, the template is offered for manual enrollment (enroll=true) but unattended GPO autoenrollment ignores it |
Build subject from Active Directory (ad_derived_subject) |
Opts user enrollments into AD-derived subjects (see above). Machine subject derivation is always available |
Allowed AD group (allowed_ad_group) |
Per-template Enroll ACL: Kerberos-authenticated requesters must be a member of this AD group — nested group membership counts (resolved via the AD LDAP_MATCHING_RULE_IN_CHAIN matching rule). Non-members are refused with a fault |
Which templates are advertised at all follows the CA's template pinning: templates pinned to the configured CA, or every active template when none are pinned.
Note: MS-WSTEP carries no explicit "which template did you pick" signal, so UCM matches the request to a template by its requested EKUs. A naked GPO CSR (no EKU extension) matches no template — in that case the Enroll ACL fails closed: the requester must satisfy at least one restricted template's group, rather than none of them.
A template can pin the C, ST, L, O and OU subject fields to fixed values (Templates → edit → Pinned subject fields). On every WSTEP issuance, pinned values override whatever the client's CSR (or the AD derivation) supplied for those fields — while CN and SAN always stay dynamic. CN can never be pinned.
This gives a "hybrid subject template": organizational identity controlled centrally, host/user identity still per-request. If the request could not be matched to a specific template and several CA-resolvable templates pin the same field to different values, that field is skipped (with a warning in the logs) rather than silently picking a winner.
On Kerberos-bound issuance, when the AD Connector is enabled, UCM embeds the authenticated requester's AD SID in the issued certificate as the SID security extension (szOID_NTDS_CA_SECURITY_EXT, OID 1.3.6.1.4.1.311.25.2) — the same extension real AD CS adds automatically, and what domain controllers use for strong certificate mapping under KB5014754 (certificate-based authentication enforcement).
Unlike the other AD Connector features this is unconditional (no per-template opt-in) and applies to naked and fully-populated Kerberos-bound CSRs alike. Fail-closed: if the connector is enabled but the SID lookup fails for a request, issuance is refused rather than issuing a weaker-mapped certificate. If the connector is not configured at all, the extension simply is not added. UsernamePassword-bound requests never get it — there is no per-request AD principal to resolve.
Details verified against real Windows clients:
- TLS 1.2 cap while WSTEP is enabled — some schannel-based TLS 1.2-only clients abort the handshake against a TLS 1.3-capable server. UCM caps its TLS at 1.2 only while WSTEP is enabled; installs that never use Windows autoenrollment keep TLS 1.3. Toggling WSTEP automatically restarts the service so the cap tracks the setting (on Docker, restart the container when prompted).
-
Microsoft Certificate Template extension — issued certificates carry the Certificate Template extension with a stable per-(CA, template) policy OID; without it,
CX509Enrollment::Enrollfails withCERTSRV_E_PROPERTY_EMPTY. - CMC / full PKCS#7 requests — Windows "Full PKCS#7" requests are unwrapped (CMC envelope → inner PKCS#10) and answered with a CMC full PKI response referencing the request's CMC body part.
- Proof of possession — always enforced. For plain PKCS#10 requests, via the CSR's self-signature; for PKCS#7/CMC-wrapped requests (whose inner self-signature is not reliable from real clients), via the outer CMS SignedData signature, which must verify against — and identify itself by the subject key identifier of — the CSR's own public key.
-
SHA-1 CSRs are rejected —
certreqdefaults to SHA-1 unless the INF setsHashAlgorithm=sha256; UCM refuses MD5/SHA-1-signed CSRs with an explicit message.
On the Windows side (Group Policy Management, Computer Configuration and/or User Configuration → Policies → Windows Settings → Security Settings → Public Key Policies):
-
Certificate Services Client – Certificate Enrollment Policy
- Set Configuration Model to Enabled.
- Add a policy server: URL
https://ucm.example.com:8443/ADPolicyProvider_CEP_Kerberos/service.svc, authentication type Windows integrated (Kerberos) — required for silent autoenrollment. The Username/password URL (.../ADPolicyProvider_CEP_UsernamePassword/service.svc) is for interactive "Request New Certificate" enrollment only. - Validate the server, then save. (The UCM server's TLS certificate must be trusted by the client.)
-
Certificate Services Client – Auto-Enrollment
- Set to Enabled, and check Renew expired certificates… and Update certificates that use certificate templates.
- Ensure at least one UCM template has Allow autoenrollment set, and (for user certificates with AD-derived subjects) Build subject from Active Directory.
At the next policy refresh (or gpupdate /force + certutil -pulse), eligible machines and users enroll silently against UCM. Interactive enrollment is available immediately in certlm.msc / certmgr.msc → Request New Certificate.
| Action | Operation |
|---|---|
certificate.issued |
WSTEP enrollment (UsernamePassword or Kerberos binding) |
certificate.renewed |
WSTEP certificate-bound renewal |
XCEP GetPolicies policy discovery is not audited (read-only).
sudo journalctl -u ucm | grep -i -E "wstep|xcep|kerberos"
tail -f /var/log/ucm/ucm.log | grep -i wstepCauses:
- The
gssapibackend is not installed —pip install pyspnego[kerberos](needslibkrb5-devor equivalent to build). Since v2.208 the Kerberos binding is also no longer advertised in the XCEP policy in this case, so clients stop attempting it. - Kerberos is not enabled, no SPN is set, or no keytab has been uploaded.
Fix: check Settings → Windows Autoenrollment → Kerberos/SPNEGO — the tab shows whether the library is available, and whether the uploaded keytab parses and matches the configured SPN.
- The template must have Allow autoenrollment set —
enroll=truealone is ignored by the unattended autoenrollment engine. - The GPO policy server must use Kerberos authentication; the Username/Password URL cannot be used unattended.
- If an Allowed AD group is set, the machine/user must be a (possibly nested) member.
GPO submitted a subject-less CSR but UCM could not derive a subject from AD. Check that the AD Connector (Settings → Active Directory) is enabled and its connection test passes, and — for user enrollment — that a template has Build subject from Active Directory set. Cross-realm Kerberos principals are refused by design.
The AD Connector is enabled but the SID lookup for the authenticated principal failed (account not found, LDAP unreachable). Issuance fails closed — fix connectivity or the account, or disable the connector if AD lookups are not wanted.
The issued certificate reached the client but carried no Certificate Template extension — in practice this means the request did not match any advertised template. Check the CA's template pinning and the template's EKU configuration.
certreq INF files default to SHA-1. Add HashAlgorithm=sha256 to the [NewRequest] section.
- Renewal identity is byte-exact — the certificate signing a renewal RST must match a UCM-issued certificate byte-for-byte; serial/subject lookalikes are refused.
- Enroll ACL fails closed — unresolvable principals, cross-realm tickets and failed group lookups deny enrollment rather than skipping the check.
- AD Connector bind password is encrypted at rest; saving fails closed if encryption is unavailable.
- The UsernamePassword binding authenticates a single shared credential — prefer the Kerberos binding for per-machine/per-user identity, group ACLs and strong certificate mapping.
- Request bodies are size-capped (64 KB XCEP / 128 KB WSTEP) and disabled protocols answer 503 on every endpoint.
- Certificate Templates — Template configuration, including the autoenrollment flags
- Microsoft CA Integration — The opposite direction: UCM as a client of an existing AD CS
- SCEP Server — Enrollment for network/mobile devices
- EST Protocol — RFC 7030 enrollment
- CA Management — Configure signing CAs
- Security — Security features overview
- ✅ MS-XCEP — X.509 Certificate Enrollment Policy Protocol (
GetPolicies) - ✅ MS-WSTEP — WS-Trust X.509v3 Token Enrollment Extensions (RST/RSTRC)
- ✅ WS-Security / WS-Trust 1.3 — UsernameToken and XML-DSig message security
- ✅ RFC 4559 — SPNEGO-based Kerberos HTTP authentication
- ✅ RFC 5272 — CMC (full PKCS#7 request/response)
- ✅ RFC 2986 — PKCS#10 Certificate Request Syntax
Need Help? See Troubleshooting or GitHub Issues
Getting started
Certificates and CAs
- CA Management
- CA Offline Mode
- Certificate Operations
- Certificate Templates
- Certificate Export
- Import and Export
- Import from OPNsense
- Certificate Toolbox
- Certificate Discovery
- Trust Store
- Approval Workflows
- Key Recovery
- Code Signing
- Deploy Hooks
- HSM Support
- SSH Certificate Authority
Protocols
- ACME
- SCEP
- EST
- OCSP Responder
- CRL and CDP
- AIA CA Issuers
- TSA (Timestamp Authority)
- Certificate Transparency
Integrations
Security and access
Operations
- System Configuration
- Database Backend
- Backup and Restore
- Monitoring
- Notifications
- Reports
- Dashboard
- Themes
- User Settings
Development
- Building from Source
- Contributing
- Developer Patterns
- Architecture
- API Reference
- API Documentation
- Roadmap
Releases