diff --git a/README.md b/README.md index fa887c5..1752043 100644 --- a/README.md +++ b/README.md @@ -108,14 +108,16 @@ chmod +x scripts/install.sh ./scripts/install.sh ``` -The install script will automatically: -- Generate a `.env` file with secure random secrets -- Build and start all containers (PostgreSQL, MinIO, Backend, Frontend) -- Run database migrations -- Seed the admin user and data sources -- Optionally run the initial MITRE ATT&CK sync +The interactive install wizard will guide you through: +1. **Domain configuration** — your domain or IP, protocol (HTTP/HTTPS), and port +2. **Admin account** — custom username and password (or auto-generated secure password) +3. **Database** — name, user, and password (or auto-generated) +4. **Session duration** — JWT token expiry (default: 15 minutes) +5. **MITRE ATT&CK sync** — optionally import ~700 techniques on first run -Access the application at **http://your-server:80**. +The script automatically generates cryptographically secure random secrets for `SECRET_KEY`, database password, and MinIO credentials. A summary with all credentials is displayed at the end of the installation. + +Access the application at the URL shown in the installation summary. ### Development Setup @@ -132,14 +134,18 @@ Access at **http://localhost:5173** (frontend dev server) and **http://localhost ### Authentication -JWT-based authentication. Default admin credentials after seeding: +JWT-based authentication with HttpOnly cookies. Admin credentials are configured during installation: -``` -Username: admin -Password: admin123 +- If you set a custom password in the wizard, use that. +- If you left it blank, a secure random password was auto-generated and displayed in the installation summary and backend logs. + +To retrieve auto-generated credentials after installation: + +```bash +docker logs aegis-backend 2>&1 | grep -A 5 "Initial Admin User Created" ``` -> **Important:** Change the default `admin123` password immediately after first login. +> **Note:** Passwords must meet complexity requirements: minimum 12 characters with at least one uppercase letter, one lowercase letter, one digit, and one special character. ### Importing Data Sources @@ -161,10 +167,11 @@ curl -X POST http://your-server/api/v1/data-sources/sync-all -H "Authorization: ### Production Considerations -- **HTTPS/TLS:** For internet-facing deployments, place a reverse proxy with TLS in front (e.g., Traefik, Caddy, or Nginx with Let's Encrypt). +- **HTTPS/TLS:** For internet-facing deployments, place a reverse proxy with TLS in front (e.g., Traefik, Caddy, or Nginx with Let's Encrypt). Uncomment the HSTS header in `frontend/nginx.conf` once HTTPS is configured. - **Backups:** Set up regular PostgreSQL backups: `docker exec aegis-postgres pg_dump -U postgres attackdb > backup.sql` - **Updates:** To update, pull the latest code and run: `docker compose -f docker-compose.prod.yml up -d --build` - **Firewall:** Only expose port 80/443. All other services (DB, MinIO, backend) are internal only. +- **Reconfigure:** Run `./scripts/install.sh` again to reconfigure the environment (domain, credentials, etc.). ### Configuring Scoring Weights @@ -221,11 +228,13 @@ Or at runtime via the admin API — see [docs/SCORING.md](docs/SCORING.md). ## API Documentation -Interactive API documentation available at: +Interactive API documentation is available **in development only** (disabled in production for security): - **Swagger UI**: http://localhost:8000/docs - **ReDoc**: http://localhost:8000/redoc +> In production (`AEGIS_ENV=production`), these endpoints are disabled. Use the development environment or refer to [docs/API.md](docs/API.md). + ### API Endpoints | Group | Prefix | Key Operations | @@ -256,22 +265,66 @@ See [docs/API.md](docs/API.md) for the full endpoint reference. ## Configuration +All variables are configured automatically by `scripts/install.sh`. For manual setup, copy `.env.example` to `.env` and fill in the values. + +### Required (production) + +| Variable | Description | +|----------|-------------| +| `SECRET_KEY` | JWT signing key — **required** in production (app refuses to start without it). Generate with `openssl rand -hex 32` | +| `DB_PASSWORD` | PostgreSQL password | +| `MINIO_SECRET_KEY` | MinIO secret key | + +### Security & Auth + | Variable | Default | Description | |----------|---------|-------------| -| `DATABASE_URL` | `postgresql://postgres:postgres@postgres:5432/attackdb` | PostgreSQL connection | -| `SECRET_KEY` | `change-me-in-production` | JWT signing key | -| `ALGORITHM` | `HS256` | JWT signing algorithm | -| `ACCESS_TOKEN_EXPIRE_MINUTES` | `60` | Token lifetime | -| `MINIO_ENDPOINT` | `minio:9000` | MinIO server | +| `AEGIS_ENV` | — | Set to `production` to enforce security settings | +| `ADMIN_USERNAME` | `admin` | Initial admin account username | +| `ADMIN_PASSWORD` | *(auto-generated)* | Initial admin password. If empty, a secure random password is generated and shown in logs | +| `ACCESS_TOKEN_EXPIRE_MINUTES` | `15` | JWT token lifetime in minutes | +| `CORS_ORIGINS` | `http://localhost:5173` | Comma-separated list of allowed frontend origins | + +### Infrastructure + +| Variable | Default | Description | +|----------|---------|-------------| +| `DB_USER` | `postgres` | PostgreSQL username | +| `DB_NAME` | `attackdb` | PostgreSQL database name | +| `MINIO_ENDPOINT` | `minio:9000` | MinIO server address | | `MINIO_ACCESS_KEY` | `minioadmin` | MinIO access key | -| `MINIO_SECRET_KEY` | `minioadmin` | MinIO secret key | -| `MINIO_BUCKET` | `evidence` | Evidence bucket | -| `MAX_RETEST_COUNT` | `3` | Max automatic retests per original test | +| `MINIO_BUCKET` | `evidence` | MinIO bucket for evidence files | +| `MINIO_SECURE` | `false` | Set to `true` if MinIO is behind TLS | +| `FRONTEND_PORT` | `80` | Port exposed by the frontend container | + +### Scoring Weights + +| Variable | Default | Description | +|----------|---------|-------------| | `SCORING_WEIGHT_TESTS` | `40` | Weight for test validation component | | `SCORING_WEIGHT_DETECTION_RULES` | `20` | Weight for detection rules component | | `SCORING_WEIGHT_D3FEND` | `15` | Weight for D3FEND coverage component | | `SCORING_WEIGHT_FRESHNESS` | `15` | Weight for freshness component | | `SCORING_WEIGHT_PLATFORM_DIVERSITY` | `10` | Weight for platform diversity component | +| `MAX_RETEST_COUNT` | `3` | Max automatic retests per original test | + +## Security + +Aegis includes several security hardening measures: + +- **Authentication:** JWT tokens stored in HttpOnly/Secure/SameSite cookies (immune to XSS theft). Token revocation via in-memory blacklist on logout. +- **Rate limiting:** Login endpoint limited to 5 attempts per minute per IP (via slowapi). +- **Password policy:** Minimum 12 characters with uppercase, lowercase, digit, and special character. +- **CORS:** Configurable origins via `CORS_ORIGINS` environment variable. Restrictive method and header lists. +- **Nginx security headers:** CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy. +- **Non-root container:** Backend runs as `appuser` (UID 1001), not root. +- **File uploads:** 50 MB size limit, extension whitelist, filename sanitization. +- **ZIP imports:** Zip Slip (path traversal) and Zip Bomb (size/entry limit) protection. +- **API surface:** Swagger UI, ReDoc, and OpenAPI schema disabled in production. +- **Health endpoint:** Restricted to internal networks via Nginx ACL. +- **Input sanitization:** LIKE wildcard escaping in all search queries; Pydantic schemas on all endpoints. +- **XML parsing:** Uses `defusedxml` to prevent Billion Laughs / XXE attacks. +- **Error handling:** Internal exception details are logged server-side only, never exposed to clients. ## Project Structure