Add server certificate management documentation and regeneration scripts
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>
This commit is contained in:
140
certs/README.md
Normal file
140
certs/README.md
Normal file
@@ -0,0 +1,140 @@
|
||||
# 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`
|
||||
Reference in New Issue
Block a user