PKI ArchitectureEN
PKI Architecture: 3-Tier vs 4-Tier Hierarchy
Overview
The varwof PKI supports two hierarchy modes:
| Mode | Config | Tiers | Use Case |
|---|---|---|---|
| Simple | --hierarchy simple |
3-tier | Small-medium organizations |
| Enterprise | --hierarchy enterprise |
4-tier | Large enterprises, compliance-heavy |
Three-Tier Architecture (Simple)
┌──────────────┐
│ Root CA │ L1 — Trust Anchor
│ (offline) │ ECDSA P-384, 20 years
└──────┬───────┘
│
┌────────────────┼────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ TLS CA │ │ People CA │ │ CodeSign │ L2 — Issuing CAs
│ (5 years) │ │ (5 years) │ │ CA (RSA) │ ECDSA P-256
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Servers │ │ Users │ │ Software │ L3 — End Entities
│ Clients │ │ AIC Agents│ │ Code │
└───────────┘ └───────────┘ └───────────┘
Characteristics
- Root CA signs all sub-CAs directly
- Sub-CAs have
MaxPathLen=0(cannot issue further CAs) - Simpler chain verification
- Faster deployment
- Root CA can be kept offline after sub-CAs are issued
Chain Verification
# Simple chain
openssl verify -CAfile root/ca.pem -untrusted tls/ca.pem server.pem
# Expected output
server.pem: OK
init-full Command
pki init-full \
--root-name "MyCorp Root CA" \
--hierarchy simple \
--org "MyCorp" \
--country US \
--base-dir /opt/pki
Creates:
/opt/pki/
├── root/ Root CA
├── management/ Management CA
├── tls/ TLS CA
├── people/ People CA
├── codesign/ CodeSign CA
├── tsa/ TSA CA
├── hr/ HR CA
├── vpn/ VPN CA
├── acme/ ACME CA
├── server.pem Server TLS cert
└── pki.json Config
Four-Tier Architecture (Enterprise)
┌──────────────┐
│ Root CA │ L1 — Trust Anchor
│ (offline) │ ECDSA P-384, 20 years
└──────┬───────┘
│
┌──────▼───────┐
│ Policy CA │ L2 — Policy Buffer
│ (10 years) │ ECDSA P-384
└──────┬───────┘
│
┌────────────────┼────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ TLS CA │ │ People CA │ │ CodeSign │ L3 — Issuing CAs
│ (5 years) │ │ (5 years) │ │ CA (RSA) │ ECDSA P-256
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Servers │ │ Users │ │ Software │ L4 — End Entities
│ Clients │ │ AIC Agents│ │ Code │
└───────────┘ └───────────┘ └───────────┘
Characteristics
- Policy CA acts as a buffer between Root and Issuing CAs
- Root CA remains fully offline (never touches online infrastructure)
- Policy CA can adjust sub-CA policies without touching Root
- Supports Policy Mappings, Policy Constraints, Inhibit anyPolicy
- Required for compliance frameworks (SOC 2, PCI DSS, NIST)
Why Policy CA?
"The Policy CA is the only difference between four-tier and three-tier — it acts as a policy buffer: once the Root CA is kept offline, the Policy CA can adjust sub-CA policies without touching the Root."
Benefits:
- Offline Root: Root CA private key never leaves the air-gapped machine
- Policy Flexibility: Policy CA can be rotated/renewed without Root CA involvement
- Compliance: Separation of duties between trust anchor and policy enforcement
- Audit Trail: Policy changes are logged at the Policy CA level
Chain Verification
# Four-tier chain requires Policy CA as intermediate
openssl verify \
-CAfile root/ca.pem \
-untrusted policy/ca.pem \
-untrusted tls/ca.pem \
server.pem
# Expected output
server.pem: OK
init-full Command
pki init-full \
--root-name "MyCorp Root CA" \
--hierarchy enterprise \
--org "MyCorp" \
--country US \
--base-dir /opt/pki
Creates:
/opt/pki/
├── root/ Root CA
├── policy/ Policy CA (NEW)
├── management/ Management CA
├── tls/ TLS CA
├── people/ People CA
├── codesign/ CodeSign CA
├── tsa/ TSA CA
├── hr/ HR CA
├── vpn/ VPN CA
├── acme/ ACME CA
├── server.pem Server TLS cert
└── pki.json Config
Comparison
| Aspect | 3-Tier (Simple) | 4-Tier (Enterprise) |
|---|---|---|
| Depth | Root → Sub-CA → End Entity | Root → Policy CA → Sub-CA → End Entity |
| Root offline | After sub-CA creation | Fully offline always |
| Policy flexibility | Limited | High (Policy CA buffer) |
| Chain verification | 2 intermediates max | 3 intermediates max |
| Compliance | Basic | SOC 2, PCI DSS, NIST |
| Complexity | Low | Medium |
| Deployment | --hierarchy simple |
--hierarchy enterprise |
Sub-CA Definitions
Both modes create 8 business sub-CAs:
| CA | Purpose | Key Type | Validity |
|---|---|---|---|
| Management | Admin/operator certs | ECDSA P-256 | 5 years |
| TLS | Server/client TLS | ECDSA P-256 | 5 years |
| People | User/employee certs | ECDSA P-256 | 5 years |
| CodeSign | Code signing | RSA-4096 | 5 years |
| TSA | Timestamp signing | RSA-4096 | 5 years |
| HR | HR department | ECDSA P-256 | 5 years |
| VPN | VPN client | ECDSA P-256 | 5 years |
| ACME | Auto-enrollment | ECDSA P-256 | 5 years |
All sub-CAs have MaxPathLen=0 (cannot issue further CAs).
Name Constraints
Sub-CAs can be restricted to specific domains:
pki ca init \
--name "Web CA" \
--profile sub-ca \
--parent "Root CA" \
--permitted-dns "*.example.com" \
--excluded-dns "*.internal.example.com" \
--permitted-emails "@example.com" \
--out-cert web/ca.pem \
--out-key web/ca.key
Supported Constraint Types
| Type | Description |
|---|---|
| DNS | Permitted/excluded domains |
| Permitted/excluded email addresses | |
| URI | Permitted/excluded URI domains |
| IP | Permitted/excluded IP CIDR ranges |
Enforcement
Name constraints are enforced during chain validation (checkNameConstraints):
- Every DNS name in the child must be within a permitted subtree
- Excluded subtrees always win over permitted
- DNS matching:
example.comalso matchessub.example.com
Policy Constraints
RFC 5280 extensions for policy enforcement:
Policy Mappings (OID 2.5.29.33)
Maps issuerDomainPolicy to subjectDomainPolicy:
{
"defaults": {
"policy_mappings": ["2.16.840.1.101.3.2.1.48.1:2.16.840.1.101.3.2.1.48.2"]
}
}
Policy Constraints (OID 2.5.29.36)
{
"defaults": {
"require_explicit_policy": 0,
"inhibit_policy_mapping": 0
}
}
require_explicit_policy: After N intermediates, explicit policy requiredinhibit_policy_mapping: After N intermediates, no further mappings
Inhibit anyPolicy (OID 2.5.29.54)
{
"defaults": {
"inhibit_any_policy": 0
}
}
After N intermediates, the anyPolicy OID is suppressed.
Offline Root CA
Setup
- Initialize root CA on air-gapped machine
- Copy only the root certificate to online server
- Use
pki ca offline-signto sign sub-CA CSRs - Copy signed sub-CA certificates back
Offline Signing
# On offline machine
pki ca offline-sign \
--ca-cert root/ca.pem \
--ca-key root/ca.key \
--csr sub.csr \
--out sub-ca.pem \
--validity 3650d
Import Root Key Security
Root CA private keys are explicitly rejected from import:
ErrRootCAImportreturned for any root key import attempt- System checks if public key matches known root CAs in DB
- Prevents attackers from wrapping root keys in non-self-signed certificates
Cross-Certificates
Cross-certificates allow trust between independent PKI domains:
# Issue cross-certificate
pki cross-cert issue \
--issuer "External Root" \
--subject "My Root" \
--validity 3650d
# List cross-certificates
pki cross-cert list
# Revoke
pki cross-cert revoke \
--issuer "External Root" \
--serial AB12CD34 \
--reason keyCompromise
Cross-Certificate Properties
- Target's Subject + Public Key
- Issuer's signature
MaxPathLen=0(restricts further delegation)- Optional name constraints
Trust Bridge Federation
Higher-level abstraction over cross-certificates:
# Establish trust bridge
pki trust-bridge issue "My Root" "Partner Root" 3650
# List trust bridges
pki trust-bridge list
# Federate trust anchors from remote
pki trust-bridge federate https://partner.example.com/ca-bundle.pem
Trust Pool Construction
Federated trust pool built from:
- Local CA certificates
- Valid cross-certificate records
- Trusted trust anchors from database
Trust Anchor Import
# Import trust bundle
pki trust import --cert partner-ca.pem --name "Partner CA"
# Fetch from URL (TLS required for non-loopback)
pki trust fetch https://partner.example.com/ca.pem
Security:
- TLS required for non-loopback hosts
- 32 MiB size limit
- Must contain at least one valid root CA
- Deduplication by SHA-256 hash
Certificate Chain Building
Chain Builder (BuildChain)
- Start with leaf certificate
- Find issuer candidates by matching
RawIssuer - Prefer trust anchors when available
- Cycle detection via
seenmap - Depth bound (default 16)
Path Verification (VerifyPath)
Pass 1 — Structural checks (leaf to root):
- Validity window check for every certificate
- Signature verification
- Issuer must be CA (
IsCAflag) - Issuer must have
keyCertSignKeyUsage - Name constraint validation
Pass 2 — Path length constraints:
- For each CA from root down, intermediates must not exceed
MaxPathLen
Pass 3 — Trust anchor check:
- Terminal certificate must match a known trust anchor
Pass 4 — Policy processing (optional):
- RFC 5280 Section 6.1 algorithm
- Policy Mappings, Policy Constraints, Inhibit anyPolicy
CLI Verification
# Verify certificate chain
pki verify-path cert.pem --db /var/lib/pki/pki.db
# With policy check
pki verify-path cert.pem --db /var/lib/pki/pki.db --policy-check
# JSON output
pki verify-path cert.pem --db /var/lib/pki/pki.db --json
Key Rotation
Atomic CA key rotation with dual-signing:
# Check rotation status
curl -sk --cert superadmin.pem --key superadmin.key \
https://localhost:4433/api/v1/ca/tls/rotation
# Perform rotation
curl -sk --cert superadmin.pem --key superadmin.key \
-X POST https://localhost:4433/api/v1/ca/tls/rotate \
-H 'Content-Type: application/json' \
-d '{"cert": "/path/new-ca.pem", "key": "/path/new-ca.key"}'
Rotation Process
- New key takes effect atomically (
atomic.Pointer) - Old key retained as "legacy" for dual-signing
- Transition window for verifying previously issued certs
- Server checks expiry every 12 hours, warns at 7 days
Cold Backup
Encrypted backup of CA keys:
# Create backup
pki ca cold-backup create \
--ca-name "Root CA" \
--ca-cert root/ca.pem \
--ca-key root/ca.key \
--password "backup-secret" \
--out backup.json
# Verify backup
pki ca cold-backup verify \
--backup backup.json \
--password "backup-secret"