Vault PKI Certificate Issuance
Overview
This runbook covers issuing client certificates from Vault PKI (DOMUS-ROOT-CA / DOMUS-ISSUING-CA) for 802.1X EAP-TLS authentication.
PKI Infrastructure:
| Component | Description | Location |
|---|---|---|
DOMUS-ROOT-CA |
Offline root CA |
Vault PKI on vault-01 |
DOMUS-ISSUING-CA (pki_int) |
Issuing CA for client/server certs |
Vault PKI on vault-01 |
ISE |
RADIUS server trusting DOMUS-ROOT-CA |
ise-01.inside.domusdigitalis.dev |
Prerequisites
-
SSH access to vault-01
-
Vault credentials from dsec (
dev/vault) -
Target hostname for certificate CN
Phase 1: Vault Access
1.1 Get Vault Credentials (Workstation)
dsource d000 dev/vault
This exports:
-
VAULT_UNSEAL_KEY_1 -
VAULT_UNSEAL_KEY_2 -
VAULT_TOKEN
Copy these values - you’ll need them on vault-01.
1.3 Set Vault Address
export VAULT_ADDR='http://127.0.0.1:8200'
| Vault runs on HTTP locally, not HTTPS. |
1.4 Check Vault Status
vault status
Filter to key fields with awk:
vault status | awk 'NR <= 5'
Key Value --- ----- Seal Type shamir Initialized true Sealed false
awk 'NR ⇐ 5' = print first 5 lines. Condition OUTSIDE braces, implicit print action.
|
Phase 2: Verify PKI Configuration
2.1 List PKI Engines
vault secrets list | grep pki
pki/ pki pki_... root CA pki_int/ pki pki_... intermediate/issuing CA
2.2 List Available Roles
vault list pki_int/roles
Keys ---- domus-byod domus-client domus-server domus-windows-machine domus-windows-user
Role Selection:
| Role | Use Case |
|---|---|
|
Linux/macOS EAP-TLS client certs |
|
Server certificates (web, API) |
|
Windows computer certificates |
|
Windows user certificates |
|
BYOD device certificates |
Phase 3: Issue Certificate
3.1 Issue Certificate to JSON
Replace <hostname> with the target machine’s FQDN:
vault write -format=json pki_int/issue/domus-client \
common_name="<hostname>.inside.domusdigitalis.dev" \
ttl="8760h" > /tmp/<hostname>-cert.json
vault write -format=json pki_int/issue/domus-client \
common_name="modestus-razer.inside.domusdigitalis.dev" \
ttl="8760h" > /tmp/modestus-razer-cert.json
ttl="8760h" = 1 year. Adjust as needed.
|
3.2 Extract Certificate Components
Extract certificate, private key, and CA chain:
jq -r '.data.certificate' /tmp/<hostname>-cert.json > /tmp/<hostname>-eaptls.crt
jq -r '.data.private_key' /tmp/<hostname>-cert.json > /tmp/<hostname>-eaptls.key
jq -r '.data.ca_chain[]' /tmp/<hostname>-cert.json > /tmp/domus-ca-chain.crt
jq -r '.data.certificate' /tmp/modestus-razer-cert.json > /tmp/modestus-razer-eaptls.crt
jq -r '.data.private_key' /tmp/modestus-razer-cert.json > /tmp/modestus-razer-eaptls.key
jq -r '.data.ca_chain[]' /tmp/modestus-razer-cert.json > /tmp/domus-ca-chain.crt
3.3 Verify Extraction
ls -la /tmp/<hostname>-eaptls.*
openssl x509 -in /tmp/<hostname>-eaptls.crt -noout -subject -issuer -dates
ls -la /tmp/modestus-razer-eaptls.*
openssl x509 -in /tmp/modestus-razer-eaptls.crt -noout -subject -issuer -dates
subject=CN=modestus-razer.inside.domusdigitalis.dev issuer=CN=DOMUS-ISSUING-CA notBefore=Feb 8 22:08:37 2026 GMT notAfter=Feb 8 22:09:07 2027 GMT
Extract Certificate Fields with awk
One-liner to extract O=/OU=/CN= from certificate subject:
openssl x509 -in /tmp/<hostname>-eaptls.crt -noout -subject | \
awk -F'/' '{for(i=1;i<=NF;i++) if($i~/^(O|OU|CN)=/) print $i}'
O=Domus-Infrastructure OU=Domus-Users CN=modestus-razer.inside.domusdigitalis.dev
awk field loop: -F'/' splits on /, then for(i=1;i⇐NF;i++) loops through fields, $i~/regex/ matches fields containing O=, OU=, or CN=.
|
Phase 4: Deploy to Client
4.1 Copy Files to Workstation
From your workstation (not vault-01):
scp vault-01:/tmp/<hostname>-eaptls.crt /tmp/
scp vault-01:/tmp/<hostname>-eaptls.key /tmp/
scp vault-01:/tmp/domus-ca-chain.crt /tmp/
scp vault-01:/tmp/modestus-razer-eaptls.crt /tmp/
scp vault-01:/tmp/modestus-razer-eaptls.key /tmp/
scp vault-01:/tmp/domus-ca-chain.crt /tmp/
4.2 Install Certificate
Install cert, key (with secure permissions), and CA chain:
sudo cp /tmp/<hostname>-eaptls.crt /etc/ssl/certs/<hostname>-eaptls.pem
sudo cp /tmp/<hostname>-eaptls.key /etc/ssl/private/<hostname>-eaptls.key
sudo chmod 600 /etc/ssl/private/<hostname>-eaptls.key
sudo cp /tmp/domus-ca-chain.crt /etc/ssl/certs/DOMUS-CA-CHAIN.pem
sudo cp /tmp/modestus-razer-eaptls.crt /etc/ssl/certs/modestus-razer-eaptls.pem
sudo cp /tmp/modestus-razer-eaptls.key /etc/ssl/private/modestus-razer-eaptls.key
sudo chmod 600 /etc/ssl/private/modestus-razer-eaptls.key
sudo cp /tmp/domus-ca-chain.crt /etc/ssl/certs/DOMUS-CA-CHAIN.pem
4.3 Check if Root CA Already Installed
ls -la /etc/ssl/certs/DOMUS-ROOT-CA.pem
If file exists, verify it’s the correct CA:
openssl x509 -in /etc/ssl/certs/DOMUS-ROOT-CA.pem -noout -subject -issuer
subject=C=US, O=Domus Digitalis, OU=Enterprise PKI, CN=DOMUS-ROOT-CA issuer=C=US, O=Domus Digitalis, OU=Enterprise PKI, CN=DOMUS-ROOT-CA
If present and correct, skip to Phase 4.4.
4.4 Install Root CA (Only If Missing)
Only run this if 4.3 showed the file is missing:
scp vault-01:/etc/ssl/certs/domus-root-ca.crt /tmp/
sudo cp /tmp/domus-root-ca.crt /etc/ssl/certs/DOMUS-ROOT-CA.pem
Verify installation:
openssl x509 -in /etc/ssl/certs/DOMUS-ROOT-CA.pem -noout -subject -issuer
4.5 Verify All Installed Files
ls -la /etc/ssl/certs/<hostname>-eaptls.pem
ls -la /etc/ssl/private/<hostname>-eaptls.key
openssl x509 -in /etc/ssl/certs/<hostname>-eaptls.pem -noout -subject -issuer
ls -la /etc/ssl/certs/modestus-razer-eaptls.pem
ls -la /etc/ssl/private/modestus-razer-eaptls.key
openssl x509 -in /etc/ssl/certs/modestus-razer-eaptls.pem -noout -subject -issuer
Phase 5: Pre-Flight Validation
5.1 Verify ISE Trusts DOMUS CAs
|
If ISE does not trust both DOMUS-ROOT-CA and DOMUS-ISSUING-CA, authentication will fail. |
netapi ise api-call openapi GET '/api/v1/certs/trusted-certificate?size=100' | jq -r '.response[].friendlyName' | grep -i domus
DOMUS-ROOT-CA DOMUS-ISSUING-CA
If DOMUS-ROOT-CA is not listed, you must add it to ISE before proceeding:
-
Export DOMUS-ROOT-CA from Vault
-
Import into ISE: Administration > System > Certificates > Trusted Certificates
-
Enable for "Trust for client authentication"
5.2 Verify Certificate Chain
The cert is signed by DOMUS-ISSUING-CA (intermediate), so verify against the full chain:
openssl verify -CAfile /etc/ssl/certs/DOMUS-CA-CHAIN.pem /etc/ssl/certs/<hostname>-eaptls.pem
openssl verify -CAfile /etc/ssl/certs/DOMUS-CA-CHAIN.pem /etc/ssl/certs/modestus-razer-eaptls.pem
/etc/ssl/certs/modestus-razer-eaptls.pem: OK
DOMUS-CA-CHAIN.pem contains both DOMUS-ISSUING-CA and DOMUS-ROOT-CA.
|
Phase 6: Configure NetworkManager (Wired 802.1X)
6.1 List Existing Connections
First, check what connections exist:
nmcli connection show | grep -E "ethernet|wifi|802"
Wired-802.1X 6730f285-c9f4-4a7d-95f3-93287dbddf35 ethernet -- Domus-Secure-802.1X 8dbd3d7d-406e-4ac9-b303-be0a1b40bd86 wifi wlan0
6.2 Create New Connection (Recommended)
|
Recommended for production: Create a NEW connection instead of modifying existing. This preserves your working config as a fallback if the new cert fails. |
sudo nmcli connection add type ethernet con-name "Wired-802.1X-Vault" \
802-1x.eap tls \
802-1x.identity "<hostname>.inside.domusdigitalis.dev" \
802-1x.client-cert /etc/ssl/certs/<hostname>-eaptls.pem \
802-1x.private-key /etc/ssl/private/<hostname>-eaptls.key \
802-1x.ca-cert /etc/ssl/certs/DOMUS-ROOT-CA.pem
sudo nmcli connection add type ethernet con-name "Wired-802.1X-Vault" \
802-1x.eap tls \
802-1x.identity "modestus-razer.inside.domusdigitalis.dev" \
802-1x.client-cert /etc/ssl/certs/modestus-razer-eaptls.pem \
802-1x.private-key /etc/ssl/private/modestus-razer-eaptls.key \
802-1x.ca-cert /etc/ssl/certs/DOMUS-ROOT-CA.pem
sudo is required because the private key file has restricted permissions (600).
|
6.3 Fix Private Key Password Prompt
If nmcli prompts for secrets, set password flags to "not required":
sudo nmcli connection modify "Wired-802.1X-Vault" \
802-1x.private-key-password "" \
802-1x.private-key-password-flags 4
password-flags 4 means "not required" - use this when the private key has no passphrase.
|
6.4 Alternative: Update Existing Connection (Riskier)
Only use this if you understand the rollback implications:
Option A: Update existing connection
sudo nmcli connection modify "Wired-802.1X" \
802-1x.eap tls \
802-1x.identity "<hostname>.inside.domusdigitalis.dev" \
802-1x.client-cert /etc/ssl/certs/<hostname>-eaptls.pem \
802-1x.private-key /etc/ssl/private/<hostname>-eaptls.key \
802-1x.ca-cert /etc/ssl/certs/DOMUS-ROOT-CA.pem
sudo nmcli connection modify "Wired-802.1X" \
802-1x.eap tls \
802-1x.identity "modestus-razer.inside.domusdigitalis.dev" \
802-1x.client-cert /etc/ssl/certs/modestus-razer-eaptls.pem \
802-1x.private-key /etc/ssl/private/modestus-razer-eaptls.key \
802-1x.ca-cert /etc/ssl/certs/DOMUS-ROOT-CA.pem
Phase 6B: Configure NetworkManager (WiFi 802.1X)
If you also have WiFi 802.1X (e.g., WPA2-Enterprise), configure it to use the same Vault certificate.
6B.1 List Existing WiFi Connections
nmcli connection show | grep wifi
Domus-Secure-802.1X 8dbd3d7d-406e-4ac9-b303-be0a1b40bd86 wifi wlan0
6B.2 Option A: Modify Existing WiFi Connection
If your WiFi is already configured with 802.1X, update the certificate paths:
sudo nmcli connection modify "<wifi-connection-name>" \
802-1x.client-cert /etc/ssl/certs/<hostname>-eaptls.pem \
802-1x.private-key /etc/ssl/private/<hostname>-eaptls.key \
802-1x.ca-cert /etc/ssl/certs/DOMUS-ROOT-CA.pem \
802-1x.private-key-password "" \
802-1x.private-key-password-flags 4
sudo nmcli connection modify "Domus-Secure-802.1X" \
802-1x.client-cert /etc/ssl/certs/modestus-razer-eaptls.pem \
802-1x.private-key /etc/ssl/private/modestus-razer-eaptls.key \
802-1x.ca-cert /etc/ssl/certs/DOMUS-ROOT-CA.pem \
802-1x.private-key-password "" \
802-1x.private-key-password-flags 4
6B.3 Option B: Create New WiFi Connection
For a fresh setup or to preserve the old config as fallback:
sudo nmcli connection add type wifi con-name "WiFi-802.1X-Vault" \
wifi.ssid "<ssid>" \
wifi-sec.key-mgmt wpa-eap \
802-1x.eap tls \
802-1x.identity "<hostname>.inside.domusdigitalis.dev" \
802-1x.client-cert /etc/ssl/certs/<hostname>-eaptls.pem \
802-1x.private-key /etc/ssl/private/<hostname>-eaptls.key \
802-1x.ca-cert /etc/ssl/certs/DOMUS-ROOT-CA.pem \
802-1x.private-key-password "" \
802-1x.private-key-password-flags 4
sudo nmcli connection add type wifi con-name "WiFi-802.1X-Vault" \
wifi.ssid "Domus-Secure" \
wifi-sec.key-mgmt wpa-eap \
802-1x.eap tls \
802-1x.identity "modestus-razer.inside.domusdigitalis.dev" \
802-1x.client-cert /etc/ssl/certs/modestus-razer-eaptls.pem \
802-1x.private-key /etc/ssl/private/modestus-razer-eaptls.key \
802-1x.ca-cert /etc/ssl/certs/DOMUS-ROOT-CA.pem \
802-1x.private-key-password "" \
802-1x.private-key-password-flags 4
6B.4 Verify WiFi 802.1X Configuration
nmcli connection show "Domus-Secure-802.1X" | grep -E "802-1x\.(eap|identity|client-cert|private-key|ca-cert)"
802-1x.eap: tls 802-1x.identity: modestus-razer.inside.domusdigitalis.dev 802-1x.ca-cert: /etc/ssl/certs/DOMUS-ROOT-CA.pem 802-1x.client-cert: /etc/ssl/certs/modestus-razer-eaptls.pem 802-1x.private-key: /etc/ssl/private/modestus-razer-eaptls.key
Phase 7: Test Authentication
7.1 Watch Logs (Terminal 1)
Open a separate terminal to watch the EAP-TLS handshake in real-time:
journalctl -f -u NetworkManager -u wpa_supplicant
7.2 Activate Wired Connection (Terminal 2)
In your original terminal, bring up the wired connection:
sudo nmcli connection up "Wired-802.1X-Vault"
7.2b Activate WiFi Connection
If you configured WiFi, reconnect to pick up new certificate:
# Disconnect and reconnect
sudo nmcli connection down "Domus-Secure-802.1X"
sudo nmcli connection up "Domus-Secure-802.1X"
Or if you created a new WiFi connection:
sudo nmcli connection up "WiFi-802.1X-Vault"
7.3 Rollback (If Failed)
If authentication fails, revert to the old connection:
sudo nmcli connection delete "Wired-802.1X-Vault"
sudo nmcli connection up "Wired-802.1X"
7.4 Verify on Switch
netapi ios exec "show access-session interface <interface> details"
User-Name: <hostname>.inside.domusdigitalis.dev Status: Authorized Method: dot1x Authc Success
7.5 Verify in ISE (Both Wired and WiFi)
netapi ise dc query "
SELECT
USERNAME,
AUTHENTICATION_PROTOCOL,
POLICY_SET_NAME,
AUTHORIZATION_RULE,
NAS_IP_ADDRESS,
PASSED,
TIMESTAMP_TIMEZONE
FROM RADIUS_AUTHENTICATIONS
WHERE USERNAME LIKE '%<hostname>%'
AND AUTHENTICATION_PROTOCOL = 'EAP-TLS'
AND TIMESTAMP_TIMEZONE > SYSDATE - 1
ORDER BY TIMESTAMP_TIMEZONE DESC
FETCH FIRST 10 ROWS ONLY
"
POLICY_SET_NAME │ NAS_IP_ADDRESS │ PASSED ────────���───────────┼────────────────┼──────── Domus-Wired 802.1X │ 10.50.1.10 │ Pass (switch) Domus-Secure 802.1X │ 10.50.1.x │ Pass (WLC)
| Different POLICY_SET_NAME indicates wired vs WiFi authentication. |
Phase 8: Comprehensive Validation
Run these commands to fully validate the migration.
8.1 Verify Certificate Issuer
Confirm the certificate is issued by Vault PKI (DOMUS-ISSUING-CA), not the old AD CS:
openssl x509 -in /etc/ssl/certs/<hostname>-eaptls.pem -issuer -subject -noout
issuer=CN=DOMUS-ISSUING-CA subject=CN=<hostname>.inside.domusdigitalis.dev
If issuer shows HOME-ISSUING-CA or HOME-ROOT-CA, you’re still using the old AD CS certificate.
|
8.2 Verify Active Sessions in ISE
Check that both wired and WiFi sessions are active:
netapi ise mnt sessions
MAC │ IP │ Username │ Type │ NAD ─────────────┼──────────────┼────────────────┼───────┼──────────── 70:15:FB:... │ 10.50.10.103 │ modestus-r... │ WiFi │ 10.50.1.40 98:BB:1E:... │ 10.50.10.130 │ modestus-r... │ Wired │ 10.50.1.10
8.3 Query DataConnect for Full Auth Details
Comprehensive query showing all authentication details:
netapi ise dc query "
SELECT
USERNAME,
AUTHENTICATION_PROTOCOL,
POLICY_SET_NAME,
AUTHORIZATION_RULE,
AUTHORIZATION_PROFILES,
IDENTITY_GROUP,
NAS_IP_ADDRESS,
CALLING_STATION_ID,
FRAMED_IP_ADDRESS,
PASSED,
TO_CHAR(TIMESTAMP_TIMEZONE, 'YYYY-MM-DD HH24:MI:SS') as TIMESTAMP
FROM RADIUS_AUTHENTICATIONS
WHERE USERNAME LIKE '%<hostname>%'
AND AUTHENTICATION_PROTOCOL = 'EAP-TLS'
AND TIMESTAMP_TIMEZONE > SYSDATE - 1
ORDER BY TIMESTAMP_TIMEZONE DESC
FETCH FIRST 10 ROWS ONLY
"
8.4 Verify Both Connection Types
Quick query to confirm both wired and WiFi are passing:
netapi ise dc query "
SELECT
POLICY_SET_NAME,
NAS_IP_ADDRESS,
PASSED,
TO_CHAR(TIMESTAMP_TIMEZONE, 'HH24:MI:SS') as TIME
FROM RADIUS_AUTHENTICATIONS
WHERE USERNAME LIKE '%<hostname>%'
AND AUTHENTICATION_PROTOCOL = 'EAP-TLS'
AND TIMESTAMP_TIMEZONE > SYSDATE - 1/24
ORDER BY TIMESTAMP_TIMEZONE DESC
FETCH FIRST 5 ROWS ONLY
"
POLICY_SET_NAME │ NAS_IP_ADDRESS │ PASSED │ TIME ─────────────────────┼────────────────┼────────┼────────── Domus-Secure 802.1X │ 10.50.1.40 │ Pass │ 15:15:24 (WiFi) Domus-Wired 802.1X │ 10.50.1.10 │ Pass │ 14:45:35 (Wired)
8.5 Verify EAP-TLS Handshake in Logs
Check that the certificate chain shows Vault PKI CAs:
journalctl -u wpa_supplicant --since "1 hour ago" | grep -E "PEER-CERT|EAP-SUCCESS"
CTRL-EVENT-EAP-PEER-CERT depth=2 subject='/C=US/O=Domus Digitalis/OU=Enterprise PKI/CN=DOMUS-ROOT-CA' CTRL-EVENT-EAP-PEER-CERT depth=1 subject='/CN=DOMUS-ISSUING-CA' CTRL-EVENT-EAP-SUCCESS EAP authentication completed successfully
Phase 9: Temp File Cleanup
Phase 10: Legacy Connection Cleanup (When Ready)
|
Recommendation: Keep legacy connections as fallback for 1-2 weeks after migration. Only remove them after confirming the Vault certificate works reliably. |
10.1 List All Connections
nmcli connection show | grep -E "ethernet|wifi|802"
Wired-802.1X-Vault 3f9fefb8-... ethernet enp130s0 (ACTIVE - Vault cert) Domus-Secure-802.1X 8dbd3d7d-... wifi wlan0 (ACTIVE - Vault cert) Wired-802.1X 6730f285-... ethernet -- (INACTIVE - old AD CS)
10.2 Verify Old Connection Is Not Active
Before removing, confirm the old connection is not in use:
nmcli device status | grep -E "enp|wlan"
enp130s0 ethernet connected Wired-802.1X-Vault wlan0 wifi connected Domus-Secure-802.1X
10.3 Remove Old Wired Connection
Once confident, remove the legacy connection:
sudo nmcli connection delete "Wired-802.1X"
Connection 'Wired-802.1X' (6730f285-c9f4-4a7d-95f3-93287dbddf35) successfully deleted.
Troubleshooting
Authentication Fails
-
Check ISE trusts DOMUS-ROOT-CA:
netapi ise api-call openapi GET '/api/v1/certs/trusted-certificate?size=100' | jq -r '.response[].friendlyName' | grep -i domus -
Check certificate chain:
openssl verify -CAfile /etc/ssl/certs/DOMUS-ROOT-CA.pem /etc/ssl/certs/<hostname>-eaptls.pem -
Check ISE live logs for failure reason