Credential Management¶
This document details the credential management practices for Project Aegis.
Directory Structure¶
All credentials are stored in the ~/.secure/ directory with restricted permissions:
~/.secure/
├── .env # Main environment file (600 permissions)
├── api_keys/ # API key subdirectory
├── aegis_api_key # Aegis dashboard API key
├── meshy-api-key # Meshy 3D generation API
├── meshy_webhook_secret # Meshy webhook validation
├── perplexity_api_key # Perplexity AI API
├── replicate-api-key # Replicate model inference
├── restic-password # Backup encryption password
├── service-passwords.txt # Service passwords index
├── starling-token # Starling Bank API token
├── stripe.env # Stripe API keys
├── stripe-intel-config.json # Intel dashboard Stripe config
├── stripe-services-config.json # Services API Stripe config
├── oauth_all_google.py # Google OAuth helper
└── exchange_all_google.py # Google token exchange helper
Security: The ~/.secure/ directory has 700 permissions (owner read/write/execute only).
Environment File Structure¶
~/.secure/.env¶
The main .env file contains credentials organized by service:
# Z.ai API Configuration (GLM-4.7)
ZAI_API_KEY=<key>
ZAI_BASE_URL=https://api.z.ai/api/anthropic/v1
# Ollama Configuration
OLLAMA_HOST=http://127.0.0.1:11434
OLLAMA_KEEP_ALIVE=5m
# PostgreSQL
POSTGRES_USER=agent
POSTGRES_PASSWORD=agent
POSTGRES_DB=aegis
# Discord
DISCORD_BOT_TOKEN=<token>
DISCORD_GUILD_ID=<guild_id>
DISCORD_CHANNEL_GENERAL=<channel_id>
# GitHub
GITHUB_TOKEN=<personal_access_token>
# Telegram
TELEGRAM_BOT_TOKEN=<token>
TELEGRAM_CHAT_ID=<chat_id>
# Vonage/WhatsApp
VONAGE_API_KEY=<key>
VONAGE_API_SECRET=<secret>
VONAGE_APPLICATION_ID=<app_id>
VONAGE_WHATSAPP_NUMBER=<number>
VONAGE_PRIVATE_KEY_B64=<base64_encoded_private_key>
VONAGE_SIGNATURE_SECRET=<secret>
# Email/Resend
RESEND_API_KEY=<key>
# Perplexity AI
PERPLEXITY_API_KEY=<key>
# Meshy 3D
MESHY_API_KEY=<key>
MESHY_WEBHOOK_SECRET=<secret>
# Stripe (Payment Processing)
STRIPE_SECRET_KEY=<key>
STRIPE_WEBHOOK_SECRET=<secret>
STRIPE_PRICE_DEVELOPER=<price_id>
STRIPE_PRICE_PRO=<price_id>
STRIPE_PRICE_ENTERPRISE=<price_id>
# Anna's Archive
ANNAS_SECRET_KEY=<key>
ANNAS_BASE_URL=https://annas-archive.li
# Knowledge Graph (FalkorDB)
FALKORDB_HOST=host.docker.internal
FALKORDB_PORT=6379
Project-Level .env¶
A separate .env file exists at /home/agent/projects/aegis-core/.env for project-specific overrides (gitignored).
MCP Server Configuration¶
MCP servers are configured in ~/.claude.json with inline credentials:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "<token>"
}
},
"discord": {
"command": "npx",
"args": ["-y", "mcp-discord"],
"env": {
"DISCORD_BOT_TOKEN": "<token>"
}
},
"telegram": {
"command": "npx",
"args": ["-y", "@iqai/mcp-telegram"],
"env": {
"TELEGRAM_BOT_TOKEN": "<token>"
}
},
"stackwiz": {
"command": "/home/agent/.local/share/pipx/venvs/stackwiz-mcp/bin/stackwiz-mcp",
"env": {
"STACKWIZ_CF_API_TOKEN": "<cloudflare_token>",
"STACKWIZ_BASE_DIR": "/home/agent/stacks",
"STACKWIZ_DEFAULT_DOMAIN": "rbnk.uk"
}
}
}
}
API Key Rotation¶
Procedure¶
- Generate new key from service provider
- Update in ~/.secure/.env (or specific key file)
- Update in ~/.claude.json if MCP-related
- Restart affected services:
- Verify functionality with health checks
- Revoke old key from service provider
- Document rotation in
/home/agent/memory/security/key-rotation.jsonl
Rotation Schedule¶
| Service | Frequency | Last Rotated |
|---|---|---|
| GitHub PAT | 90 days | Check token expiry |
| Discord Bot | Annually | On compromise |
| Telegram Bot | Annually | On compromise |
| Stripe Keys | Manually | On security event |
| Z.ai API Key | Quarterly | Based on usage |
| Vonage Keys | Manually | On security event |
Docker Compose Secret Injection¶
Services receive credentials via environment variables loaded from .env:
services:
dashboard:
environment:
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY:-}
- VONAGE_API_KEY=${VONAGE_API_KEY:-}
- GITHUB_TOKEN=${GITHUB_TOKEN:-}
The :- syntax provides empty fallback if variable is unset (prevents container crashes).
Never Commit Secrets Policy¶
Protected Files¶
The following patterns are automatically blocked by the block-sensitive-files.py hook:
*.pem(SSL certificates, private keys)*.key(Private keys)id_rsa,id_ed25519(SSH keys).env,.env.*(Environment files) - warned but allowed for config work- Files in
/.secure/- warned but allowed for automation credentials,*credentials*- warned but allowed.claude.json- warned but allowed for MCP setup
Git Configuration¶
.gitignore patterns:
# Credentials
.env
.env.*
.secure/
*credentials*
*.pem
*.key
id_rsa*
id_ed25519*
# MCP config with inline tokens
.claude.json
Pre-Commit Verification¶
Before committing:
- Run
git diffand manually review for secrets - Check that hook didn't warn about sensitive files
- Verify
.gitignorecatches new credential files - Use
git-secretsorgitleaksfor automated scanning (optional)
Service-Specific Credentials¶
GitHub Personal Access Token¶
Scopes required:
- repo (full control of private repositories)
- workflow (update GitHub Actions workflows)
- read:org (read org and team membership)
Located: ~/.secure/.env (GITHUB_TOKEN)
Discord Bot Token¶
Permissions required: - Send Messages - Read Message History - Embed Links
Located: ~/.secure/.env (DISCORD_BOT_TOKEN)
Vonage/WhatsApp¶
Multi-component authentication:
- VONAGE_API_KEY - Account API key
- VONAGE_API_SECRET - Account API secret
- VONAGE_APPLICATION_ID - Messages API application
- VONAGE_PRIVATE_KEY_B64 - Base64-encoded private key for JWT signing
- VONAGE_SIGNATURE_SECRET - Webhook signature validation
Located: ~/.secure/.env
Stripe API Keys¶
Separate keys for test and production:
- STRIPE_SECRET_KEY - Main secret key (live mode)
- STRIPE_WEBHOOK_SECRET - Webhook signature validation
- STRIPE_PRICE_* - Price IDs for subscription tiers
Located: ~/.secure/stripe.env (loaded by dashboard)
Emergency Response¶
If Credentials Are Compromised¶
- IMMEDIATELY revoke the compromised key/token from the service provider
- Generate a new credential
- Update in
~/.secure/.envand~/.claude.json - Restart services:
cd /home/agent/projects/aegis-core && docker compose restart - Document incident in
/home/agent/memory/security/incidents.jsonl - Post to Discord #alerts channel
- Review recent logs for suspicious activity:
Incident Template¶
{
"timestamp": "2026-01-25T12:00:00Z",
"severity": "critical|high|medium|low",
"credential_type": "github_token|discord_bot|etc",
"impact": "Description of exposure",
"response": [
"Revoked key at 12:05 UTC",
"Generated new key at 12:10 UTC",
"Services restarted at 12:15 UTC"
],
"root_cause": "Accidental commit|Log exposure|etc",
"prevention": "Added .gitignore rule|Implemented hook|etc"
}
Best Practices¶
- Least Privilege: Request minimum scopes needed for each API token
- Expiration: Use short-lived tokens when supported (e.g., GitHub PAT expiry)
- Rotation: Rotate critical keys quarterly, all keys annually
- Isolation: Never share credentials between environments (dev/prod)
- Audit Logging: All credential usage is logged to
~/memory/security/mcp-audit.jsonl - Backup Security: Encrypted backups use
~/.secure/restic-password - No Hardcoding: Never hardcode credentials in source files
- MCP Audit: Review MCP security audit logs weekly for anomalies
- Access Review: Quarterly review of which services have access to what
- Documentation: Update this file when adding new credential types
Audit Trail¶
All credential access via MCP tools is logged by the mcp-security-audit.py hook:
{
"timestamp": "2026-01-25T12:00:00Z",
"session_id": "abc123",
"mcp_server": "github",
"operation": "create_repository",
"risk_level": "medium",
"flagged": false
}
Location: ~/memory/security/mcp-audit.jsonl
Review flagged operations: