Skip to content
Download free

Skyrsoft CertOps · Issue

Certificate enrolment agents for Windows and macOS

A small service that generates its own keypair, enrols and renews a certificate, and never lets the private key leave the host — for Windows and macOS.

All 25 CertOps features · Issue

The Skyrsoft CertOps agent is a small service that runs on a Windows or macOS host: it generates its own keypair, submits the resulting CSR, and installs the signed certificate without the private key ever leaving the device. It renews automatically ahead of each template’s threshold, with no admin involvement once it is enrolled. A separate per-user agent issues certificates to the signed-in person rather than the machine, for the certificate store a machine-level service cannot write into.

How it works

An agent onboards in four steps: install with an enrolment token, bootstrap against the server to receive an mTLS identity and the CA trust bundle, heartbeat periodically to report status and pick up configuration, then enrol and renew certificates under the device group it is assigned to. The Windows agent has run in production on Windows Server 2019 and 2022, and has also been confirmed working on a Windows 10 workstation.

Renewal runs on its own schedule, driven by the template’s own threshold rather than a fixed calendar:

agent — unattended renewal
# the template threshold is 30 days by default;
# the agent checks every tick
Cert <serial elided> entering renewal window
  (NotAfter=2027-01-31T00:00:00Z, thresholdDays=30);
  submitting renewal CSR.
Generating fresh 2048-bit RSA keypair for renewal
  (subject='CN=web01.example.com', SAN count=1).
Renewal auto-issued (oldSerial=<elided>, newSerial=<elided>,
  notAfter=2028-01-31T00:00:00Z); previous artifacts archived.
# the new keypair was generated on the host; only the CSR was ever sent

Windows and macOS machine agents

The Windows agent is a self-contained service — no separately installed .NET runtime — that authenticates with mTLS using a client certificate CertOps issues and manages for it automatically. The macOS machine agent does the same job on a Mac, installing its certificate into the System keychain:

macOS — verifying the installed certificate
# the machine agent installs its certificate into the System keychain
$ security find-certificate -a -c web01 /Library/Keychains/System.keychain
keychain: "/Library/Keychains/System.keychain"
"labl"<blob>="web01.example.com"

A device group can also deliver a macOS Wi-Fi profile. The agent fetches it, saves it and opens it, and a local administrator approves it in System Settings. It carries the issuing CA’s root as a trust anchor and an 802.1X Wi-Fi network, and no client certificate, so a renewal never invalidates it. The agent installs the machine certificate itself and binds it to the SSID. See Certificate-based Wi-Fi for Macs.

Machine and user agents

The machine agent runs as LocalSystem (Windows) or root (macOS) and cannot write into a signed-in user’s own certificate store — on macOS this is absolute, since root has no access to another account’s login keychain. A user agent runs inside the user’s own session instead: on Windows it starts from an HKLM Run key at logon, on macOS from a LaunchAgent, and each lands its certificate in the user’s own store — CurrentUser\My on Windows, the login keychain on macOS.

The user-agent relay

Neither user agent talks to the server on its own. Each hands its enrolment, heartbeat and status calls to the machine agent, which performs them with its own mTLS identity — over a named pipe on Windows, a Unix socket on macOS. This is the only transport either user agent has on either platform; there is no direct-HTTP fallback to fall back to. A configuration switch exists to disable the relay for troubleshooting, but that stops user-certificate issuance rather than routing around it.

The relay exists because the alternative was worse: giving the user agent its own copy of the machine agent’s private key meant any local account on that machine could act as the device and request a certificate for any user. The relay’s dispatcher instead asks the operating system who is actually calling — a Windows process token, or the peer credential on the macOS socket — and derives the certificate’s identity from that answer alone, ignoring whatever the request itself claims. An unidentified caller is refused outright, for every method.

Golden images and sysprep

An agent keeps two kinds of state separately: per-site config (server URL, enrolment token, site ID), which is safe to bake into an image, and per-machine identity (device GUID, mTLS certificate and key, enrolment state), which is not. Before capturing a golden image, run Reset-CertOpsAgent.ps1 (or --reset-identity on the agent executable) to clear the identity so every clone re-bootstraps as its own device rather than colliding on one device record.

As a backstop for an image captured without that step, the agent records the hardware UUID it enrolled under and clears its own identity automatically if that UUID changes at the next startup — the signature of a clone or a migrated VM. The backstop only fires once the hardware UUID actually changes, so running the reset before sealing the image is still the reliable path.

Limits

Getting an agent to actually issue depends on four things, and each fails quietly. The server’s FQDN has to be set. The DeviceMachine and UserAuth built-in templates ship inactive and need activating. A device only picks up a template from a device group with enrolment enabled — the global template setting in agent settings is not used for this. And the approval-rules engine denies by default, with FQDN and subject patterns evaluated as regular expressions rather than globs, so a rule written with * to “match anything” is invalid and silently never matches; use .*. Any one of these leaves the agent looking like it is doing nothing.

The relay channel is reachable by every logged-in user, and that is deliberate. The Windows named pipe is ACL’d to Authenticated Users, and the macOS socket is mode 0666 — both as defence in depth only, not as the actual boundary. What stops one user enrolling a certificate for another is the peer resolver: the operating system reports who is actually calling, the dispatcher derives the certificate’s identity from that report alone, and a caller the OS cannot attest is refused outright, for every method. There is no local-account workaround to weigh here — the borrowable machine-agent key this replaced is gone on both platforms.

Skipping the identity reset before sysprep can break the image, not just leave a duplicate device. Windows’ DPAPI keys change after sysprep /generalize, so a private key that was encrypted before capture becomes undecryptable afterwards, and the agent fails rather than recovering on its own.

An agent-issued certificate cannot be pushed to it centrally. The keypair never left the host in the first place, so there is no key on the server to deploy — renewal happens on the agent’s own schedule instead of through a deployment target.