feat: add API key authentication system for ChatGPT Business
Implements comprehensive Bearer token authentication to ensure only authorized ChatGPT workspaces can access the MCP server. Core Features: - API key validation with constant-time comparison - Multi-key support for rotation grace periods - Rate limiting (5 failures per IP per 5 min) - Comprehensive audit logging of all auth attempts - IP-based failed attempt tracking Key Management: - generate_api_key.py: Create secure 64-char keys - rotate_api_key.py: Guided key rotation with backup - check_key_age.py: Automated expiration monitoring Infrastructure: - Traefik labels for HTTPS and rate limiting - Security headers (HSTS, CSP, X-Frame-Options) - Environment-based configuration - Docker secrets support Documentation: - AUTH_SETUP.md: Complete authentication setup guide - CHATGPT_SETUP.md: ChatGPT Business integration guide - KEY_ROTATION.md: Key rotation procedures and automation Security: - Read-only operations enforced - No write access to Gitea possible - All auth attempts logged with correlation IDs - Failed attempts trigger IP rate limits - Keys never logged in full (only hints) Breaking Changes: - AUTH_ENABLED defaults to true - MCP_API_KEYS environment variable now required - Minimum key length: 32 characters (64 recommended) Migration: 1. Generate API key: make generate-key 2. Add to .env: MCP_API_KEYS=<generated-key> 3. Restart: docker-compose restart aegis-mcp 4. Configure ChatGPT with Authorization header Closes requirements for ChatGPT Business exclusive access.
This commit is contained in:
434
AUTH_SETUP.md
Normal file
434
AUTH_SETUP.md
Normal file
@@ -0,0 +1,434 @@
|
||||
# Authentication Setup Guide
|
||||
|
||||
This guide walks you through setting up API key authentication for AegisGitea MCP to ensure only your ChatGPT workspace can access your self-hosted Gitea instance.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
AegisGitea MCP uses **Bearer Token authentication** to secure access:
|
||||
|
||||
- **API Keys**: Cryptographically secure 64-character tokens
|
||||
- **Header-based**: Keys sent via `Authorization: Bearer <key>` header
|
||||
- **Multi-key support**: Multiple keys for rotation grace periods
|
||||
- **Rate limiting**: Failed auth attempts trigger IP-based rate limits
|
||||
- **Audit logging**: All auth attempts logged for security monitoring
|
||||
|
||||
---
|
||||
|
||||
## Quick Start (5 minutes)
|
||||
|
||||
### 1. Generate API Key
|
||||
|
||||
```bash
|
||||
# Using Make
|
||||
make generate-key
|
||||
|
||||
# Or directly
|
||||
python3 scripts/generate_api_key.py
|
||||
```
|
||||
|
||||
This will:
|
||||
- Generate a secure 64-character API key
|
||||
- Show you the key (save it immediately!)
|
||||
- Provide `.env` configuration snippet
|
||||
- Optionally save metadata (not the key itself) for tracking
|
||||
|
||||
**Example output:**
|
||||
```
|
||||
✓ API Key Generated Successfully!
|
||||
|
||||
API KEY:
|
||||
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2
|
||||
|
||||
📋 Next Steps:
|
||||
1. Add this key to your .env file
|
||||
2. Restart the MCP server
|
||||
3. Configure ChatGPT Business
|
||||
```
|
||||
|
||||
### 2. Add Key to .env
|
||||
|
||||
```bash
|
||||
# Edit .env
|
||||
nano .env
|
||||
|
||||
# Add/update this line:
|
||||
MCP_API_KEYS=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2
|
||||
```
|
||||
|
||||
### 3. Restart MCP Server
|
||||
|
||||
```bash
|
||||
docker-compose restart aegis-mcp
|
||||
|
||||
# Verify authentication is enabled
|
||||
docker-compose logs aegis-mcp | grep "authentication"
|
||||
```
|
||||
|
||||
Expected log output:
|
||||
```
|
||||
API key authentication ENABLED (1 key(s) configured)
|
||||
```
|
||||
|
||||
### 4. Test Authentication
|
||||
|
||||
```bash
|
||||
# Without key - should fail with 401
|
||||
curl https://mcp.yourdomain.com/mcp/tools
|
||||
|
||||
# With valid key - should succeed
|
||||
curl -H "Authorization: Bearer YOUR_KEY_HERE" \
|
||||
https://mcp.yourdomain.com/mcp/tools
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# Enable/disable authentication
|
||||
AUTH_ENABLED=true # Set to false ONLY for testing
|
||||
|
||||
# API keys (comma-separated for multiple)
|
||||
MCP_API_KEYS=key1 # Single key
|
||||
MCP_API_KEYS=key1,key2,key3 # Multiple keys (rotation grace period)
|
||||
|
||||
# Rate limiting
|
||||
MAX_AUTH_FAILURES=5 # Max failed attempts before blocking
|
||||
AUTH_FAILURE_WINDOW=300 # Time window in seconds (5 min)
|
||||
```
|
||||
|
||||
### Multiple Keys (Rotation Grace Period)
|
||||
|
||||
During key rotation, you can temporarily allow multiple keys:
|
||||
|
||||
```bash
|
||||
# Old key
|
||||
MCP_API_KEYS=old-key-here
|
||||
|
||||
# Add new key (both work)
|
||||
MCP_API_KEYS=old-key-here,new-key-here
|
||||
|
||||
# After updating ChatGPT, remove old key
|
||||
MCP_API_KEYS=new-key-here
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Features
|
||||
|
||||
### 1. Constant-Time Comparison
|
||||
|
||||
Keys are compared using `hmac.compare_digest()` to prevent timing attacks.
|
||||
|
||||
### 2. Rate Limiting
|
||||
|
||||
- **Threshold**: 5 failed attempts per IP
|
||||
- **Window**: 5 minutes (configurable)
|
||||
- **Action**: Reject all requests from that IP until window expires
|
||||
- **Logging**: High-severity security event logged
|
||||
|
||||
### 3. Audit Logging
|
||||
|
||||
Every authentication attempt logs:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2026-01-29T12:34:56.789Z",
|
||||
"event": "api_authentication",
|
||||
"status": "success",
|
||||
"client_ip": "203.0.113.42",
|
||||
"user_agent": "ChatGPT-User/1.0",
|
||||
"key_hint": "a1b2c3d4...e1f2"
|
||||
}
|
||||
```
|
||||
|
||||
Failed attempts:
|
||||
|
||||
```json
|
||||
{
|
||||
"timestamp": "2026-01-29T12:34:56.789Z",
|
||||
"event": "access_denied",
|
||||
"reason": "invalid_api_key",
|
||||
"client_ip": "203.0.113.42"
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Key Format Validation
|
||||
|
||||
- Minimum length: 32 characters
|
||||
- Recommended length: 64 characters
|
||||
- Format: Hexadecimal string (0-9, a-f)
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: "No API keys configured" error
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
docker-compose logs: "No API keys configured in environment"
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
1. Check `.env` file exists and contains `MCP_API_KEYS`
|
||||
2. Ensure no typos (`MCP_API_KEYS` not `MCP_API_KEY`)
|
||||
3. Verify key is at least 32 characters
|
||||
4. Restart container after updating `.env`
|
||||
|
||||
### Issue: "Invalid API key" on valid key
|
||||
|
||||
**Possible causes:**
|
||||
|
||||
1. **Whitespace in .env**: Remove spaces around `=`
|
||||
```bash
|
||||
# Wrong
|
||||
MCP_API_KEYS = key-here
|
||||
|
||||
# Correct
|
||||
MCP_API_KEYS=key-here
|
||||
```
|
||||
|
||||
2. **Key truncated**: Ensure entire 64-char key is copied
|
||||
```bash
|
||||
# Check key length
|
||||
echo -n "your-key-here" | wc -c
|
||||
# Should output: 64
|
||||
```
|
||||
|
||||
3. **Container not restarted**: Always restart after changing `.env`
|
||||
```bash
|
||||
docker-compose restart aegis-mcp
|
||||
```
|
||||
|
||||
### Issue: Rate limit blocking legitimate requests
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
"Too many failed authentication attempts"
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
1. Check audit logs for failed attempts:
|
||||
```bash
|
||||
docker-compose exec aegis-mcp cat /var/log/aegis-mcp/audit.log | grep "invalid_api_key"
|
||||
```
|
||||
|
||||
2. Wait 5 minutes for rate limit to reset
|
||||
|
||||
3. If accidentally blocked yourself:
|
||||
```bash
|
||||
# Restart container (clears in-memory rate limits)
|
||||
docker-compose restart aegis-mcp
|
||||
```
|
||||
|
||||
4. Adjust rate limit settings in `.env` if needed:
|
||||
```bash
|
||||
MAX_AUTH_FAILURES=10
|
||||
AUTH_FAILURE_WINDOW=600
|
||||
```
|
||||
|
||||
### Issue: ChatGPT can't connect after adding auth
|
||||
|
||||
See [CHATGPT_SETUP.md](CHATGPT_SETUP.md) for detailed ChatGPT configuration.
|
||||
|
||||
**Quick check:**
|
||||
1. Verify key in ChatGPT settings matches `.env`
|
||||
2. Check Authorization header format: `Bearer <key>` (with space)
|
||||
3. Test manually with curl first
|
||||
|
||||
---
|
||||
|
||||
## Monitoring Authentication
|
||||
|
||||
### View All Auth Attempts
|
||||
|
||||
```bash
|
||||
# All auth events
|
||||
docker-compose exec aegis-mcp grep "api_authentication" /var/log/aegis-mcp/audit.log
|
||||
|
||||
# Failed attempts only
|
||||
docker-compose exec aegis-mcp grep "access_denied" /var/log/aegis-mcp/audit.log
|
||||
|
||||
# Rate limit triggers
|
||||
docker-compose exec aegis-mcp grep "auth_rate_limit_exceeded" /var/log/aegis-mcp/audit.log
|
||||
```
|
||||
|
||||
### Real-Time Monitoring
|
||||
|
||||
```bash
|
||||
# Follow auth events
|
||||
docker-compose exec aegis-mcp tail -f /var/log/aegis-mcp/audit.log | grep "auth"
|
||||
```
|
||||
|
||||
### Weekly Summary Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Save as scripts/auth_summary.sh
|
||||
|
||||
CONTAINER="aegis-gitea-mcp"
|
||||
LOG_PATH="/var/log/aegis-mcp/audit.log"
|
||||
|
||||
echo "=== Weekly Auth Summary ==="
|
||||
echo ""
|
||||
echo "Total auth attempts:"
|
||||
docker exec $CONTAINER grep "api_authentication" $LOG_PATH | wc -l
|
||||
|
||||
echo ""
|
||||
echo "Successful:"
|
||||
docker exec $CONTAINER grep "api_authentication.*success" $LOG_PATH | wc -l
|
||||
|
||||
echo ""
|
||||
echo "Failed:"
|
||||
docker exec $CONTAINER grep "access_denied.*invalid_api_key" $LOG_PATH | wc -l
|
||||
|
||||
echo ""
|
||||
echo "Rate limited IPs:"
|
||||
docker exec $CONTAINER grep "auth_rate_limit_exceeded" $LOG_PATH | wc -l
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Key Storage
|
||||
|
||||
- ✅ Store in `.env` file (never commit to git)
|
||||
- ✅ Use password manager for backup
|
||||
- ✅ Save key metadata (not key itself) for tracking
|
||||
- ❌ Never hardcode in application code
|
||||
- ❌ Never share via unencrypted channels
|
||||
|
||||
### 2. Key Rotation
|
||||
|
||||
- **Schedule**: Every 90 days (automated check available)
|
||||
- **Method**: Use `make rotate-key` for guided rotation
|
||||
- **Grace period**: Temporarily allow both old and new keys
|
||||
- **Verification**: Test new key before removing old key
|
||||
|
||||
See [KEY_ROTATION.md](KEY_ROTATION.md) for detailed rotation procedures.
|
||||
|
||||
### 3. Access Control
|
||||
|
||||
- **Single workspace**: One key for your ChatGPT Business account
|
||||
- **Multiple users**: One key per user (track with metadata)
|
||||
- **Revocation**: Remove key from `.env` and restart
|
||||
|
||||
### 4. Monitoring
|
||||
|
||||
- **Weekly**: Review auth logs for anomalies
|
||||
- **Monthly**: Check key age with `make check-key-age`
|
||||
- **Quarterly**: Rotate keys
|
||||
- **Alerts**: Set up notifications for rate limit events
|
||||
|
||||
---
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Disable Authentication (Testing Only)
|
||||
|
||||
**⚠️ WARNING: Only for isolated test environments**
|
||||
|
||||
```bash
|
||||
# .env
|
||||
AUTH_ENABLED=false
|
||||
```
|
||||
|
||||
Server will log critical warning:
|
||||
```
|
||||
API key authentication DISABLED - server is open to all requests!
|
||||
```
|
||||
|
||||
### Custom Rate Limiting
|
||||
|
||||
```bash
|
||||
# More lenient (for high-traffic)
|
||||
MAX_AUTH_FAILURES=20
|
||||
AUTH_FAILURE_WINDOW=600 # 10 minutes
|
||||
|
||||
# More strict (for high-security)
|
||||
MAX_AUTH_FAILURES=3
|
||||
AUTH_FAILURE_WINDOW=1800 # 30 minutes
|
||||
```
|
||||
|
||||
### Key Hashing (Future Enhancement)
|
||||
|
||||
Currently keys are stored in plaintext in `.env`. Future versions will support hashed keys in database.
|
||||
|
||||
**Current security model:**
|
||||
- ✅ Keys never logged in full (only first 8 + last 4 chars)
|
||||
- ✅ `.env` file protected by filesystem permissions
|
||||
- ✅ Container runs as non-root user
|
||||
- ⚠️ Ensure `.env` has restrictive permissions: `chmod 600 .env`
|
||||
|
||||
---
|
||||
|
||||
## Security Checklist
|
||||
|
||||
Before going to production:
|
||||
|
||||
- [ ] API key generated with `make generate-key` (not manually typed)
|
||||
- [ ] Key is exactly 64 characters
|
||||
- [ ] `.env` file has restrictive permissions (`chmod 600 .env`)
|
||||
- [ ] `.env` is in `.gitignore` (verify: `git status` shows no .env)
|
||||
- [ ] Container restarted after adding key
|
||||
- [ ] Authentication enabled (check logs for "ENABLED" message)
|
||||
- [ ] Test curl command succeeds with key, fails without
|
||||
- [ ] ChatGPT configured with Authorization header
|
||||
- [ ] Rate limiting tested (try 6 failed attempts)
|
||||
- [ ] Audit logs capturing auth events
|
||||
- [ ] Key rotation reminder set (90 days)
|
||||
- [ ] Backup key stored securely (password manager)
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Can I use the same key for multiple ChatGPT workspaces?**
|
||||
|
||||
A: Yes, but not recommended. Generate separate keys for auditability:
|
||||
```bash
|
||||
MCP_API_KEYS=workspace1-key,workspace2-key
|
||||
```
|
||||
|
||||
**Q: How do I revoke access immediately?**
|
||||
|
||||
A: Remove key from `.env` and restart:
|
||||
```bash
|
||||
# Edit .env (remove old key)
|
||||
docker-compose restart aegis-mcp
|
||||
```
|
||||
|
||||
Access is revoked instantly after restart.
|
||||
|
||||
**Q: Does rate limiting affect valid keys?**
|
||||
|
||||
A: No. Rate limiting only applies to IPs that fail authentication. Valid keys are never rate limited.
|
||||
|
||||
**Q: Can I see which key was used for each request?**
|
||||
|
||||
A: Yes. Audit logs include `key_hint` (first 8 + last 4 characters):
|
||||
```json
|
||||
{"key_hint": "a1b2c3d4...e1f2"}
|
||||
```
|
||||
|
||||
**Q: What happens if I lose my API key?**
|
||||
|
||||
A: Generate a new one with `make generate-key`, update `.env`, restart server, update ChatGPT config. The old key stops working immediately after restart.
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [ChatGPT Setup Guide](CHATGPT_SETUP.md) - Configure ChatGPT Business
|
||||
- [Key Rotation Guide](KEY_ROTATION.md) - Automated rotation procedures
|
||||
- [Security Policy](SECURITY.md) - Overall security best practices
|
||||
|
||||
---
|
||||
|
||||
**Need help?** Open an issue in the Gitea repository.
|
||||
Reference in New Issue
Block a user