Wiki / Certificate Lifecycle (CLM)

Deploying a Certificate to a Cisco Catalyst 9800 WLC

Last updated

CertTracker CLM — Deploying a Certificate to a Cisco Catalyst 9800 WLC

This guide connects a Cisco Catalyst 9800 Wireless LAN Controller (hardware appliance or 9800-CL) to CertTracker so the CLM agent can install and renew the controller's service certificates automatically — no manual crypto pki import, no pasting base64 into a console, no re-pointing a trustpoint by hand.

The 9800 runs several TLS services off separate trustpoints, so this adapter is organized as one adapter per service. You add a separate adapter for each service you want managed, and each one imports a cert into its own trustpoint and repoints just that service.

Service What it secures Bound with
Web UI The HTTPS admin GUI ip http secure-trustpoint
Captive portal Web-auth / guest splash pages parameter-map type webauth <name> → trustpoint
EAP Local EAP / dot1x server cert eap profile <name> → pki-trustpoint
CAPWAP AP-join / wireless-management DTLS wireless management trustpoint — currently unavailable, see below

⚠ CAPWAP is currently unavailable — read this before you plan

The adapter can technically repoint the wireless-management (CAPWAP) trustpoint, but the service is disabled in the product and cannot be selected. This is deliberate, and it is not a limitation of CertTracker — it is how AP trust works on the 9800.

When an access point joins the controller over CAPWAP, the DTLS handshake has the AP validate the controller's certificate against the AP's own trust store. By default APs trust Cisco's Manufacturer CA (their MIC/SUDI world) and, on a 9800-CL, the controller's self-signed cert is the built-in AP-join identity that "just works." The moment you repoint the wireless-management trustpoint to a certificate from an internal/enterprise CA the APs don't trust, the APs reject the controller and drop immediately — and they will not rejoin until the trustpoint is reverted or the APs are provisioned to trust that CA.

This was confirmed in the field on 2026-07-28: swapping the CAPWAP trustpoint to an internal-CA cert dropped all access points instantly (not on the next rejoin — immediately), and ap auth-list ap-cert-policy allow-mic-ap did not help, because that policy governs the controller trusting the APs, not the APs trusting the controller. Reverting the wireless-management trustpoint to the original self-signed trustpoint brought every AP straight back.

What it would take to enable CAPWAP safely is one of:

  • AP LSC provisioning — the APs enroll to your CA (ap lsc-provision), get their own Locally Significant Certificates, and receive the CA root into their trust store before the controller swap. This is a project in its own right (a SCEP-reachable CA such as AD CS with NDES, controller enrollment, and an AP re-provision that reboots the APs), and it should be proven on a lab 9800-CL, never first on a controller with live APs.
  • A publicly-trusted CA — a cert from a well-known public CA (DigiCert, Entrust, Verisign, etc.) whose roots Cisco ships in AP factory trust stores. In principle an AP would validate a controller cert from one of these without LSC provisioning. This is under evaluation and unproven — do not assume it works until it has been tested end to end.

Until one of those paths is validated, use Web UI, Captive portal, and EAP — they carry no AP-join risk. CAPWAP monitoring (watching the cert on UDP 5246) is separate and remains fully supported; it's only managing the CAPWAP cert that's gated off.


How it works

The CLM agent SSHes into the controller and, for each managed service, on every issue/renew:

  1. builds a PKCS#12 from the issued cert + chain + key locally on the agent (legacy 3DES/SHA1 encryption at 2048 KDF rounds — the format IOS-XE accepts),
  2. imports it into a PKI trustpoint with crypto pki import … pkcs12 terminal (once per distinct trustpoint — see "Sharing a trustpoint"),
  3. repoints that one service at the trustpoint using the service's own command (see the table above), and
  4. verifies and, on write-mem, saves the running config.

The controller credentials stay on the agent (in its local credential store); CertTracker holds only the non-secret target config (host, service, trustpoint name, SSH options).

What you'll need

  • A Catalyst 9800 (appliance or 9800-CL) on IOS-XE, SSH reachable from the agent, with a privilege-15 login (or a login plus an enable secret).
  • A CLM agent on 1.12.0+ (the release that introduced this adapter) that can reach the controller.
  • A managed certificate that meets the requirements below.

Certificate requirements — read this first

Same shape as any Cisco device cert:

  • RSA 2048 key (not EC) for the broadest compatibility.
  • Key Usage: Digital Signature, Key Encipherment
  • Extended Key Usage: TLS Web Server Authentication (serverAuth)
  • Subject Alternative Name: the FQDN the service is reached by

If you issue from Microsoft AD CS over SCEP/NDES: choose the Encryption (or Signature and Encryption) key usage — not "Signature only" — so Key Encipherment is set, on a template that includes Server Authentication.


Step 1 — Prepare the controller

On the controller (its own config, not the agent), ensure SSH and a privilege-15 login exist, and — for the Web UI service — the secure web server is on:

ip domain-name your.domain
crypto key generate rsa modulus 2048
ip ssh version 2
username clm-deploy privilege 15 secret <StrongPassword>

! only for the Web UI service
ip http secure-server

The agent creates and populates each service's trustpoint itself — you do not pre-create them.

Step 2 — The login credential (and enable), in the product — no CLI

Store the controller's username + password on the agent: Workers → Agent → Status → Credentials on this agent → + Add / update credential. CertTracker hands the secret to the agent over the authenticated channel and keeps no copy. Note the credential ref it generates.

Enable / privileged EXEC is a HOST setting on the 9800 adapter — one login per controller, shared by every service adapter, set on the host (Edit host → Device type: Catalyst 9800), not on each service. Pick one:

  • Login is already privilege 15 → leave the enable credential blank.
  • Separate enable secret → store a second credential and select it as the host's enable credential.
  • AAA where enable = your login password → check "reuse the login credential for enable."

Step 3 — Register the host, add a service adapter, deploy

On the Deployments tab:

  1. + Add host — name it, set Host to the controller's FQDN or management IP (IP is safest for internal names), SSH port 22, and Device type: Cisco Catalyst 9800 WLC. Set the enable handling here if the login isn't already privilege 15. Under Access, pick the credential from Step 2. Save — the row should show the credential loaded (green).

  2. On the host's row, Add adapter, once per service you're managing:

  3. Service: Web UI, Captive portal, or EAP. (CAPWAP is shown but disabled — see the callout above.)
  4. Cert: the managed certificate to install.
  5. Trustpoint: type a new name (e.g. CLM-WLC-WEB) or pick one already used on this host to share a cert.
  6. Captive portal also asks for the parameter-map name (default global); EAP also asks for the EAP profile name.

  7. Deploy now. The step trail runs build PKCS#12 → SSH connect → privileged EXEC → crypto pki import pkcs12 → repoint the service → write memory → verify. Renewals re-run the same path automatically.

Sharing a trustpoint across services

Point two adapters at the same trustpoint name and they share one certificate: the agent imports it once per distinct trustpoint and skips any trustpoint that already holds the exact cert (matched by serial). Give them different names to keep them fully separate. Because it's one adapter per service, you can split or re-share later without editing another adapter.

Verifying it worked

The deploy step trail shows the on-device confirmation for the service. To confirm the live Web UI cert from your own machine:

echo | openssl s_client -connect <wlc-fqdn>:443 2>/dev/null \
  | openssl x509 -noout -issuer -subject -dates -fingerprint -sha256

The fingerprint should match the cert's detail page and the issuer should be your CA.

Troubleshooting

  • All access points dropped after a CAPWAP change → revert the wireless-management trustpoint to the original (self-signed) trustpoint — wireless management trustpoint <original-name> — and the APs rejoin within a few minutes. This is exactly why CAPWAP is disabled in the product; see the callout above. Capture the current name with show wireless management trustpoint before any CAPWAP work.
  • private key is null / import fails, cert has an EC key → reissue with an RSA 2048 key.
  • Browser shows SEC_ERROR_INADEQUATE_CERT_TYPE even though the service serves the cert → the cert lacks Key Encipherment; reissue for encryption/key-exchange.
  • Captive portal / EAP % invalid on repoint → confirm the parameter-map (webauth) or EAP profile name exists (or let the agent create it) and that the login reached privileged EXEC.
  • Deploy green but "verify served cert" is a yellow âš  → the controller confirmed the cert on-device but the agent couldn't re-fetch it from its own network location. A warning, not a failure.