13 KiB
13 KiB
Certificate Authority Infrastructure Plan
Overview
Build a secure, self-contained Certificate Authority (CA) infrastructure on an isolated Ubuntu machine (192.168.8.248) using two YubiKeys for hardware-secured key storage, with a web-based Key Vault UI for certificate management.
Architecture
┌─────────────────────────────────────────────────────┐
│ certauth Machine (192.168.8.248) │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ YubiKey #1 │ │ YubiKey #2 │ │
│ │ Root CA Key │ │ Intermediate │ │
│ │ (PIN+Touch) │ │ CA Key │ │
│ └──────┬───────┘ │ (PIN+Touch) │ │
│ │ └──────┬───────┘ │
│ │ │ │
│ Root Certificate Intermediate Cert │
│ (signed on YK1) (signed by Root) │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ Certificate API │ │
│ │ + Key Vault UI │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌─────────▼─────────┐ │
│ │ Certificate DB │ │
│ │ (SQLite/Postgres) │ │
│ └───────────────────┘ │
│ │
│ Firewall: Only local network (192.168.8.0/24) │
│ No outbound internet except Ubuntu package updates │
└─────────────────────────────────────────────────────┘
Phase 1: Machine Hardening
1.1 Base System Configuration
- Fresh Ubuntu Server installation verification
- Create dedicated
certauthuser with sudo privileges - Disable root login, enforce key-based SSH
- Configure SSH to only accept connections from local network (192.168.8.0/24)
- Set up UFW firewall:
- Allow SSH (port 22) from 192.168.8.0/24 only
- Allow HTTPS (port 443) for Key Vault UI from 192.168.8.0/24 only
- Allow HTTP (port 80) for redirect from 192.168.8.0/24 only
- Deny all other inbound traffic
- Deny all outbound traffic except:
- Ubuntu package repositories (archive.ubuntu.com, security.ubuntu.com)
- DNS (port 53)
- NTP (port 123)
- Local network traffic (192.168.8.0/24)
1.2 System Hardening
- Automatic security updates enabled
- Fail2ban for SSH protection
- Auditd for security auditing
- Remove unnecessary packages and services
- ConfigureAppArmor profiles
- Set up encrypted swap
- Configure secure kernel parameters (sysctl)
1.3 YubiKey Preparation
- Install
yubikey-manager,pcscd,opensc,gnutls-bin - Verify YubiKey connectivity and PIV applet
- Test both YubiKeys are recognized
Phase 2: YubiKey #1 - Root CA
2.1 YubiKey Configuration
- Set PIV PIN (strong, 9-16 chars)
- Set PIV PUK (for PIN reset)
- Set management key
- Configure touch policy to
callbackorfixed-onfor the signing key slot - Generate RSA 4096-bit (or EC P-384) key pair on the YubiKey (never leaves device)
- Key stored in PIV slot
9c(signing)
2.2 Root Certificate Generation
- Generate self-signed Root CA certificate on YubiKey
- Validity: 20-30 years
- Key usage: Certificate Signing, CRL Signing
- Basic constraints: CA:TRUE, pathlen:1
- Subject:
CN=certauth Root CA, O=Home, C=US(customizable) - Store Root CA certificate in
/etc/ssl/ca/root/
2.3 Security
- Root CA certificate is public and stored on disk
- Root private key never leaves YubiKey #1
- YubiKey #1 can be physically removed and stored offline when not in use
- All signing operations require PIN + physical touch
Phase 3: YubiKey #2 - Intermediate CA
3.1 YubiKey Configuration
- Set PIV PIN (strong, 9-16 chars, different from YK1)
- Set PIV PUK
- Set management key
- Configure touch policy to
callbackorfixed-onfor signing key slot - Generate RSA 4096-bit (or EC P-384) key pair on the YubiKey
- Key stored in PIV slot
9c(signing)
3.2 Intermediate Certificate Generation
- Generate CSR on YubiKey #2
- Sign CSR using YubiKey #1 (Root CA) — requires PIN + touch on YK1
- Validity: 10-15 years
- Key usage: Certificate Signing, CRL Signing
- Basic constraints: CA:TRUE, pathlen:0
- Subject:
CN=certauth Intermediate CA, O=Home, C=US - Store Intermediate CA certificate in
/etc/ssl/ca/intermediate/
3.3 Security
- Intermediate private key never leaves YubiKey #2
- All signing operations require PIN + physical touch
- Certificate chain: Root CA → Intermediate CA → Leaf Certificates
Phase 4: Certificate Management API & Key Vault UI
4.1 Technology Stack
- Backend: Python FastAPI (lightweight, async, good OpenAPI support)
- Database: SQLite (simple, file-based, sufficient for this scale)
- Frontend: HTMX + Tailwind CSS (minimal JS, server-rendered, fast)
- Reverse Proxy: Caddy (automatic HTTPS, simple config)
- Process Manager: systemd
4.2 API Endpoints
Authentication:
POST /api/auth/login - Admin login (username + password + TOTP)
POST /api/auth/logout - Logout
GET /api/auth/verify - Verify API key
Domain Management:
POST /api/domains - Register a new domain (e.g., *.example.com)
GET /api/domains - List all registered domains
GET /api/domains/{id} - Get domain details
DELETE /api/domains/{id} - Revoke domain registration
Certificate Management:
POST /api/certs/request - Request a new certificate for a domain
GET /api/certs - List all certificates
GET /api/certs/{id} - Get certificate details
GET /api/certs/{id}/download - Download certificate + chain
POST /api/certs/{id}/revoke - Revoke a certificate
POST /api/certs/{id}/renew - Renew a certificate
Health & Status:
GET /api/health - Health check
GET /api/yubikeys - YubiKey status (connected, slots)
4.3 Key Vault UI Features
- Dashboard showing certificate inventory, expiring certs, YubiKey status
- Domain registration form with validation
- Certificate request workflow:
- Select registered domain
- Specify SANs (Subject Alternative Names)
- Choose validity period
- Confirm request (triggers signing workflow)
- Certificate signing workflow:
- System generates CSR locally
- Admin inserts YubiKey #2, enters PIN, touches YubiKey
- Certificate is signed and stored
- Certificate + chain available for download
- Certificate download page with PEM files
- Audit log viewer
- Settings page for CA configuration
4.4 Signing Workflow (Human-in-the-Loop)
Since YubiKey requires physical touch + PIN, the signing process is semi-interactive:
1. Admin requests certificate via UI/API
2. System generates CSR and stores pending request
3. Admin runs: certauth sign --request <id>
- This prompts for YubiKey #2 PIN
- Admin touches YubiKey #2 when prompted
- Certificate is signed by Intermediate CA
4. Signed certificate stored in database
5. Status updated to "issued"
6. Certificate available for download
Alternative: Web-based signing using WebAuthn/CTAP2 (future enhancement)
4.5 API Key Authentication
- Admin generates API keys via UI
- API keys are scoped (read-only, sign, admin)
- Services authenticate with API key header:
X-API-Key: <key> - API keys stored hashed in database
Phase 5: Security Hardening
5.1 Application Security
- All API endpoints require authentication
- Rate limiting on API endpoints
- Input validation and sanitization
- SQL injection prevention (parameterized queries)
- CSRF protection for UI
- Content Security Policy headers
- Secure cookie flags (HttpOnly, Secure, SameSite)
5.2 Data Protection
- Database encrypted at rest (LUKS encrypted partition)
- Certificate files stored with restricted permissions (root:certauth, 0640)
- No secrets in plaintext logs
- API keys hashed (bcrypt)
- Passwords hashed (bcrypt)
5.3 Network Security
- Caddy configured with strong TLS settings
- Only binds to local network interfaces
- No services exposed to internet
- Outbound connections restricted by firewall
5.4 Operational Security
- Audit logging of all certificate operations
- Regular backup of certificates and configuration (encrypted)
- Monitoring for failed authentication attempts
- Log rotation and retention policy
Phase 6: Setup Script
6.1 Automated Setup Script (setup-certauth.sh)
A single script that can provision a fresh Ubuntu machine:
- Validates prerequisites (Ubuntu version, YubiKeys present)
- Runs all hardening steps
- Configures YubiKeys (interactive prompts for PINs)
- Generates CA certificates
- Installs and configures the Certificate API
- Sets up firewall rules
- Creates systemd services
- Outputs configuration summary and credentials
6.2 Configuration File (certauth.conf)
All configurable values in one file:
- CA subject information
- Certificate validity periods
- Network configuration
- Admin credentials
- YubiKey PIN policies
6.3 Documentation
- README with architecture overview
- OPERATIONS.md with daily usage instructions
- TROUBLESHOOTING.md with common issues
- BACKUP.md with backup and restore procedures
Directory Structure
certauth/
├── setup-certauth.sh # Main setup script
├── certauth.conf # Configuration file
├── README.md # Project documentation
├── OPERATIONS.md # Operations guide
├── scripts/
│ ├── harden-system.sh # System hardening
│ ├── configure-yubikey.sh # YubiKey setup
│ ├── generate-ca.sh # CA certificate generation
│ ├── install-api.sh # API installation
│ └── configure-firewall.sh # Firewall setup
├── api/
│ ├── main.py # FastAPI application
│ ├── models.py # Database models
│ ├── auth.py # Authentication
│ ├── signing.py # Certificate signing logic
│ ├── templates/ # HTML templates
│ ├── static/ # Static assets
│ └── requirements.txt # Python dependencies
├── systemd/
│ ├── certauth-api.service # API service unit
│ └── certauth-sign.timer # Signing timer unit
├── caddy/
│ └── Caddyfile # Caddy configuration
├── ssl/
│ └── openssl.cnf # OpenSSL configuration
└── tests/
└── test_api.py # API tests
Implementation Order
- Plan Review — You review and approve this plan
- Machine Hardening — SSH into machine, verify state, apply hardening
- YubiKey Setup — Configure both YubiKeys with Root and Intermediate CAs
- API Development — Build the Certificate Management API and UI
- Integration — Connect API to YubiKeys for signing
- Testing — End-to-end testing of certificate issuance
- Setup Script — Create reproducible setup script
- Documentation — Final documentation and handover
Security Considerations & Trade-offs
YubiKey Touch Policy
callback: Prompts user to touch (most flexible, requires polling)fixed-on: Always requires touch (most secure, slightly slower UX)- Recommendation:
fixed-onfor both keys
Key Algorithm
- RSA 4096: Wider compatibility, larger keys/certs
- EC P-384: Smaller, faster, modern
- Recommendation: RSA 4096 for maximum compatibility with all services/browsers
Signing Workflow
- Fully automated signing is not possible with YubiKey touch requirement
- Admin must be present to touch YubiKey and enter PIN
- This is a feature, not a limitation — it provides human-in-the-loop security
- For bulk operations, a CLI tool handles batch signing requests
Offline Root CA
- YubiKey #1 (Root) can be removed after Intermediate CA is created
- Root is only needed if Intermediate CA key is compromised
- This provides true offline root CA capability
Questions for Confirmation
- Key algorithm: RSA 4096 vs EC P-384? (RSA 4096 recommended for compatibility)
- Certificate validity: Root: 25 years, Intermediate: 15 years, Leaf: configurable per-request?
- TOTP for admin login: Enable two-factor authentication?
- Backup strategy: Encrypted backups to local disk only, or also to network share?
- Additional domains: Any specific domains to pre-register beyond
*.example.com? - CRL/OCSP: Do we need Certificate Revocation List or OCSP responder? (Adds complexity)
- Admin username: Should the admin account be
certauthor a different username?