BYOD Certificate Management with Vault and dsec

Complete operational runbook for issuing, tracking, and managing BYOD device certificates using HashiCorp Vault PKI with dsec-integrated password management.

Overview

This runbook provides enterprise-grade procedures for BYOD certificate management in the Domus home enterprise environment, integrating:

  • HashiCorp Vault PKI - Certificate issuance via domus-byod role (90-day TTL)

  • dsec Secrets Management - Secure PKCS#12 password storage

  • Automated Tooling - issue-byod-cert script with enterprise security controls

  • ISE Integration - 802.1X EAP-TLS authentication to Domus-Secure SSID

Architecture

BYOD Certificate Workflow
┌──────────────┐     ┌─────────────────┐     ┌──────────────┐
│  certmgr-01  │────▶│  Vault PKI      │────▶│  PKCS#12     │
│  (issue)     │     │  {vault-pki-int}/       │     │  Bundle      │
└──────────────┘     │  {vault-byod-role}     │     └──────────────┘
                     └─────────────────┘            │
                                                     │
       ┌─────────────────────────────────────────────┘
       │
       ▼
┌──────────────┐     ┌─────────────────┐     ┌──────────────┐
│  Workstation │────▶│  dsec           │     │  Device      │
│  (password)  │     │  {dsec-vault}/{dsec-byod-path}/*/   │     │  (import)    │
└──────────────┘     └─────────────────┘     └──────────────┘

Security Model

Password Storage Strategy

Enterprise Security Principle: PKCS#12 passwords are stored in dsec, NOT on filesystem.

Component Storage Location Access Control

Certificate

certmgr-01.inside.domusdigitalis.dev: /home/ansible/byod-certs/<device>/*.p12

File permissions (600)

Private Key

Embedded in PKCS#12 (encrypted)

PKCS#12 password

PKCS#12 Password

dsec: d000/byod/<device-owner>/p12-password

Age encryption + DSEC_SECURITY_MODE

Metadata

certmgr-01.inside.domusdigitalis.dev: /home/ansible/byod-certs/.metadata/certificates.json

File permissions (600), NO passwords

CA Chain

Embedded in PKCS#12

Public (trusted)

Why dsec for Password Storage?

  1. Centralized secrets management - Consistent with ISE credentials, Vault tokens

  2. Encrypted at rest - Age encryption with master key

  3. Access control - DSEC_SECURITY_MODE enforcement

  4. Audit trail - Track password access

  5. Backup/DR - Part of enterprise secrets backup strategy

  6. No plaintext on disk - Passwords never stored in filesystem

Prerequisites

Required Access
  • SSH access to certmgr-01.inside.domusdigitalis.dev

  • Vault token with pki_int/issue/domus-byod permissions

  • dsec configured on workstation (for password storage/retrieval)

  • netapi configured (for ISE verification)

Required Tools on certmgr-01.inside.domusdigitalis.dev
  • vault CLI (installed)

  • issue-byod-cert script (/home/ansible/bin/issue-byod-cert)

  • openssl, jq, shred (system tools)

Required Tools on Workstation
  • dsec CLI (configured with d000 vault)

  • netapi CLI (ISE API access)

  • scp (file transfer)

Certificate Issuance Workflow

Step 1: SSH to certmgr-01.inside.domusdigitalis.dev

# From workstation
ssh certmgr-01.inside.domusdigitalis.dev

Step 2: Set Vault Environment

dsource is NOT available on certmgr-01.inside.domusdigitalis.dev - it’s a workstation tool. You must get the Vault token from your workstation BEFORE SSHing to certmgr-01.inside.domusdigitalis.dev.

# On your WORKSTATION first:
DSEC_SECURITY_MODE=permissive dsec show {dsec-vault} {dsec-vault-path}
# Copy the vault_token value
# Now on certmgr-01.inside.domusdigitalis.dev:
# Set Vault connection
export VAULT_ADDR='http://127.0.0.1:8200'

# Paste the token from your workstation
export VAULT_TOKEN='<paste token here>'

# Verify Vault status
vault status
# Expected: Sealed: false

Step 3: Issue Certificate

# Syntax: issue-byod-cert <device-model> <owner-name> [platform]
# Platform: android or ios (default: android)

# Example for Samsung Z Fold 7
issue-byod-cert <device-model> <owner-name> android

# Example for iPhone
issue-byod-cert <device-model> <owner-name> ios
Expected Output
╔════════════════════════════════════════════════════════════════╗
║      BYOD Certificate Issuance - Home Enterprise Edition      ║
╚════════════════════════════════════════════════════════════════╝

→ Device: <device-model>
→ Owner: <owner-name>
→ Platform: android
→ Common Name: <device-model>-<owner-name>.byod.inside.domusdigitalis.dev

[1/7] Issuing certificate from Vault PKI...
✓ Certificate issued successfully
  Serial: 6f:3a:d1:8c:2e:95:4b:7a:1d:f2:8e:6c:9b:4a:5e:3f:2c:7d:9e:1a
  Expires: 2026-05-29 14:23:45 PDT

[2/7] Extracting certificate components...
✓ Components extracted

[3/7] Generating secure PKCS#12 password...
✓ Password generated (see below for storage)

[4/7] Creating PKCS#12 bundle...
✓ PKCS#12 created: zfold7-evanusmodestus.p12

[5/7] Securely deleting intermediate files...
✓ Cleanup complete

[6/7] Saving certificate metadata...
✓ Metadata saved (password NOT stored on filesystem)

[7/7] Enterprise password management...

╔════════════════════════════════════════════════════════════════╗
║                    Certificate Issued                         ║
╚════════════════════════════════════════════════════════════════╝

Device:    <device-model>-<owner-name>
File:      /home/ansible/byod-certs/<device-model>/<device-model>-<owner-name>.p12
Expires:   2026-05-29 14:23:45 PDT

╔════════════════════════════════════════════════════════════════╗
║                  PKCS#12 IMPORT PASSWORD                       ║
╠════════════════════════════════════════════════════════════════╣
║  XfR7mK2pL9nQ3vB8wZ4c                                          ║
╚════════════════════════════════════════════════════════════════╝

▸ Store password in dsec (run from workstation):

echo "<p12-password>" | dsec set d000 byod/<device-model>-<owner-name>/p12-password

▸ Retrieve password later:

dsec show d000 byod/<device-model>-<owner-name>/p12-password

▸ Next Steps:
  1. Store password in dsec (command above)
  2. Transfer <device-model>-<owner-name>.p12 to your workstation:
     scp certmgr-01.inside.domusdigitalis.dev:/home/ansible/byod-certs/<device-model>/<device-model>-<owner-name>.p12 ~/Downloads/
  3. Transfer to device and import
  4. Configure WiFi: Domus-Secure, EAP-TLS, select certificate

✓ Certificate issuance complete!

Step 4: Store Password in dsec

CRITICAL: The password is displayed but NOT stored on certmgr-01.inside.domusdigitalis.dev.

# Exit from certmgr-01.inside.domusdigitalis.dev
exit

# Back on your workstation, store the password in dsec
echo "<p12-password>" | dsec set d000 byod/<device-model>-<owner-name>/p12-password

# Verify storage
dsec show d000 byod/<device-model>-<owner-name>/p12-password
# Should output: <p12-password>

Copy-paste the exact command from the script output - it includes the device name and password automatically.

Step 5: Transfer PKCS#12 to Workstation

# From workstation
scp certmgr-01.inside.domusdigitalis.dev:/home/ansible/byod-certs/<device-model>/<device-model>-<owner-name>.p12 ~/Downloads/

Step 6: Transfer to Device and Import

Android

  1. Transfer .p12 via adb push or email

  2. SettingsSecurityInstall from storage

  3. Select the .p12 file, enter password from dsec

  4. Name the certificate (e.g., "Domus-BYOD")

  5. Connect to Domus-Secure, select EAP-TLS, choose certificate

iOS/iPadOS (Requires mobileconfig Profile)

iOS does not expose EAP-TLS in WiFi settings. Create a .mobileconfig profile:

# Get base64 of the .p12
P12_B64=$(ssh certmgr-01.inside.domusdigitalis.dev "base64 -w0 /home/ansible/byod-certs/ipad/ipad-<owner-name>.p12")

# Create profile (unquoted ENDPROFILE so variable expands)
cat > ~/Downloads/domus-byod-ios.mobileconfig << ENDPROFILE
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PayloadContent</key>
    <array>
        <dict>
            <key>Password</key>
            <string><p12-password></string>
            <key>PayloadCertificateFileName</key>
            <string>ipad-<owner-name>.p12</string>
            <key>PayloadContent</key>
            <data>\$<base64-encoded-p12></data>
            <key>PayloadIdentifier</key>
            <string>com.domusdigitalis.cert</string>
            <key>PayloadType</key>
            <string>com.apple.security.pkcs12</string>
            <key>PayloadUUID</key>
            <string>11111111-1111-1111-1111-111111111111</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
        </dict>
        <dict>
            <key>AutoJoin</key>
            <true/>
            <key>EAPClientConfiguration</key>
            <dict>
                <key>AcceptEAPTypes</key>
                <array>
                    <integer>13</integer>
                </array>
                <key>PayloadCertificateAnchorUUID</key>
                <array>
                    <string>11111111-1111-1111-1111-111111111111</string>
                </array>
            </dict>
            <key>EncryptionType</key>
            <string>WPA2</string>
            <key>SSID_STR</key>
            <string>Domus-Secure</string>
            <key>PayloadIdentifier</key>
            <string>com.domusdigitalis.wifi</string>
            <key>PayloadType</key>
            <string>com.apple.wifi.managed</string>
            <key>PayloadUUID</key>
            <string>22222222-2222-2222-2222-222222222222</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
        </dict>
    </array>
    <key>PayloadDisplayName</key>
    <string>Domus BYOD</string>
    <key>PayloadIdentifier</key>
    <string>com.domusdigitalis.byod</string>
    <key>PayloadType</key>
    <string>Configuration</string>
    <key>PayloadUUID</key>
    <string>33333333-3333-3333-3333-333333333333</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
</dict>
</plist>
ENDPROFILE

# Verify cert data embedded (~8000+ chars)
grep -o '<data>.*</data>' ~/Downloads/domus-byod-ios.mobileconfig | wc -c
Install on iOS
  1. Email domus-byod-ios.mobileconfig to yourself

  2. Tap attachment on iOS device

  3. AjustesPerfil descargadoInstalar

  4. Enter device passcode

  5. Device auto-connects to Domus-Secure

Privacy Warning: iOS shows "Advertencia de privacidad" when using real MAC. This is normal for enterprise WiFi. Random MAC works with cert-auth but don’t change it mid-session.

Password Management

Retrieve Password

# From workstation
dsec show d000 byod/<device>-<owner>/p12-password

# Example
dsec show d000 byod/<device-model>-<owner-name>/p12-password

List All BYOD Passwords

# List all stored BYOD passwords
dsec list d000 byod/

# Expected output:
# byod/<device-model>-<owner-name>/p12-password
# byod/iphone16-<owner-name>/p12-password

Delete Password After Import

After the device successfully imports the certificate, the PKCS#12 password is no longer needed. Consider deleting it from dsec for security:

# After confirming device can authenticate to WiFi
dsec delete d000 byod/<device-model>-<owner-name>/p12-password

Trade-off: If user needs to re-import (e.g., factory reset), you’ll need to re-export the certificate with a new password.

Certificate Tracking

View Issued Certificates

# On certmgr-01.inside.domusdigitalis.dev
cat /home/ansible/byod-certs/.metadata/certificates.json | jq -r '.[] | "\(.device)-\(.owner) | \(.platform) | \(.expiration_date) | \(.status)"' | column -t -s '|'
Example Output
zfold7-evanusmodestus     android  2026-05-29  active
iphone16-evanusmodestus   ios      2026-06-15  active

Check Expiring Certificates

# Find certificates expiring in next 30 days
cat /home/ansible/byod-certs/.metadata/certificates.json | jq -r --argjson now "$(date +%s)" --argjson days 30 '
  .[] | select((.expiration_timestamp) <= ($now + ($days * 86400))) |
  "\(.device)-\(.owner) expires in \(((.expiration_timestamp - $now) / 86400) | floor) days"
'

Certificate Renewal

Use Case: Certificate approaching 90-day expiration.

# Issue new certificate (same process as initial issuance)
ssh certmgr-01.inside.domusdigitalis.dev
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='<your-vault-token>'

# Issue replacement certificate
issue-byod-cert <device-model> <owner-name> android

# Store new password in dsec (overwrites old password)
echo "<p12-password>" | dsec set d000 byod/<device-model>-<owner-name>/p12-password

# User imports new certificate
# Old certificate automatically stops working after expiration

Do NOT revoke the old certificate until user confirms new certificate is working.

Certificate Revocation

Use Case: Device lost/stolen, employee termination, security incident.

Step 1: Identify Certificate Serial Number

# On certmgr-01.inside.domusdigitalis.dev
cat /home/ansible/byod-certs/.metadata/certificates.json | jq -r '.[] | select(.device + "-" + .owner == "<device-model>-<owner-name>") | .serial_number'

# Example output: <serial-number>

Step 2: Revoke in Vault

# On certmgr-01.inside.domusdigitalis.dev
export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN='<your-vault-token>'

# Revoke certificate
vault write pki_int/revoke serial_number="<serial-number>"

# Verify revocation
vault read pki_int/cert/<serial-number>
# Should show: revocation_time: <timestamp>

Step 3: Block Device in ISE (Immediate Effect)

CRL/OCSP Not Yet Configured

ISE does not currently check Vault CRL. Revoked certificates will still authenticate until ISE is configured to check revocation status.

For immediate blocking, use ISE endpoint blocking.

# From workstation, get device MAC address
netapi ise mnt sessions | grep -i "<device-model>-<owner-name>"

# Block endpoint
netapi ise block-endpoint <mac-address> --reason "Certificate revoked - device lost"

Step 4: Delete Password from dsec

# From workstation
dsec delete d000 byod/<device-model>-<owner-name>/p12-password

Step 5: Update Metadata

# On certmgr-01.inside.domusdigitalis.dev
cat /home/ansible/byod-certs/.metadata/certificates.json | jq '
  (.[] | select(.serial_number == "<serial-number>")) |= . + {status: "revoked"}
' > /tmp/updated.json

mv /tmp/updated.json /home/ansible/byod-certs/.metadata/certificates.json

Troubleshooting

Password Not Found in dsec

Symptoms: dsec show returns empty or error.

Causes: 1. Password was never stored (forgot Step 4 during issuance) 2. Password was deleted 3. Wrong dsec path

Resolution:

# Check if password exists
dsec list d000 byod/ | grep -i "<device>"

# If not found, re-export certificate with new password:
# (Requires original cert data on certmgr-01.inside.domusdigitalis.dev)
ssh certmgr-01.inside.domusdigitalis.dev
cd /home/ansible/byod-certs/<device>

# Check if original .p12 still exists
ls -lh *.p12

# If exists, user can re-import with original password
# If not, must issue new certificate

Cannot Retrieve Vault Token

Symptoms: vault commands fail with "permission denied".

Resolution:

# From workstation, get Vault token from dsec
DSEC_SECURITY_MODE=permissive dsec show d000 dev/vault

# Look for vault_token or similar field
# Copy token and export on certmgr-01.inside.domusdigitalis.dev
export VAULT_TOKEN='<your-vault-token>'

PKCS#12 File Not Found

Symptoms: scp fails to transfer .p12 file from certmgr-01.inside.domusdigitalis.dev.

Resolution:

# SSH to certmgr-01.inside.domusdigitalis.dev and verify file location
ssh certmgr-01.inside.domusdigitalis.dev
find /home/ansible/byod-certs -name "*.p12" -ls

# Files are in /home/ansible/byod-certs/<device-model>/<device>-<owner>.p12
# Example: /home/ansible/byod-certs/<device-model>/<device-model>-<owner-name>.p12

# Use correct path in scp
scp certmgr-01.inside.domusdigitalis.dev:/home/ansible/byod-certs/<device-model>/<device-model>-<owner-name>.p12 ~/Downloads/

Backup and Disaster Recovery

What to Backup

Component Location Backup Method

Certificates metadata

certmgr-01.inside.domusdigitalis.dev: /home/ansible/byod-certs/.metadata/certificates.json

Daily rsync to backup server

PKCS#12 passwords

dsec: d000/byod/*

Included in dsec vault backups

Issued PKCS#12 files

certmgr-01.inside.domusdigitalis.dev: /home/ansible/byod-certs//\.p12

Optional (can be re-issued)

Vault PKI data

certmgr-01.inside.domusdigitalis.dev: /opt/vault/data

Daily encrypted backup (see Runbook: Backup All Infrastructure)

Recovery Scenarios

Scenario 1: certmgr-01.inside.domusdigitalis.dev disk failure

# Restore Vault data from backup
# Unseal Vault with Shamir keys
# Metadata is lost, but can be rebuilt:

# For each device still using certificates:
# 1. Get serial number from ISE sessions
# 2. Query Vault for certificate details
# 3. Rebuild metadata file

Scenario 2: dsec vault corruption

# Restore dsec vault from backup
# Passwords are recovered
# PKCS#12 files on certmgr-01 are unaffected

Scenario 3: Lost all PKCS#12 passwords

# If dsec backup is lost and passwords are gone:
# 1. Devices currently connected continue to work (cert in device keystore)
# 2. For new imports: Must issue NEW certificates
# 3. Cannot re-import existing PKCS#12 files without password

Security Considerations

Password Lifetime

One-time use: PKCS#12 passwords are only needed during certificate import. After successful import, the certificate is stored in the device’s secure hardware keystore (Android Keystore, iOS Secure Enclave).

Recommendation: Delete passwords from dsec 24 hours after device confirms successful authentication to WiFi.

Access Control

Who should have access: * Vault token: Network administrators only * dsec d000/byod/ path: Certificate administrators, helpdesk (read-only) * certmgr-01.inside.domusdigitalis.dev SSH: Certificate administrators only

Audit Logging

# Track certificate issuance
grep "Certificate issued" /var/log/auth.log  # SSH session logs

# Track dsec password access
# (Requires dsec audit logging - future enhancement)

Appendix: Quick Reference

Certificate Issuance (Three Commands)
# 1. On certmgr-01.inside.domusdigitalis.dev: Issue certificate
ssh certmgr-01.inside.domusdigitalis.dev
issue-byod-cert <device-model> <owner-name> android
# Copy the password from output

# 2. On workstation: Store password in dsec
echo "<p12-password>" | dsec set d000 byod/<device-model>-<owner-name>/p12-password

# 3. On workstation: Transfer .p12 file
scp certmgr-01.inside.domusdigitalis.dev:/home/ansible/byod-certs/<device-model>/<device-model>-<owner-name>.p12 ~/Downloads/
Password Retrieval (One Command)
dsec show d000 byod/<device>-<owner>/p12-password
Certificate Revocation (Three Commands)
# 1. Revoke in Vault
vault write pki_int/revoke serial_number="<serial-number>"

# 2. Block in ISE
netapi ise block-endpoint <mac-address>

# 3. Delete password
dsec delete d000 byod/<device>-<owner>/p12-password