Authenticate with client certificates (EAP-TLS)
When you need this
Section titled “When you need this”PEAP-MSCHAPv2 authenticates a username and password inside a TLS tunnel. That works, but the inner MS-CHAPv2 primitive is weak, and the whole thing rests on the tunnel. EAP-TLS removes the password entirely: the endpoint presents a client certificate, the server verifies it against a trust anchor, and the authenticated identity is the certificate’s subject. If you can issue client certificates to your endpoints, this is the stronger method.
l2trace runs EAP-TLS as a peer of PEAP on the same RADIUS server. You do not choose per port; the server offers a method and a supplicant configured for EAP-TLS asks for it (via a Legacy Nak), and the server switches. Nothing else about the setup changes.
The trust model
Section titled “The trust model”The one thing that makes EAP-TLS meaningful is the trust anchor: the CA a
client certificate must chain to. l2trace will not run EAP-TLS without one. A server
that verified nothing would complete every handshake and authenticate anyone, so if
RADIUS_EAP_TLS_CLIENT_CA is unset, EAP-TLS is simply off, and if it is set to a CA,
only certificates that chain to it are accepted.
1. Get certificates
Section titled “1. Get certificates”For a lab, scripts/gen_lab_ca.py mints a throwaway CA, the l2trace server leaf, a
client leaf, and an empty CRL, and prints which file maps to which setting:
uv run python scripts/gen_lab_ca.py --force --hostname radius.lab.example --ip 127.0.0.1| File | Used as |
|---|---|
ca.crt | RADIUS_EAP_TLS_CLIENT_CA (the trust anchor) |
server.crt / server.key | RADIUS_TLS_CERT / RADIUS_TLS_KEY (the server leaf) |
client.crt / client.key | the endpoint’s EAP-TLS credential |
crl.pem | RADIUS_EAP_TLS_CRL (optional revocation list) |
For production, issue these from your own PKI. Nothing about the lab script is fit for production; it exists to prove the flow.
2. Configure the server
Section titled “2. Configure the server”Set the trust anchor (and, optionally, a CRL) in the server’s environment:
RADIUS_EAP_TLS_CLIENT_CA=/path/to/ca.crtRADIUS_EAP_TLS_CRL=/path/to/crl.pem # optional, see revocation belowThe server leaf it presents inside the tunnel is the same RADIUS_TLS_CERT /
RADIUS_TLS_KEY PEAP already uses.
3. Point the endpoint at the SSID or port
Section titled “3. Point the endpoint at the SSID or port”The switch or access point config is ordinary 802.1X, the same RADIUS server, the same shared secret. The only change is on the endpoint: its supplicant is configured for EAP-TLS with the client certificate and key, not a username and password. When it Naks the server’s first offer and asks for EAP-TLS, the server hands the conversation to its EAP-TLS state machine automatically.
4. Watch the decision
Section titled “4. Watch the decision”On success the auth_event records the identity taken from the certificate subject,
plus a credential note naming the certificate’s issuer and serial. That note is
what you need to revoke the exact credential that got on the network, without it, “a
cert authenticated” is not actionable.
Revocation
Section titled “Revocation”Set RADIUS_EAP_TLS_CRL to a PEM CRL and l2trace checks the client’s leaf against
it: a revoked certificate then fails the handshake exactly like an untrusted one.
See also
Section titled “See also”- Stand up 802.1X in monitor mode, the wired base and the monitor-first rollout
- Stand up wireless 802.1X, WPA-Enterprise and the session keys
- The security model, and the sharp edges, where EAP-TLS sits relative to PEAP in the threat model
- Manage secrets, how the server’s own key is handled