Enterprise PKI Strategy
Overview
This document defines the enterprise Public Key Infrastructure (PKI) strategy, implementing a two-tier architecture with HashiCorp Vault as the primary internal CA.
|
Core Principle: Internal must stay internal. Public-facing services use Let’s Encrypt; all internal services use Vault PKI. |
|
AD CS Deprecation: HOME-ROOT-CA on home-dc01.inside.domusdigitalis.dev is deprecated and will be decommissioned by 2026-07. All new certificates must be issued from Vault. The DC retains AD services (authentication, DNS, LDAP) but no CA role. |
Architecture
| Tier | Authority | Domain | Use Case |
|---|---|---|---|
Tier 1: Public |
Let’s Encrypt |
|
Guest portals, public APIs, external-facing services |
Tier 2: Internal |
HashiCorp Vault (DOMUS-ROOT-CA) |
|
ISE, switches, APs, NAS, workstations, BYOD, pxGrid, automation |
Certificate Hierarchy
DOMUS-ROOT-CA (Root CA - RSA 4096, 20 years)
└── DOMUS-ISSUING-CA (Issuing CA - RSA 4096, 5 years)
├── Server Certificates (ISE, Keycloak, NAS)
├── Workstation Certificates (EAP-TLS 802.1X)
├── BYOD Certificates (90-day mobile devices)
├── pxGrid Certificates (netapi-pxgrid)
└── Automation Certificates (24-72h short-lived)
Why This Architecture?
-
Security: Internal hostnames never exposed to external CA validation
-
Cost: No Microsoft licensing fees for CA services
-
Skill Investment: HashiCorp Vault is industry-standard for secrets management
-
Automation: Vault enables dynamic short-lived certificates via API
-
Simplicity: Single CA hierarchy instead of parallel AD CS and Vault
Tier 1: Public Services (Let’s Encrypt)
Managed Certificates
Certificate: public-portals
Domains:
- guest.domusdigitalis.dev
- sponsor.domusdigitalis.dev
Location: /etc/letsencrypt/live/public-portals/
Renewal: Automatic (certbot timer)
Infrastructure
-
Cert Manager: certmgr-01.inside.domusdigitalis.dev
-
DNS Provider: Cloudflare (DNS-01 challenge)
-
Renewal Timer: systemd
certbot.timer(twice daily)
Renewal Process
# Check certificate status
ssh certmgr-01.inside.domusdigitalis.dev "sudo certbot certificates"
# Manual dry-run test
ssh certmgr-01.inside.domusdigitalis.dev "sudo certbot renew --dry-run"
# View timer status
ssh certmgr-01.inside.domusdigitalis.dev "systemctl status certbot.timer"
Deploy Hook
After renewal, certificates are automatically deployed to:
-
ISE (REST API import)
-
iPSK Manager (SCP + Apache reload)
Deploy hook location: /etc/letsencrypt/renewal-hooks/deploy/deploy-certs.sh
ISE Portal Certificate Import
|
Bug CSCvq85152: The ISE API rejects certificates with apostrophes in the subject (e.g., "O=Let’s Encrypt"). This blocks API import of the E8 intermediate. Server certificates (CN=guest.domusdigitalis.dev) work fine via API. |
One-Time Setup: E8 Intermediate (GUI Required)
The Let’s Encrypt E8 intermediate must be imported via ISE GUI due to the apostrophe bug:
# Download E8 intermediate
curl -o /tmp/e8.pem https://letsencrypt.org/certs/2024/e8.pem
# Verify certificate
openssl x509 -in /tmp/e8.pem -noout -subject -dates
# Subject: CN=E8, O=Let's Encrypt, C=US
# Valid until: 2027
GUI Steps:
-
Administration → System → Certificates → Trusted Certificates
-
Import → Browse → Select
e8.pem -
Friendly Name:
letsencrypt-intermediate-e8 -
Trust for: ✓ Trust for client authentication
-
Submit
Server Certificate Renewal (Automated)
The 90-day server certificate renewal is fully automated via the deploy hook:
# Manual test via netapi CLI
dsource d000 dev/network
netapi ise cert import-from-certmgr \
--cert-dir public-portals \
--domain guest.domusdigitalis.dev \
--name guest-portal-letsencrypt \
--portal
Tier 2: Internal Services (Vault PKI)
Server Details
Server: certmgr-01.inside.domusdigitalis.dev:8200
Root CA: DOMUS-ROOT-CA (RSA 4096, expires 2046)
Issuing CA: DOMUS-ISSUING-CA (RSA 4096, expires 2031)
Storage: File (/opt/vault/data)
Status: Active, Unsealed
Backup: Daily to NAS (vault-backup.timer)
PKI Roles
| Role | Use Case | TTL |
|---|---|---|
|
Server certificates (ISE, Keycloak, NAS) |
1 year |
|
Linux workstation EAP-TLS 802.1X |
1 year |
|
BYOD mobile device certificates |
90 days |
|
pxGrid client authentication |
1 year |
|
Ephemeral automation certificates |
24-72h |
Issuing Certificates
Server Certificate
# Load vault credentials
dsource d000 dev/vault
# Issue server certificate
netapi vault pki-issue nas-01.inside.domusdigitalis.dev \
--role domus-server \
--ttl 8760h \
-o /tmp/nas-cert
ISE Trust Store Setup
|
ISE must trust both the root and issuing CA for certificate validation to work. |
# Export CA certificates from Vault
vault read -field=certificate pki/cert/ca > DOMUS-ROOT-CA.pem
vault read -field=certificate pki_int/cert/ca > DOMUS-ISSUING-CA.pem
# Import to ISE via GUI:
# Administration → System → Certificates → Trusted Certificates
# 1. Import DOMUS-ROOT-CA.pem - Trust for client auth + EAP
# 2. Import DOMUS-ISSUING-CA.pem - Trust for client auth + EAP
netapi vault Commands
| Command | Description |
|---|---|
|
Show Vault status (sealed/unsealed) |
|
Health check endpoint |
|
Auto-unseal using dsec keys |
|
Emergency seal operation |
|
List enabled secrets engines |
|
Backup to NAS |
|
PKI secrets engine status |
|
Issue certificate from Vault PKI |
Deprecated: AD CS (Remove by 2026-07)
|
AD CS on home-dc01.inside.domusdigitalis.dev is deprecated. Do not issue new certificates from this CA. |
Current Status
CA Name: HOME-ROOT-CA
CA Type: Enterprise Root CA
Server: home-dc01.inside.domusdigitalis.dev
Status: DEPRECATED - Remove CA role by 2026-07
DNS Architecture
|
|
domusdigitalis.dev (Cloudflare - Public)
├── guest.domusdigitalis.dev → 216.150.1.1 (Public IP)
├── sponsor.domusdigitalis.dev → 216.150.1.1 (Public IP)
└── inside.domusdigitalis.dev NS → home-dc01.inside.domusdigitalis.dev (Delegated)
├── ise-01.inside.domusdigitalis.dev → 10.50.1.20
├── ise-02.inside.domusdigitalis.dev → 10.50.1.21
├── nas-01.inside.domusdigitalis.dev → 10.50.1.70
└── ... (all internal hosts)
This is why Let’s Encrypt DNS-01 challenges fail for *.inside.domusdigitalis.dev - the challenge TXT records can’t be validated externally.
Troubleshooting
Let’s Encrypt Renewal Fails
# Check logs
ssh certmgr-01.inside.domusdigitalis.dev "sudo tail -50 /var/log/letsencrypt/letsencrypt.log"
# Verify Cloudflare credentials
ssh certmgr-01.inside.domusdigitalis.dev "sudo cat /home/ansible/.secrets/cloudflare.ini"
# Test DNS propagation
dig _acme-challenge.guest.domusdigitalis.dev TXT @8.8.8.8
Vault Sealed After Reboot
# Load credentials and unseal
dsource d000 dev/vault
netapi vault unseal --auto
BYOD Certificate Not Working
-
Verify ISE trusts both Vault CAs (root + issuing)
-
Check Certificate Authentication Profile in ISE
-
Verify PKCS#12 bundle was imported correctly on device
-
Check ISE Live Logs for certificate validation errors
# View ISE trusted certificates
dsource d000 dev/network
netapi ise cert list --trusted
# Check certificate chain
openssl verify -CAfile DOMUS-ROOT-CA.pem -untrusted DOMUS-ISSUING-CA.pem client.pem
Quick Reference
Certificate Locations
| Type | Path |
|---|---|
Let’s Encrypt Public |
|
Vault PKI Output |
Specified via |
Vault CA Certificates |
|
BYOD Bundles |
|
Key Commands
# Check all Let's Encrypt certs
ssh certmgr-01.inside.domusdigitalis.dev "sudo certbot certificates"
# Check Vault status
dsource d000 dev/vault && netapi vault status
# Issue internal cert via Vault
netapi vault pki-issue webserver.inside.domusdigitalis.dev
# Export CA certificates
vault read -field=certificate pki/cert/ca > root-ca.pem
vault read -field=certificate pki_int/cert/ca > issuing-ca.pem
# Issue BYOD certificate
netapi vault pki-issue byod.inside.domusdigitalis.dev --role domus-byod --pkcs12 -o device.p12