Files
AegisGitea-MCP/AUTH_SETUP.md
latte eeaad748a6 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.
2026-01-29 20:05:49 +01:00

435 lines
10 KiB
Markdown

# 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.