Documentation: - certs/README.md: Complete guide for managing nginx TLS certificates - Server cert generation (self-signed, CA-signed, Let's Encrypt) - Certificate expiry monitoring and renewal procedures - Agent certificate pinning configuration - Air-gapped deployment notes Tooling: - certs/regenerate-server-cert.sh: Bash script for cert regeneration - certs/regenerate-server-cert.ps1: PowerShell script for Windows - Both scripts backup old certs and display new thumbprint Config: - Updated .gitignore to allow cert management files (docs/scripts/config) - Private keys and actual certificates still excluded (security) Context: - User asked where to manage server-side certificate - Current cert: self-signed, CN=localhost, valid 1 year - Agents validate server cert via pinning or Windows trusted roots - Critical for mTLS client cert authentication (ADR-006) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
141 lines
4.0 KiB
Markdown
141 lines
4.0 KiB
Markdown
# ShopDB Server Certificate Management
|
|
|
|
This directory contains the TLS certificates for ShopDB's nginx server.
|
|
|
|
## Current Certificate
|
|
|
|
- **File**: `server.crt` (certificate) and `server.key` (private key)
|
|
- **Common Name**: localhost
|
|
- **Subject Alternative Names**: localhost, 192.168.100.1
|
|
- **Validity**: 1 year from generation date
|
|
- **Type**: Self-signed (for development and air-gapped sites)
|
|
|
|
## Certificate Location
|
|
|
|
The `certs/` directory is mounted into the nginx container at `/etc/nginx/certs/`:
|
|
|
|
```yaml
|
|
# docker-compose.yml
|
|
nginx:
|
|
volumes:
|
|
- ./certs:/etc/nginx/certs:ro
|
|
```
|
|
|
|
Referenced in `nginx.conf`:
|
|
```nginx
|
|
ssl_certificate /etc/nginx/certs/server.crt;
|
|
ssl_certificate_key /etc/nginx/certs/server.key;
|
|
```
|
|
|
|
## Generating a New Server Certificate
|
|
|
|
### Option 1: Self-Signed (Development/Air-Gapped)
|
|
|
|
Generate a new self-signed certificate valid for 1 year:
|
|
|
|
```bash
|
|
cd certs
|
|
|
|
# Generate new private key and certificate
|
|
openssl req -x509 -newkey rsa:2048 -nodes \
|
|
-keyout server.key \
|
|
-out server.crt \
|
|
-days 365 \
|
|
-config openssl.cnf
|
|
|
|
# Restart nginx to pick up new certificate
|
|
docker-compose restart nginx
|
|
```
|
|
|
|
### Option 2: Custom Certificate (Production)
|
|
|
|
If you have a certificate from a trusted CA or internal PKI:
|
|
|
|
1. Copy your certificate to `certs/server.crt`
|
|
2. Copy your private key to `certs/server.key`
|
|
3. Update `certs/openssl.cnf` with the correct CN and SANs
|
|
4. Restart nginx: `docker-compose restart nginx`
|
|
|
|
### Option 3: Let's Encrypt (Public-Facing Sites)
|
|
|
|
For internet-accessible ShopDB instances, use Let's Encrypt:
|
|
|
|
```bash
|
|
# Install certbot
|
|
apt-get install certbot python3-certbot-nginx
|
|
|
|
# Generate certificate (interactive)
|
|
certbot --nginx -d your-domain.com
|
|
|
|
# Copy certificates to certs directory
|
|
cp /etc/letsencrypt/live/your-domain.com/fullchain.pem certs/server.crt
|
|
cp /etc/letsencrypt/live/your-domain.com/privkey.pem certs/server.key
|
|
|
|
# Restart nginx
|
|
docker-compose restart nginx
|
|
```
|
|
|
|
## Certificate Expiry
|
|
|
|
Check current certificate expiry:
|
|
|
|
```bash
|
|
openssl x509 -in certs/server.crt -noout -dates
|
|
```
|
|
|
|
ShopDB agents validate the server certificate using:
|
|
- **Pinning** (if `ServerCertThumbprint` configured in agent appsettings.json)
|
|
- **Windows trusted roots** (if no pinning configured)
|
|
|
|
## Agent Certificate Pinning
|
|
|
|
To enable server certificate pinning on agents:
|
|
|
|
1. Get the server certificate thumbprint:
|
|
```powershell
|
|
# Windows
|
|
certutil -hashfile certs\server.crt SHA256
|
|
|
|
# Or from certificate details
|
|
openssl x509 -in certs/server.crt -fingerprint -sha256 -noout
|
|
```
|
|
|
|
2. Update agent `appsettings.json`:
|
|
```json
|
|
{
|
|
"ServerCertThumbprint": "AA:BB:CC:DD:EE:FF:..."
|
|
}
|
|
```
|
|
|
|
3. Restart the agent service
|
|
|
|
**NOTE**: When you renew the server certificate, you must update `ServerCertThumbprint` on all agents before the old certificate expires, or agents will reject the new certificate.
|
|
|
|
## Air-Gapped Site Deployment
|
|
|
|
For air-gapped sites:
|
|
1. Generate certificate on work PC (with correct hostname/IP)
|
|
2. Include `certs/` directory in bundle (already in git repo)
|
|
3. Deploy bundle to site
|
|
4. Certificate deploys automatically with `docker-compose up`
|
|
|
|
## Certificate Files
|
|
|
|
- `server.crt` - Server certificate (nginx HTTPS)
|
|
- `server.key` - Server private key
|
|
- `openssl.cnf` - OpenSSL configuration for certificate generation
|
|
- `test-client.crt`, `test-client.key`, `test-client.p12` - Test client certificates (for development only)
|
|
|
|
## Security Notes
|
|
|
|
- **Private Key Protection**: `server.key` should be readable only by nginx (done via Docker volume mount)
|
|
- **Self-Signed Trust**: Self-signed certificates are expected in air-gapped environments
|
|
- **Agent Pinning**: Use `ServerCertThumbprint` to prevent MITM attacks with self-signed certs
|
|
- **Expiry Monitoring**: Set calendar reminders to renew certificates before expiry
|
|
|
|
## Related Documentation
|
|
|
|
- Agent certificate renewal: `plugins/endpoints/api/certificate_renewal.py`
|
|
- Client certificate authentication: `shopdb/core/auth/client_cert.py`
|
|
- Nginx configuration: `nginx.conf`
|