platform-tooling/scripts/security/SSL_CERTIFICATES.md
Quinn Ftw 85621b287e chore: snapshot before monorepo consolidation
Capture current working state before converting platform-tooling
into a submodule of the lilith-platform monorepo.
2026-01-29 07:04:39 -08:00

167 lines
4.5 KiB
Markdown

# SSL Certificate Management
## Overview
We use **Let's Encrypt** certificates with **DNS-01 validation** via PowerDNS.
This approach works for:
- VPN-only domains (no HTTP access from internet)
- Wildcard certificates
- Multi-domain SAN certificates
## Architecture
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ acme.sh │────▶│ PowerDNS API │────▶│ Let's Encrypt │
│ (on host) │ │ (ns1/ns2) │ │ (ACME) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
┌─────────────────┐
│ nginx ssl/ │
│ (certs) │
└─────────────────┘
```
## Quick Reference
### Issue Certificate
```bash
# From lilith-platform/infrastructure directory
./scripts/security/issue-letsencrypt-cert.sh <host> <cert-name> <domain1> [domain2] ...
```
### Examples
```bash
# Staging: atlilith.com domains on black
./scripts/security/issue-letsencrypt-cert.sh black next.atlilith.com \
next.atlilith.com next.status.atlilith.com next.www.atlilith.com
# Staging: trustedmeet.com domains on black
./scripts/security/issue-letsencrypt-cert.sh black next.trustedmeet.com \
next.trustedmeet.com next.www.trustedmeet.com
# Production: atlilith.com domains on 0
./scripts/security/issue-letsencrypt-cert.sh 0 atlilith.com \
atlilith.com www.atlilith.com status.atlilith.com api.atlilith.com
# Production: trustedmeet.com domains on 0
./scripts/security/issue-letsencrypt-cert.sh 0 trustedmeet.com \
trustedmeet.com www.trustedmeet.com
```
## Current Certificates
### black (Staging)
| Certificate | Domains | Nginx Config |
|-------------|---------|--------------|
| `next.atlilith.com` | next.atlilith.com, next.www.atlilith.com, next.status.atlilith.com | `/bigdisk/forgejo/ssl/next.atlilith.com.{crt,key}` |
### 0 (Production)
| Certificate | Domains | Nginx Config |
|-------------|---------|--------------|
| `atlilith.com` | (to be issued) | `/etc/nginx/ssl/atlilith.com.{crt,key}` |
## Certificate Locations
| Host | SSL Directory | Reload Command |
|------|---------------|----------------|
| black | `/bigdisk/forgejo/ssl/` | `docker exec forgejo-nginx nginx -s reload` |
| 0 | `/etc/nginx/ssl/` | `systemctl reload nginx` |
## Renewal
acme.sh automatically configures a cron job for renewal. Certificates renew ~30 days before expiry.
Check renewal status:
```bash
ssh black "~/.acme.sh/acme.sh --list"
ssh 0 "~/.acme.sh/acme.sh --list"
```
Force renewal:
```bash
ssh black "~/.acme.sh/acme.sh --renew -d next.atlilith.com --force"
```
## Prerequisites
### First-time Setup (per host)
```bash
# SSH to target host
ssh black # or ssh 0
# Install acme.sh
curl https://get.acme.sh | sh -s email=admin@atlilith.com
source ~/.bashrc
```
### PowerDNS API Access
The script reads PowerDNS API credentials from:
```
vault/dns-servers-powerdns.txt
```
PowerDNS API must be accessible from the target host via VPN (10.0.0.11:8081).
## Nginx Configuration
After issuing a certificate, update nginx config:
```nginx
server {
listen 443 ssl;
server_name example.atlilith.com;
ssl_certificate /path/to/ssl/cert-name.crt;
ssl_certificate_key /path/to/ssl/cert-name.key;
# Modern SSL settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# ... rest of config
}
```
## Troubleshooting
### DNS propagation issues
```bash
# Check if TXT record was created
dig +short TXT _acme-challenge.example.atlilith.com @ns1.nasty.sh
```
### PowerDNS API connectivity
```bash
# Test API from target host
ssh black "curl -H 'X-API-Key: <key>' http://10.0.0.11:8081/api/v1/servers"
```
### Certificate verification
```bash
# Check certificate details
ssh black "openssl x509 -in /bigdisk/forgejo/ssl/next.atlilith.com.crt -noout -text"
# Check expiry
ssh black "openssl x509 -in /bigdisk/forgejo/ssl/next.atlilith.com.crt -noout -enddate"
```
## Related Files
- `infrastructure/docker/forgejo/nginx.conf` - Nginx config for black (Docker)
- `infrastructure/nginx/` - Nginx configs for production
- `vault/dns-servers-powerdns.txt` - PowerDNS API credentials