Uploaded on Dec. 12, 2025
Last modified on Dec. 12, 2025
A short tutorial on how to build a CA with Vault & issue (server & client) certificates for EAP-TLS authentication powered by FreeRADIUS. Part of my "upinem" project to stream-line the implementation of EAP-TLS enabled eduroam systems.
Related project:
TechYou can find more code and technical stuff on how to use Vault with FreeRADIUS from the following repo.
GitHub: joshua-liew/up-in-em
/etc/freeradius/certs directory.
Within that directory is the ca.cnf file, which contains the configuration used to generate the self-signed CA for the test certificates.
Using this as a reference, we can go about generating the CA in Vault.GitHub: /raddb/certs/ca.cnf
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = ./
certs = $dir
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir
certificate = $dir/ca.pem
serial = $dir/serial
crl = $dir/crl.pem
private_key = $dir/ca.key
RANDFILE = $dir/.rand
name_opt = ca_default
cert_opt = ca_default
default_days = 60
default_crl_days = 30
default_md = sha256
preserve = no
policy = policy_match
crlDistributionPoints = URI:http://www.example.org/example_ca.crl
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
prompt = no
distinguished_name = certificate_authority
default_bits = 2048
input_password = whatever
output_password = whatever
x509_extensions = v3_ca
[certificate_authority]
countryName = FR
stateOrProvinceName = Radius
localityName = Somewhere
organizationName = Example Inc.
emailAddress = admin@example.org
commonName = "Example Certificate Authority"
[v3_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = critical,CA:true
crlDistributionPoints = URI:http://www.example.org/example_ca.crl
pki secrets engine at pki_root path using the sys/mounts endpoint.
The pki_root engine will be used to generate the Root CA & subsequently sign the Intermediate CA. curl --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{"type":"pki"}' \
$VAULT_ADDR/v1/sys/mounts/pki_root
pki_root engine to issue certificates with max TTL of 87600 hours.
This corresponds to the max TTL of the Root CA generated by pki_root engine. NOTE: set the
max_lease_ttlas necessary.
API: [POST] /sys/mounts/:path/tune
curl --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{"max_lease_ttl":"87600h"}' \
$VAULT_ADDR/v1/sys/mounts/pki_root/tune
payload-gen-root-ca.json) containing information to generate the root certificate.
Refer to the API to understand which parameters can be used.max_path_length: Security Best Practice. Set to 1 to prevent the Intermediate CA from issuing another Intermediate CA.issuer_name: This parameter will be used as the issue_ref parameter when creating a Root CA role. NOTE: change parameters as necessary. Some of the parameters set here will be seen in the EAP-TLS process in FreeRADIUS later on in attributes such as
TLS-Cert-SubjectandTLS-Cert-Issuer.
API: [POST] /pki/root/generate/:type
{
"common_name": "Upinem AOU",
"issuer_name": "root-ca",
"ttl": "87600h",
"organization": "Aomori University",
"country": "JP",
"province": "Aomori-ken",
"locality": "Aomori-shi",
"max_path_length": 1,
"key_bits": 4096,
"key_type": "rsa"
}
curl --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-gen-root-ca.json \
$VAULT_ADDR/v1/pki_root/root/generate/internal \
| jq -r ".data.certificate" > root_ca.pem
API: [LIST] /pki/issuers
curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
--request LIST \
$VAULT_ADDR/v1/pki_root/issuers \
| jq -r ".data.keys[]"
# Extract and export it as a variable
export ISSUER_ROOT_ID=$(curl -s -H "X-Vault-Token: $VAULT_TOKEN" --request LIST $VAULT_ADDR/v1/pki_root/issuers | jq -r ".data.keys[]")
curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
$VAULT_ADDR/v1/pki_root/issuer/$ISSUER_ROOT_ID | jq
payload-role-root-ca.json) to create a role for the root CA.
Here are the list of important parameters.allow_any_name: Required for flexibility to sign the Intermediate CA's CSR, which will contain its own CN and subject fields. Rely on max_path_length for security.issuer_ref: Required to link this policy role to the Root CA certificate generated (above).max_path_length: CRITICAL Security Constraint. This ensures that any CA issued by this role (your Intermediate CA) can only sign one more layer of certificates (the final leaf/client certificates). This prevents unauthorized sub-CAs.key_usage: Required. "CertSign" and "CRLSign" are the minimum key usages for a CA certificate.{
"allow_any_name": true,
"issuer_ref": "root-ca",
"max_ttl": "43800h",
"key_usage": ["CertSign", "CRLSign"],
"organization": "Aomori University",
"country": "JP",
"province": "Aomori-ken",
"locality": "Aomori-shi"
}
root-ca-role for the Root CA.curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-role-root-ca.json \
$VAULT_ADDR/v1/pki_root/roles/root-ca-role
payload-url-ca.json) containing the URLs to set for the Root CA.crl_distribution_points: URL set here is seen in the TLS-Cert-CRL-Distribution-Points attribute during the EAP-TLS handshake in FreeRADIUS.{
"issuing_certificates": "http://127.0.0.1:8200/v1/pki_root/ca",
"crl_distribution_points": "http://127.0.0.1:8200/v1/pki_root/crl"
}
curl --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-url-ca.json \
$VAULT_ADDR/v1/pki_root/config/urls
pki secrets engine at pki_int path. Create a separate engine as best practice.curl --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{"type":"pki"}' \
$VAULT_ADDR/v1/sys/mounts/pki_int
pki_int secrets engine to issue certificates with a maximum TTL of 43800 hours.
This corresponds to the max TTL of the Intermediate CA generated by pki_int engine. NOTE: set the
max_lease_ttlas necessary.
API: [POST] /sys/mounts/:path/tune
curl --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data '{"max_lease_ttl":"43800h"}' \
$VAULT_ADDR/v1/sys/mounts/pki_int/tune
payload-gen-int-csr.json) used to generate the Intermediate CA's CSR.{
"common_name": "Upinem AOU Intermediate CA",
"organization": "Aomori University",
"country": "JP",
"province": "Aomori-ken",
"locality": "Aomori-shi",
"key_bits": 4096,
"key_type": "rsa"
}
/pki_int/intermediate/generate/internal endpoint and save it as pki_intermediate.csr.curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-gen-int-csr.json \
$VAULT_ADDR/v1/pki_int/intermediate/generate/internal \
| jq -c '.data | .csr' >> pki_intermediate.csr
payload-gen-int-ca.json) to sign the CSR. Use a script (payload-gen-int-ca.sh to generate the payload.
This is a CRITICAL STEP. Pay close attention to the parameters set here!common_name: Required to match the value set in the CSR. Will be seen in the EAP-TLS handshake within FreeRADIUS as the attributes TLS-Cert-Subject and TLS-Cert-Common-Name.permitted_email_addresses: CRITICAL for this use case. This embeds the Name Constraint into the Intermediate CA certificate, authorizing it to sign certificates for the example.com and example.org email domain.max_path_length: Security Hardening. Ensures the Intermediate CA can only issue leaf (end-entity) certificates and cannot sign another subordinate CA. (This overrides the max_path_length=1 set on the (signing) Root CA role).#!/bin/bash
tee payload-gen-int-ca.json <<EOF
{
"common_name": "Upinem AOU Intermediate CA",
"ttl": "43800h",
"max_path_length": 0,
"permitted_email_addresses": "example.com, example.org",
"format": "pem_bundle",
"use_csr_values": true,
"csr": $(cat pki_intermediate.csr)
}
EOF
pki_root path) private key, and save the certificate as intermediate.cert.pem.curl --silent --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-gen-int-ca.json \
$VAULT_ADDR/v1/pki_root/issuer/root-ca/sign-intermediate \
| jq '.data | .certificate' >> intermediate.cert.pem
pki_int secrets engine using the /pki_int/intermediate/set-signed endpoint.
Create an API request payload containing the certificate you obtained. Perform this with a script - payload-signed.sh.#!/bin/bash
tee payload-signed.json <<EOF
{
"certificate": $(cat intermediate.cert.pem)
}
EOF
pki_int engine.curl --silent --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-signed.json \
$VAULT_ADDR/v1/pki_int/intermediate/set-signed \
| jq
payload-url-int.json) containing the URLs to set for the Intermediate CA.crl_distribution_points: Seen in the TLS-Client-Cert-CRL-Distribution-Points attribute during the EAP-TLS handshake within FreeRADIUS.NOTE: the URLs set here are for the Intermediate CA. The Root CA has separate URLs as denoted by the paths -
pki_root/crlandpki_int/crl.
API: [POST] /pki/config/urls
{
"issuing_certificates": "http://127.0.0.1:8200/v1/pki_int/ca",
"crl_distribution_points": "http://127.0.0.1:8200/v1/pki_int/crl"
}
curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-url-int.json \
$VAULT_ADDR/v1/pki_int/config/urls
server.cnf file as a reference to create a role in Vault that issues server certificates.GitHub: /raddb/certs/server.cnf
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = ./
certs = $dir
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir
certificate = $dir/server.pem
serial = $dir/serial
crl = $dir/crl.pem
private_key = $dir/server.key
RANDFILE = $dir/.rand
name_opt = ca_default
cert_opt = ca_default
default_days = 60
default_crl_days = 30
default_md = sha256
preserve = no
policy = policy_match
copy_extensions = copy
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
prompt = no
distinguished_name = server
default_bits = 2048
input_password = whatever
output_password = whatever
#req_extensions = v3_req
[server]
countryName = FR
stateOrProvinceName = Radius
localityName = Somewhere
organizationName = Example Inc.
emailAddress = admin@example.org
commonName = "Example Server Certificate"
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
# This should be a host name of the RADIUS server.
# Note that the host name is exchanged in EAP *before*
# the user machine has network access. So the host name
# here doesn't really have to match anything in DNS.
[alt_names]
DNS.1 = radius.example.com
# NAIRealm from RFC 7585
otherName.0 = 1.3.6.1.5.5.7.8.8;FORMAT:UTF8,UTF8:*.example.com
payload-role-server.json) containing the role information.issuer_ref: Points to the Intermediate CA you just imported, ensuring it signs all leaf certs.allowed_domains: Limits the hostnames that can be requested i.e. only radius.example.com and example.com.cn_validations: CRITICAL. Enforces that the CN must be a hostname (e.g., radius.example.com).server_flag: CRITICAL. true enables the required TLS Web Server Authentication extended key usage.client_flag: Security. false prevents the certificate from being misused for client authentication.ext_key_usage: Explicitly sets the necessary Extended Key Usage. For TLS Web Server Authentication use "ServerAuth".allowed_other_sans: CRITICAL. This is required to allow the NAI Realm OID (1.3.6.1.5.5.7.8.8) seen in your server.cnf to be included in the server certificate.{
"issuer_ref": "default",
"max_ttl": "26280h",
"allowed_domains": "radius.example.com, example.com",
"allow_subdomains": true,
"allow_bare_domains": true,
"allow_glob_domains": true,
"cn_validations": "hostname",
"require_cn": true,
"enforce_hostnames": true,
"server_flag": true,
"client_flag": false,
"key_usage": ["DigitalSignature", "KeyEncipherment"],
"ext_key_usage": ["ServerAuth"],
"allowed_other_sans": "1.3.6.1.5.5.7.8.8;UTF8:*",
"key_type": "rsa",
"key_bits": 4096,
"organization": "Aomori University",
"country": "JP",
"province": "Aomori-ken",
"locality": "Aomori-shi"
}
eap-tls-server to issue server certificates for EAP-TLS usage.curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-role-server.json \
$VAULT_ADDR/v1/pki_int/roles/eap-tls-server \
| jq
payload-gen-server.json) to issue the server certificate.common_name: This must be the FQDN of your RADIUS server, matching the hostname constraint in the role.alt_names: Specifies the requested Subject Alternative Names, in a comma-delimited list. These can be host names or email addresses; they will be parsed into their respective fields. Ensures the FQDN is included as a DNS Subject Alternative Name (SAN), which is best practice for TLS validation.ip_sans: Replace this with the actual IP Address of your RADIUS server if clients will connect via IP.other_sans: CRITICAL. This directly includes the required NAI Realm SAN from your FreeRADIUS server.cnf, which the eap-tls-server role is configured to allow.{
"common_name": "radius.example.com",
"alt_names": "radius.example.com, upinem.example.com",
"ip_sans": "192.168.1.100",
"other_sans": "1.3.6.1.5.5.7.8.8;UTF8:*.example.com",
"ttl": "8760h",
"format": "pem_bundle"
}
result-server-cert.json file.
We will extract the necessary information from the json file with jq later on.curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-gen-server.json \
$VAULT_ADDR/v1/pki_int/issue/eap-tls-server \
| jq > result-server-cert.json
server.key. Will be ported for use in FreeRADIUS.jq -r '.data.private_key' result-server-cert.json > server.key
server.pem. Will be ported for use in FreeRADIUS.jq -r '.data.certificate' result-server-cert.json | \
grep -E 'BEGIN CERTIFICATE|END CERTIFICATE|' | \
awk '
BEGIN {cert_found=0}
/BEGIN CERTIFICATE/ { cert_found=1; print; next }
cert_found { print }
/END CERTIFICATE/ { exit }
' > server.pem
ca.pem.
This contains the Intermediate and Root CAs for client trust.
Will be ported for use in FreeRADIUS.jq -r '.data.ca_chain[]' result-server-cert.json > ca.pem
client.cnf file as a reference to create a role in Vault that issues client certificates.GitHub: /raddb/certs/client.cnf
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = ./
certs = $dir
crl_dir = $dir/crl
database = $dir/index.txt
new_certs_dir = $dir
certificate = $dir/ca.pem
serial = $dir/serial
crl = $dir/crl.pem
private_key = $dir/ca.key
RANDFILE = $dir/.rand
name_opt = ca_default
cert_opt = ca_default
default_days = 60
default_crl_days = 30
default_md = sha256
preserve = no
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
prompt = no
distinguished_name = client
default_bits = 2048
input_password = whatever
output_password = whatever
[client]
countryName = FR
stateOrProvinceName = Radius
localityName = Somewhere
organizationName = Example Inc.
emailAddress = user@example.org
commonName = user@example.org
payload-role-client.json) for the role used to create client certificates.issuer_ref: Points to the Intermediate CA you just imported, ensuring it signs all leaf certs.allowed_domains: Constrains the domains to match the Intermediate CA's Name Constraints.cn_validations: CRITICAL. Forces the Common Name to be an email address (e.g., user@example.com).client_flag: CRITICAL. true enables the clientAuth Extended Key Usage used for client authentication.server_flag: Security. false prevents the client certificate from being misused to impersonate a server.key_usage: Standard usages ("DigitalSignature", "KeyAgreement") for client authentication, focusing on signature/key exchange.ext_key_usage: Specifies the exact EKU OID to be included in the certificate (e.g., ClientAuth).{
"issuer_ref": "default",
"max_ttl": "26280h",
"allowed_domains": "example.com, example.org",
"allow_subdomains": true,
"allow_bare_domains": true,
"allow_glob_domains": false,
"cn_validations": "email",
"require_cn": true,
"enforce_hostnames": false,
"server_flag": false,
"client_flag": true,
"key_usage": ["DigitalSignature", "KeyAgreement"],
"ext_key_usage": ["ClientAuth"],
"key_type": "rsa",
"key_bits": 4096,
"organization": "Aomori University",
"country": "JP",
"province": "Aomori-ken",
"locality": "Aomori-shi"
}
eap-tls-client to issue client certificates for EAP-TLS usage.curl -s --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-role-client.json \
$VAULT_ADDR/v1/pki_int/roles/eap-tls-client \
| jq
# payload-gen-client-1.json
{
"common_name": "user1@example.com",
"alt_names": "user1@example.com",
"ip_sans": "192.168.1.200",
"ttl": "8760h"
}
# payload-gen-client-2.json
{
"common_name": "user2@example.org",
"alt_names": "user2@example.org",
"ip_sans": "192.168.1.201",
"ttl": "8760h"
}
# Create client cert with CN 'user1@example.com'
curl --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-gen-client-1.json \
$VAULT_ADDR/v1/pki_int/issue/eap-tls-client \
| jq > result-client-1.json
# Create client cert with CN 'user2@example.com'
curl --header "X-Vault-Token: $VAULT_TOKEN" \
--request POST \
--data @payload-gen-client-2.json \
$VAULT_ADDR/v1/pki_int/issue/eap-tls-client \
| jq > result-client-2.json
You can use
jq -r '.data.ca_chain[]' result-client-1.json > client-1-ca.pemto extract the CA chain. However this is unnecessary as the CA chain of the server certificate is identical to those of the client certificates. Using the CA chain of the server certificate will suffice.
jq -r '.data.private_key' result-client-1.json > client-1.key
jq -r '.data.certificate' result-client-1.json > client-1.pem
jq -r '.data.private_key' result-client-2.json > client-2.key
jq -r '.data.certificate' result-client-2.json > client-2.pem
sudo rm /etc/freeradius/mods-enabled/eap
upinem-eap.conf) with minimum necessary settings configured for EAP-TLS.
Save the EAP module to the /etc/freeradius/mods-available directory where modules are defined.
Required to set the proper permissions so that the FreeRADIUS process can eventually read the module config.private_key_file: Point to the private key (.key) of the server certificate created above (i.e. server.key in Step 3).certificate_file: Point to the server certificate (.pem) created above (i.e. server.pem in Step 3)ca_file: Point to the CA chain file created above (i.e. ca.pem in Step 3)private_key_password: Comment out. Redundant to encrypt private_key_file; unnecessary.##
## upinem-eap.conf -- UPINEM EAP module
## configuration file for FreeRADIUS - 3.2.*
##
## Find out more about UPINEM below.
## https://github.com/joshua-liew/up-in-em
######################################################################
eap {
default_eap_type = tls
timer_expire = 60
ignore_unknown_eap_types = no
max_sessions = ${max_requests}
# Common TLS configuration for TLS-based EAP types
tls-config tls-common {
#private_key_password = whatever
private_key_file = ${certdir}/server.key
certificate_file = ${certdir}/server.pem
ca_file = ${cadir}/ca.pem
ca_path = ${cadir}
auto_chain = yes
# check_cert_issuer = "<CERT_ISSUER>"
# check_cert_cn = %{User-Name}
cipher_list = "DEFAULT"
cipher_server_preference = no
tls_min_version = "1.2"
tls_max_version = "1.2"
ecdh_curve = ""
}
# EAP-TLS configuration
tls {
tls = tls-common
#virtual_server = check-eap-tls
}
}
upinem-eap module created. Symbolic links are used for this purpose.sudo ln -sr /etc/freeradius/mods-available/upinem-eap.conf /etc/freeradius/mods-enabled/upinem-eap
# You may need to set permissions for the symbolic link.
sudo chown freeradius:freeradius -h /etc/freeradius/mods-enabled/upinem-eap
realms to the proxy.file to ensure that the corresponding EAP identities are handled locally.
Any empty realm or realm with no server pool specified causes packets to be processed locally.
These realms must correspond to the CN constraints (allowed_domains, allow_subdomains, etc.) for client authentication in EAP-TLS set in Step 4.realm example.com {
}
realm example.org {
}
sudo -u freeradius radiusd -X
FreeRADIUS Version 3.2.8
...
Starting - reading configuration files ...
...
including configuration file /etc/freeradius/mods-enabled/upinem-eap
...
radiusd: #### Instantiating modules ####
...
# Loaded module rlm_eap
# Loading module "eap" from file /etc/freeradius/mods-enabled/upinem-eap
eap {
default_eap_type = "tls"
timer_expire = 60
max_eap_type = 52
ignore_unknown_eap_types = no
cisco_accounting_username_bug = no
max_sessions = 16384
dedup_key = ""
}
...
# Instantiating module "eap" from file /etc/freeradius/mods-enabled/upinem-eap
# Linked to sub-module rlm_eap_tls
tls {
tls = "tls-common"
}
tls-config tls-common {
verify_depth = 0
ca_path = "/etc/freeradius/certs"
pem_file_type = yes
private_key_file = "/etc/freeradius/certs/server.key"
certificate_file = "/etc/freeradius/certs/server.pem"
ca_file = "/etc/freeradius/certs/ca.pem"
fragment_size = 1024
include_length = yes
auto_chain = yes
check_crl = no
check_all_crl = no
ca_path_reload_interval = 0
cipher_list = "DEFAULT"
cipher_server_preference = no
reject_unknown_intermediate_ca = no
ecdh_curve = ""
tls_max_version = "1.2"
tls_min_version = "1.2"
cache {
enable = no
lifetime = 24
max_entries = 255
}
verify {
skip_if_ocsp_ok = no
}
ocsp {
enable = no
override_cert_url = no
use_nonce = yes
timeout = 0
softfail = no
}
}
...
You can install the
eapol_testtool with apt-get:sudo apt-get install eapoltest
# test-client-1.conf
network={
ssid="test"
key_mgmt=WPA-EAP
eap=TLS
identity="user1@example.com"
ca_cert="/tmp/certs/ca.pem"
client_cert="/tmp/certs/clients/client-1.pem"
private_key="/tmp/certs/clients/client-1.key"
eapol_flags=3
}
radiusd -X running in one terminal, open another terminal and perform the eapol test.
You should see a SUCCESS message in the terminal.eapol_test -c test-client-1.conf -s testing123
# Example output below
Reading configuration file 'test-client-1.conf'
Line: 1 - start of a new network block
ssid - hexdump_ascii(len=4):
74 65 73 74 test
key_mgmt: 0x1
eap methods - hexdump(len=16): 00 00 00 00 0d 00 00 00 00 00 00 00 00 00 00 00
identity - hexdump_ascii(len=21):
... user1@example.com
ca_cert - hexdump_ascii(len=17):
... /tmp/certs/ca.pem
client_cert - hexdump_ascii(len=31):
... /tmp/certs/clients/client-1.pem
private_key - hexdump_ascii(len=31):
... /tmp/certs/clients/client-1.key
Priority group 0
id=0 ssid='test'
...
MPPE keys OK: 1 mismatch: 0
SUCCESS
Sent Access-Accept logged within the output....
(9) eap_tls: TLS-Cert-Serial := "5b477fe9fd13eeed3b043572ce23fa3a4f0d80d0"
(9) eap_tls: TLS-Cert-Expiration := "301126100938Z"
(9) eap_tls: TLS-Cert-Valid-Since := "251127100908Z"
(9) eap_tls: TLS-Cert-Subject := "/C=JP/ST=Aomori-ken/L=Aomori-shi/O=Aomori University/CN=Upinem AOU Intermediate CA"
(9) eap_tls: TLS-Cert-Issuer := "/C=JP/ST=Aomori-ken/L=Aomori-shi/O=Aomori University/CN=Upinem AOU"
(9) eap_tls: TLS-Cert-Common-Name := "Upinem AOU Intermediate CA"
(9) eap_tls: TLS-Cert-CRL-Distribution-Points += "http://127.0.0.1:8200/v1/pki_root/crl"
(9) eap_tls: (TLS) TLS - Creating attributes from certificate 1 in chain
(9) eap_tls: TLS-Client-Cert-Serial := "084cf7653d49b706801c38f820125ace298a1788"
(9) eap_tls: TLS-Client-Cert-Expiration := "261128072323Z"
(9) eap_tls: TLS-Client-Cert-Valid-Since := "251128072254Z"
(9) eap_tls: TLS-Client-Cert-Subject := "/C=JP/ST=Aomori-ken/L=Aomori-shi/O=Aomori University/CN=user1@sub.example.com"
(9) eap_tls: TLS-Client-Cert-Issuer := "/C=JP/ST=Aomori-ken/L=Aomori-shi/O=Aomori University/CN=Upinem AOU Intermediate CA"
(9) eap_tls: TLS-Client-Cert-Common-Name := "user1@example.com"
(9) eap_tls: TLS-Client-Cert-CRL-Distribution-Points += "http://127.0.0.1:8200/v1/pki_int/crl"
(9) eap_tls: TLS-Client-Cert-Subject-Alt-Name-Email := "user1@example.com"
(9) eap_tls: TLS-Client-Cert-X509v3-Extended-Key-Usage += "TLS Web Client Authentication"
(9) eap_tls: TLS-Client-Cert-X509v3-Subject-Key-Identifier += "DD:3B:59:A3:E2:AD:B3:0D:F2:42:9F:83:39:F4:59:71:51:F2:7F:6A"
(9) eap_tls: TLS-Client-Cert-X509v3-Authority-Key-Identifier += "7C:CE:86:95:50:B8:E5:DE:1F:40:1D:AE:C3:0B:55:72:C2:7A:1D:7F"
(9) eap_tls: TLS-Client-Cert-X509v3-Extended-Key-Usage-OID += "1.3.6.1.5.5.7.3.2"
...
(10) Sent Access-Accept Id 10 from 127.0.0.1:1812 to 127.0.0.1:60161 length 189
(10) MS-MPPE-Recv-Key = 0x7447441801becf79d243bf3d08df60dd307bebcbd756fb4f8e0fdfcec7a82207
(10) MS-MPPE-Send-Key = 0xc6b811229731c1e2f6ecde0fbcf03bed01237456b03c90dbe90329bec1ce845e
(10) EAP-Message = 0x03e90004
(10) Message-Authenticator = 0x00000000000000000000000000000000
(10) User-Name = "user1@example.com"
(10) Framed-MTU += 1014
(10) Finished request
Congratulations. You have successfully configured FreeRADIUS to perform EAP-TLS authentication with certificates generated by Vault's PKI Secrets Engine.