Reissuing a laptop certificate under the same common name feels like a replacement, and everyone assumes the old one is dead. It is not. The predecessor remains a valid certificate signed by the same authority, and any control that admits clients by name will keep admitting it. What separates an identity check from a credential check is the serial number, and that is where the fix belongs.

Start with the naming policy the server uses

Two controls get conflated: admitting a client because of who it claims to be, and removing one specific certificate from service. The first is a name check, the second is a revocation check. They answer different questions, and a deployment can have one without the other.

Read the server configuration and note which identity source is in play. username-as-common-name makes the authenticated username the effective name for client-specific lookups. Without it, the subject common name from the certificate is used. Whatever the answer is, write it down before you touch any allowlist.

The two paths produce a different set of permitted names for the same certificate. Guessing here means editing the wrong file and concluding the control does not work.

Check what actually admits a client

A client-config-dir with a matching file supplies per-client options; on its own it is not an admission rule. Admission by name requires ccd-exclusive, which refuses clients that have no matching file. Enabling that on a live deployment disconnects everyone whose name has no file, so count the files before you flip anything.

grep -nE 'ccd-exclusive|client-config-dir|username-as-common-name' /etc/openvpn/server/server.conf
ls -1 /etc/openvpn/ccd/

The count is the check: compare the directory listing with the identities you expect to connect.

Then confirm each file name matches the effective identity exactly, including case and spacing. A file for office-laptop does nothing for a certificate whose subject reads Office-Laptop. Trailing whitespace also hides from a plain listing, which is how a file that looks present stays unread.

Check the CRL the gateway loads

A CRL names revoked certificates by issuer and serial, which is the granularity a name check lacks. Two certificates can share a common name and differ in serial, and only a serial-level list separates them.

Confirm the configured path, the issue date and the next-update field before trusting the file at all.

openssl crl -in /etc/openvpn/crl.pem -noout -lastupdate -nextupdate
openssl x509 -in office-laptop.crt -noout -serial -subject

Compare the serial in the CRL with the serial on the certificate you intend to keep. That comparison is the whole test, and doing it by eye once is worth more than trusting a script nobody read. Distribute the updated CRL through the path the gateway already reads. A CRL sitting in the wrong directory enforces nothing, and no client log will mention it.

Replace, then prove both outcomes

Issue the replacement under the same common name, record both serials, and only then revoke the old one. That order keeps a working identity available while you prepare the change.

Test the replacement first: it should authenticate and reach whatever its name is entitled to. Then test the old certificate and confirm it is refused, because a successful replacement says nothing about revocation. If both still connect, the revocation input is not being read or the old serial was never listed. If neither connects, you have broken the admission rule rather than the credential.

Sessions already established are a separate matter, since revocation applies to new authentications unless the gateway is also configured to drop live connections. Decide whether immediate removal is required before you promise it to anyone.

What a name check can never do

An allowlist answers whether this identity may connect. It cannot say which certificate that identity used, and it will admit an older credential for as long as the credential remains valid and unrevoked. That gap surfaces during an incident, when the replacement was issued months ago and the predecessor still works.

Where certificate-level control is required, use a mechanism that names the certificate: CRL entries, or a verify hook that checks a fingerprint the operator maintains. Both cost maintenance, and both are honest about the object they examine. The OpenVPN 2.6 manual documents crl-verify and client-specific admission as separate options for that reason.

Write down which control does which job, then test the negative case. A revocation you have never watched refuse a connection is a configuration you are hoping works.

Qillqakuna t'inkisqa