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:
435
CHATGPT_SETUP.md
Normal file
435
CHATGPT_SETUP.md
Normal file
@@ -0,0 +1,435 @@
|
||||
# ChatGPT Business Setup Guide
|
||||
|
||||
Complete guide for connecting ChatGPT Business to your secured AegisGitea MCP server.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- ✅ AegisGitea MCP server deployed and running
|
||||
- ✅ API key generated (see [AUTH_SETUP.md](AUTH_SETUP.md))
|
||||
- ✅ Traefik configured with HTTPS (or reverse proxy with TLS)
|
||||
- ✅ ChatGPT Business or Developer subscription
|
||||
|
||||
---
|
||||
|
||||
## Setup Steps
|
||||
|
||||
### Step 1: Verify MCP Server is Running
|
||||
|
||||
```bash
|
||||
# Check container status
|
||||
docker-compose ps
|
||||
|
||||
# Should show "Up" status
|
||||
aegis-gitea-mcp Up 0.0.0.0:8080->8080/tcp
|
||||
```
|
||||
|
||||
### Step 2: Test Authentication
|
||||
|
||||
```bash
|
||||
# Replace YOUR_API_KEY with your actual key
|
||||
curl -H "Authorization: Bearer YOUR_API_KEY" \
|
||||
https://mcp.yourdomain.com/mcp/tools
|
||||
|
||||
# Expected: JSON response with available tools
|
||||
# If error: Check AUTH_SETUP.md troubleshooting
|
||||
```
|
||||
|
||||
### Step 3: Configure ChatGPT Business
|
||||
|
||||
1. **Open ChatGPT Settings**
|
||||
- Click your profile icon (bottom left)
|
||||
- Select "Settings"
|
||||
- Navigate to "Beta Features" or "Integrations"
|
||||
|
||||
2. **Add MCP Server**
|
||||
- Look for "Model Context Protocol" or "MCP Servers"
|
||||
- Click "Add Server" or "+"
|
||||
|
||||
3. **Enter Server Details**
|
||||
```
|
||||
Name: AegisGitea MCP
|
||||
URL: https://mcp.yourdomain.com
|
||||
Type: HTTP/SSE (Server-Sent Events)
|
||||
```
|
||||
|
||||
4. **Add Custom Header**
|
||||
```
|
||||
Header Name: Authorization
|
||||
Header Value: Bearer YOUR_API_KEY_HERE
|
||||
```
|
||||
|
||||
**Important:**
|
||||
- Include the word "Bearer" followed by a space
|
||||
- Then paste your full 64-character API key
|
||||
- No quotes around the key
|
||||
|
||||
5. **Save Configuration**
|
||||
|
||||
### Step 4: Test Connection
|
||||
|
||||
Start a new ChatGPT conversation and try:
|
||||
|
||||
```
|
||||
List my Gitea repositories
|
||||
```
|
||||
|
||||
**Expected Response:**
|
||||
```
|
||||
I found X repositories in your Gitea instance:
|
||||
|
||||
1. org/repo-name - Description here
|
||||
2. org/another-repo - Another description
|
||||
...
|
||||
```
|
||||
|
||||
**If it fails**, see Troubleshooting section below.
|
||||
|
||||
---
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
After setup, verify:
|
||||
|
||||
- [ ] ChatGPT shows "Connected" status for AegisGitea MCP
|
||||
- [ ] Test command "List my Gitea repositories" works
|
||||
- [ ] Audit logs show successful authentication:
|
||||
```bash
|
||||
docker-compose logs aegis-mcp | grep "api_authentication.*success"
|
||||
```
|
||||
- [ ] Can read file contents:
|
||||
```
|
||||
Show me the README.md file from org/repo-name
|
||||
```
|
||||
- [ ] Can browse repository structure:
|
||||
```
|
||||
What files are in the src/ directory of org/repo-name?
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example Commands
|
||||
|
||||
Once connected, try these commands in ChatGPT:
|
||||
|
||||
### Repository Discovery
|
||||
```
|
||||
What repositories do I have access to?
|
||||
List all my Gitea repositories
|
||||
Show me my private repositories
|
||||
```
|
||||
|
||||
### Repository Information
|
||||
```
|
||||
Tell me about the org/my-repo repository
|
||||
What's the default branch of org/my-repo?
|
||||
When was org/my-repo last updated?
|
||||
```
|
||||
|
||||
### File Operations
|
||||
```
|
||||
Show me the file tree of org/my-repo
|
||||
What files are in the src/ directory of org/my-repo?
|
||||
Read the README.md file from org/my-repo
|
||||
Show me the contents of src/main.py in org/my-repo
|
||||
```
|
||||
|
||||
### Code Understanding
|
||||
```
|
||||
Explain what the main function does in org/my-repo/src/main.py
|
||||
Summarize the architecture of org/my-repo
|
||||
What dependencies does org/my-repo use?
|
||||
Find all TODO comments in org/my-repo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: "Cannot connect to MCP server"
|
||||
|
||||
**Check 1: Server is running**
|
||||
```bash
|
||||
docker-compose ps
|
||||
docker-compose logs aegis-mcp
|
||||
```
|
||||
|
||||
**Check 2: Domain/URL is correct**
|
||||
```bash
|
||||
curl https://mcp.yourdomain.com/health
|
||||
# Should return: {"status": "healthy"}
|
||||
```
|
||||
|
||||
**Check 3: Firewall/Network**
|
||||
- Ensure port 443 is open
|
||||
- Check Traefik is routing correctly
|
||||
- Verify DNS resolves correctly
|
||||
|
||||
### Issue: "Authentication failed"
|
||||
|
||||
**Check 1: Authorization header format**
|
||||
|
||||
Correct:
|
||||
```
|
||||
Authorization: Bearer a1b2c3d4e5f6g7h8...
|
||||
```
|
||||
|
||||
Wrong:
|
||||
```
|
||||
Authorization: a1b2c3d4... (missing "Bearer ")
|
||||
Authorization: "Bearer a1b2c3d4..." (extra quotes)
|
||||
Authorization:Bearer a1b2c3d4... (missing space after colon)
|
||||
```
|
||||
|
||||
**Check 2: Key matches .env**
|
||||
```bash
|
||||
# Show configured keys (first 12 chars only for security)
|
||||
docker-compose exec aegis-mcp printenv MCP_API_KEYS | cut -c1-12
|
||||
```
|
||||
|
||||
Compare with your ChatGPT key (first 12 chars).
|
||||
|
||||
**Check 3: Server logs**
|
||||
```bash
|
||||
docker-compose logs aegis-mcp | tail -50
|
||||
```
|
||||
|
||||
Look for:
|
||||
- `invalid_api_key` → Key doesn't match
|
||||
- `missing_api_key` → Header not sent
|
||||
- `invalid_key_format` → Key too short
|
||||
|
||||
### Issue: "No repositories visible"
|
||||
|
||||
**Verify bot user has access:**
|
||||
|
||||
1. Log into Gitea
|
||||
2. Go to repository Settings > Collaborators
|
||||
3. Confirm bot user is listed with Read permission
|
||||
4. If not, add bot user as collaborator
|
||||
|
||||
**Test manually:**
|
||||
```bash
|
||||
curl -H "Authorization: Bearer YOUR_KEY" \
|
||||
https://mcp.yourdomain.com/mcp/tool/call \
|
||||
-X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"tool": "list_repositories", "arguments": {}}'
|
||||
```
|
||||
|
||||
### Issue: "Rate limited"
|
||||
|
||||
**Symptoms:**
|
||||
```
|
||||
Too many failed authentication attempts
|
||||
```
|
||||
|
||||
**Solution:**
|
||||
1. Wait 5 minutes
|
||||
2. Verify API key is correct
|
||||
3. Check audit logs:
|
||||
```bash
|
||||
docker-compose exec aegis-mcp grep "auth_rate_limit" /var/log/aegis-mcp/audit.log
|
||||
```
|
||||
4. If accidentally locked out:
|
||||
```bash
|
||||
docker-compose restart aegis-mcp
|
||||
```
|
||||
|
||||
### Issue: ChatGPT says "Tool not available"
|
||||
|
||||
**Verify tools are registered:**
|
||||
```bash
|
||||
curl -H "Authorization: Bearer YOUR_KEY" \
|
||||
https://mcp.yourdomain.com/mcp/tools
|
||||
```
|
||||
|
||||
Should return JSON with tools array.
|
||||
|
||||
---
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### 1. API Key Management
|
||||
|
||||
- ✅ Store key in password manager
|
||||
- ✅ Never share key in chat or messages
|
||||
- ✅ Rotate key every 90 days
|
||||
- ❌ Don't paste key in public ChatGPT conversations
|
||||
- ❌ Don't screenshot ChatGPT settings with key visible
|
||||
|
||||
### 2. Workspace Separation
|
||||
|
||||
If multiple team members:
|
||||
|
||||
```
|
||||
User A: Use key_a1b2c3...
|
||||
User B: Use key_b4c5d6...
|
||||
User C: Use key_c7d8e9...
|
||||
```
|
||||
|
||||
Configure in `.env`:
|
||||
```bash
|
||||
MCP_API_KEYS=key_a1b2c3...,key_b4c5d6...,key_c7d8e9...
|
||||
```
|
||||
|
||||
Each user configures their own ChatGPT with their specific key.
|
||||
|
||||
### 3. Monitoring Usage
|
||||
|
||||
Weekly check:
|
||||
```bash
|
||||
# Who's using the MCP server?
|
||||
docker-compose exec aegis-mcp grep "api_authentication" /var/log/aegis-mcp/audit.log | \
|
||||
grep "success" | \
|
||||
tail -20
|
||||
```
|
||||
|
||||
Look for `key_hint` to identify which key was used.
|
||||
|
||||
### 4. Incident Response
|
||||
|
||||
If key is compromised:
|
||||
|
||||
1. **Immediate:** Remove from `.env`
|
||||
```bash
|
||||
# Edit .env (remove compromised key)
|
||||
docker-compose restart aegis-mcp
|
||||
```
|
||||
|
||||
2. **Generate new key**
|
||||
```bash
|
||||
make generate-key
|
||||
```
|
||||
|
||||
3. **Update ChatGPT** with new key
|
||||
|
||||
4. **Check audit logs** for unauthorized access:
|
||||
```bash
|
||||
docker-compose exec aegis-mcp grep "key_hint: <compromised_key_hint>" /var/log/aegis-mcp/audit.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Custom MCP Tool Calls (For Developers)
|
||||
|
||||
You can call tools directly via API:
|
||||
|
||||
```bash
|
||||
# List repositories
|
||||
curl -X POST https://mcp.yourdomain.com/mcp/tool/call \
|
||||
-H "Authorization: Bearer YOUR_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"tool": "list_repositories",
|
||||
"arguments": {}
|
||||
}'
|
||||
|
||||
# Get file contents
|
||||
curl -X POST https://mcp.yourdomain.com/mcp/tool/call \
|
||||
-H "Authorization: Bearer YOUR_KEY" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"tool": "get_file_contents",
|
||||
"arguments": {
|
||||
"owner": "org",
|
||||
"repo": "my-repo",
|
||||
"filepath": "README.md"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### Webhook Integration (Future)
|
||||
|
||||
For automated workflows, you can integrate MCP tools into CI/CD:
|
||||
|
||||
```yaml
|
||||
# Example GitHub Actions (future enhancement)
|
||||
- name: Sync to Gitea via MCP
|
||||
run: |
|
||||
curl -X POST https://mcp.yourdomain.com/mcp/tool/call \
|
||||
-H "Authorization: Bearer ${{ secrets.MCP_API_KEY }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{...}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Tips
|
||||
|
||||
### 1. Rate Limiting Awareness
|
||||
|
||||
Traefik limits: **60 requests/minute**
|
||||
|
||||
For heavy usage:
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
labels:
|
||||
- "traefik.http.middlewares.aegis-ratelimit.ratelimit.average=120"
|
||||
```
|
||||
|
||||
### 2. Large Files
|
||||
|
||||
Files >1MB are rejected by default. To increase:
|
||||
|
||||
```bash
|
||||
# .env
|
||||
MAX_FILE_SIZE_BYTES=5242880 # 5MB
|
||||
```
|
||||
|
||||
### 3. Batch Operations
|
||||
|
||||
Instead of:
|
||||
```
|
||||
Show me file1.py
|
||||
Show me file2.py
|
||||
Show me file3.py
|
||||
```
|
||||
|
||||
Use:
|
||||
```
|
||||
Show me all Python files in the src/ directory
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Can I use this with Claude or other AI assistants?**
|
||||
|
||||
A: Currently optimized for ChatGPT Business, but the MCP protocol is standard. Other AI assistants with MCP support should work with the same configuration.
|
||||
|
||||
**Q: Do I need a separate key for each ChatGPT conversation?**
|
||||
|
||||
A: No. One key per user/workspace. All conversations in that workspace use the same key.
|
||||
|
||||
**Q: Can ChatGPT modify my repositories?**
|
||||
|
||||
A: **No**. AegisGitea MCP is read-only by design. ChatGPT can only read code, never write/commit/push.
|
||||
|
||||
**Q: What happens if I hit the rate limit?**
|
||||
|
||||
A: You'll receive a 429 error. Wait 1 minute and try again. The limit is per IP, not per key.
|
||||
|
||||
**Q: Can I use this from mobile ChatGPT app?**
|
||||
|
||||
A: Yes, if your ChatGPT Business account syncs to mobile. The MCP configuration follows your account.
|
||||
|
||||
**Q: How do I disconnect ChatGPT?**
|
||||
|
||||
A: Go to ChatGPT Settings > MCP Servers > Remove "AegisGitea MCP"
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Key Rotation Guide](KEY_ROTATION.md) - Rotate keys every 90 days
|
||||
- [Authentication Setup](AUTH_SETUP.md) - Detailed auth configuration
|
||||
- [Security Policy](SECURITY.md) - Best practices and threat model
|
||||
|
||||
---
|
||||
|
||||
**Happy coding with AI-assisted Gitea access!** 🚀
|
||||
Reference in New Issue
Block a user