- PostgreSQL schema: 14 tables, JSONB attributes, audit triggers, soft delete - FastAPI backend: CRUD, search/filter, relationship graph, bulk import, JWT RBAC - React frontend: CI table, detail card, force-graph, dashboard - Seed data: homelab scenario (Proxmox, Mikrotik, VMs, services) - Docker Compose + Kubernetes manifests - 20 backend tests (pytest + httpx)
133 lines
3.1 KiB
Markdown
133 lines
3.1 KiB
Markdown
# Security & Operations Guide
|
|
|
|
## PostgreSQL Security
|
|
|
|
### User Privileges
|
|
```sql
|
|
-- Create limited user for the application
|
|
CREATE USER cmdb_app WITH PASSWORD 'strong_password';
|
|
GRANT CONNECT ON DATABASE cmdb TO cmdb_app;
|
|
GRANT USAGE ON SCHEMA public TO cmdb_app;
|
|
GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO cmdb_app;
|
|
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO cmdb_app;
|
|
|
|
-- Read-only user for reporting
|
|
CREATE USER cmdb_reader WITH PASSWORD 'reader_password';
|
|
GRANT CONNECT ON DATABASE cmdb TO cmdb_reader;
|
|
GRANT USAGE ON SCHEMA public TO cmdb_reader;
|
|
GRANT SELECT ON ALL TABLES IN SCHEMA public TO cmdb_reader;
|
|
```
|
|
|
|
### SSL/TLS
|
|
```ini
|
|
# postgresql.conf
|
|
ssl = on
|
|
ssl_cert_file = '/etc/ssl/certs/server.crt'
|
|
ssl_key_file = '/etc/ssl/private/server.key'
|
|
ssl_min_protocol_version = 'TLSv1.2'
|
|
```
|
|
|
|
```bash
|
|
# pg_hba.conf — force SSL for remote connections
|
|
hostssl cmdb cmdb_app 10.0.0.0/24 scram-sha-256
|
|
```
|
|
|
|
## Backup Strategy
|
|
|
|
### pg_dump (logical backup)
|
|
```bash
|
|
# Daily backup script
|
|
#!/bin/bash
|
|
BACKUP_DIR="/var/backups/cmdb"
|
|
DATE=$(date +%Y%m%d_%H%M%S)
|
|
pg_dump -h localhost -U cmdb cmdb | gzip > "$BACKUP_DIR/cmdb_$DATE.sql.gz"
|
|
# Keep 30 days
|
|
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete
|
|
```
|
|
|
|
### pg_basebackup (physical backup)
|
|
```bash
|
|
# For PITR (Point-in-Time Recovery)
|
|
pg_basebackup -h localhost -U replicator -D /var/lib/cmdb-backup \
|
|
-Fp -Xs -P -R
|
|
```
|
|
|
|
### pgBackRest (enterprise)
|
|
```ini
|
|
# pgbackrest.conf
|
|
[cmdb]
|
|
pg1-path=/var/lib/postgresql/data
|
|
repo1-path=/var/lib/pgbackrest
|
|
repo1-retention-full=2
|
|
repo1-retention-diff=7
|
|
```
|
|
|
|
### Recovery
|
|
```bash
|
|
# From pg_dump
|
|
dropdb cmdb && createdb cmdb
|
|
zcat /var/backups/cmdb/cmdb_20240101_030000.sql.gz | psql -U cmdb cmdb
|
|
|
|
# From WAL replay
|
|
restore_command = 'cp /var/lib/pgbackrest/archive/cmdb/%f %p'
|
|
recovery_target_time = '2024-01-01 12:00:00'
|
|
```
|
|
|
|
## API Security
|
|
|
|
### Rate Limiting
|
|
Configured in `backend/.env`: `RATE_LIMIT_PER_MINUTE=120`
|
|
|
|
### CORS
|
|
```python
|
|
# Restrict in production
|
|
CORS_ORIGINS=["https://cmdb.yourdomain.com"]
|
|
```
|
|
|
|
### JWT Best Practices
|
|
- Rotate secrets quarterly
|
|
- Short expiration (60 min default)
|
|
- Store in HTTP-only cookies for web clients
|
|
- Validate `exp`, `iss`, `aud` claims
|
|
|
|
## Monitoring
|
|
|
|
### Prometheus Metrics (add to FastAPI)
|
|
```python
|
|
from prometheus_client import Counter, Histogram
|
|
|
|
REQUEST_COUNT = Counter('cmdb_requests_total', 'Total requests', ['method', 'endpoint'])
|
|
REQUEST_LATENCY = Histogram('cmdb_request_latency_seconds', 'Request latency', ['endpoint'])
|
|
```
|
|
|
|
### Health Checks
|
|
```bash
|
|
# Backend
|
|
curl http://localhost:8000/api/health
|
|
# → {"status": "healthy", "version": "1.0.0"}
|
|
|
|
# PostgreSQL
|
|
pg_isready -h localhost -p 5432 -U cmdb
|
|
```
|
|
|
|
### Log Aggregation
|
|
```yaml
|
|
# docker-compose logging
|
|
logging:
|
|
driver: json-file
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "3"
|
|
```
|
|
|
|
## Hardening Checklist
|
|
|
|
- [ ] Run containers as non-root
|
|
- [ ] Use read-only filesystem mounts where possible
|
|
- [ ] Enable seccomp/AppArmor profiles
|
|
- [ ] Scan images with Trivy/Snyk
|
|
- [ ] Rotate database passwords regularly
|
|
- [ ] Audit changelog table weekly
|
|
- [ ] Monitor for failed login attempts
|
|
- [ ] Set up alerting for 5xx errors
|