certauth/PLAN.md

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 certauth user 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 callback or fixed-on for 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 callback or fixed-on for 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:
    1. Select registered domain
    2. Specify SANs (Subject Alternative Names)
    3. Choose validity period
    4. Confirm request (triggers signing workflow)
  • Certificate signing workflow:
    1. System generates CSR locally
    2. Admin inserts YubiKey #2, enters PIN, touches YubiKey
    3. Certificate is signed and stored
    4. 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

  1. Plan Review — You review and approve this plan
  2. Machine Hardening — SSH into machine, verify state, apply hardening
  3. YubiKey Setup — Configure both YubiKeys with Root and Intermediate CAs
  4. API Development — Build the Certificate Management API and UI
  5. Integration — Connect API to YubiKeys for signing
  6. Testing — End-to-end testing of certificate issuance
  7. Setup Script — Create reproducible setup script
  8. 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-on for 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

  1. Key algorithm: RSA 4096 vs EC P-384? (RSA 4096 recommended for compatibility)
  2. Certificate validity: Root: 25 years, Intermediate: 15 years, Leaf: configurable per-request?
  3. TOTP for admin login: Enable two-factor authentication?
  4. Backup strategy: Encrypted backups to local disk only, or also to network share?
  5. Additional domains: Any specific domains to pre-register beyond *.example.com?
  6. CRL/OCSP: Do we need Certificate Revocation List or OCSP responder? (Adds complexity)
  7. Admin username: Should the admin account be certauth or a different username?