146 lines
4.9 KiB
Markdown
146 lines
4.9 KiB
Markdown
# Production Deployment Guide
|
|
|
|
## Overview
|
|
|
|
AOC runs as a set of Docker containers orchestrated by Docker Compose:
|
|
|
|
- **nginx** — reverse proxy, TLS termination, static file serving
|
|
- **backend** — FastAPI application (Gunicorn + Uvicorn workers)
|
|
- **mongo** — MongoDB data store (not exposed externally)
|
|
- **valkey** — Redis-compatible cache and async job queue (not exposed externally)
|
|
|
|
## Prerequisites
|
|
|
|
- Docker Engine 24+ and Docker Compose plugin
|
|
- A server with ports 80/443 reachable from your users
|
|
- TLS certificates (place in `nginx/ssl/` or use Let's Encrypt)
|
|
- A valid `.env` file at the repo root (see `.env.example`)
|
|
|
|
## Quick start
|
|
|
|
1. **Clone / pull the latest release**
|
|
|
|
```bash
|
|
git checkout v1.7.14
|
|
```
|
|
|
|
2. **Copy and edit environment variables**
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
# Edit .env and fill in real credentials
|
|
```
|
|
|
|
3. **Set the release version**
|
|
|
|
```bash
|
|
export AOC_VERSION=v1.7.14
|
|
```
|
|
|
|
4. **Deploy**
|
|
|
|
```bash
|
|
docker compose -f docker-compose.prod.yml pull
|
|
docker compose -f docker-compose.prod.yml up -d
|
|
```
|
|
|
|
5. **Verify**
|
|
|
|
```bash
|
|
curl http://localhost/health
|
|
curl http://localhost/api/events
|
|
```
|
|
|
|
## Updating to a new release
|
|
|
|
```bash
|
|
export AOC_VERSION=v1.7.14
|
|
docker compose -f docker-compose.prod.yml pull
|
|
docker compose -f docker-compose.prod.yml up -d
|
|
```
|
|
|
|
## Enabling HTTPS
|
|
|
|
### Option A: Use your own certificates
|
|
|
|
1. Place `cert.pem` and `key.pem` in `nginx/ssl/`
|
|
2. Uncomment the HTTPS server block in `nginx/nginx.conf`
|
|
3. Uncomment the HTTP → HTTPS redirect server block
|
|
4. Reload nginx:
|
|
|
|
```bash
|
|
docker compose -f docker-compose.prod.yml exec nginx nginx -s reload
|
|
```
|
|
|
|
### Option B: Let's Encrypt with Certbot
|
|
|
|
Replace the `nginx` service in `docker-compose.prod.yml` with a Certbot-friendly setup (e.g., use the `nginx-proxy` + `acme-companion` stack) or mount the Certbot certificates into `nginx/ssl/`.
|
|
|
|
## Security Hardening
|
|
|
|
- MongoDB is **not exposed** to the host — only the backend container can reach it.
|
|
- Valkey/Redis is **not exposed** to the host — only the backend container can reach it.
|
|
- The backend runs as a non-root (`aoc`) user inside the container.
|
|
- nginx adds security headers (`X-Frame-Options`, `X-Content-Type-Options`, etc.).
|
|
- Keep `.env` out of version control — it is listed in `.gitignore`.
|
|
- Set `AUTH_ENABLED=true` and configure `AUTH_ALLOWED_ROLES` or `AUTH_ALLOWED_GROUPS` to restrict access to admin/security roles.
|
|
- Set explicit `CORS_ORIGINS` — do not use `*` in production when auth is enabled.
|
|
- Set `DOCS_ENABLED=false` to hide OpenAPI docs (`/docs`, `/openapi.json`).
|
|
- Configure `WEBHOOK_CLIENT_SECRET` to validate Graph webhook notifications.
|
|
- Set `LLM_ALLOWED_DOMAINS` if using AI features (e.g. `api.openai.com,*.openai.azure.com`).
|
|
- Set `SIEM_ALLOWED_DOMAINS` if using SIEM forwarding.
|
|
- Review `METRICS_ALLOWED_IPS` — defaults to private networks + loopback.
|
|
|
|
## Azure Key Vault (Optional)
|
|
|
|
To eliminate long-lived secrets from `.env`:
|
|
|
|
1. Create an Azure Key Vault and add these secrets:
|
|
- `aoc-client-secret` — your Graph app `CLIENT_SECRET`
|
|
- `aoc-llm-api-key` — your `LLM_API_KEY` (if using AI)
|
|
- `aoc-mongo-uri` — your `MONGO_URI`
|
|
- `aoc-webhook-client-secret` — your `WEBHOOK_CLIENT_SECRET`
|
|
|
|
2. Uncomment `azure-identity` and `azure-keyvault-secrets` in `backend/requirements.txt`
|
|
|
|
3. Set `AZURE_KEY_VAULT_NAME=your-keyvault-name` in `.env`
|
|
|
|
4. Grant the container identity `Get` permission on secrets:
|
|
- If using Azure Container Instances / AKS: assign a managed identity
|
|
- If using VM: assign a managed identity or use a service principal
|
|
- If using local Docker: authenticate via `az login` on the host
|
|
|
|
5. Rebuild and redeploy:
|
|
```bash
|
|
docker compose -f docker-compose.prod.yml up -d --build
|
|
```
|
|
|
|
## Rollback
|
|
|
|
```bash
|
|
export AOC_VERSION=v1.7.13
|
|
docker compose -f docker-compose.prod.yml pull
|
|
docker compose -f docker-compose.prod.yml up -d
|
|
```
|
|
|
|
## Monitoring
|
|
|
|
- Prometheus metrics: `http://your-host/metrics` (IP-restricted by default)
|
|
- Health check: `http://your-host/health`
|
|
- Container logs:
|
|
|
|
```bash
|
|
docker compose -f docker-compose.prod.yml logs -f backend
|
|
docker compose -f docker-compose.prod.yml logs -f nginx
|
|
docker compose -f docker-compose.prod.yml logs -f mongo
|
|
docker compose -f docker-compose.prod.yml logs -f valkey
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
- **Auth warning in logs**: "AUTH_ENABLED is true but no AUTH_ALLOWED_ROLES or AUTH_ALLOWED_GROUPS are configured" — set these to restrict access.
|
|
- **CORS issues**: Set `CORS_ORIGINS` to your exact frontend origin(s). Wildcard with auth enabled disables credentials.
|
|
- **Rate limiting 429s**: Check Redis/Valkey connectivity. The rate limiter fails closed (returns 429) when Redis is down.
|
|
- **LLM errors**: Verify `LLM_BASE_URL` is in `LLM_ALLOWED_DOMAINS` if the allowlist is configured.
|
|
- **SIEM not forwarding**: Verify `SIEM_WEBHOOK_URL` uses HTTPS and is in `SIEM_ALLOWED_DOMAINS`.
|