636 lines
19 KiB
Markdown
636 lines
19 KiB
Markdown
# 🏗️ API-First Zero-Trust Architecture - Complete Guide
|
|
|
|
## 📋 Table of Contents
|
|
|
|
1. [Architecture Overview](#architecture-overview)
|
|
2. [Security Model](#security-model)
|
|
3. [Authentication Flows](#authentication-flows)
|
|
4. [RBAC & Permissions](#rbac--permissions)
|
|
5. [API Endpoints](#api-endpoints)
|
|
6. [Telegram Bot Integration](#telegram-bot-integration)
|
|
7. [Testing Strategy](#testing-strategy)
|
|
8. [Deployment](#deployment)
|
|
9. [Production Checklist](#production-checklist)
|
|
|
|
---
|
|
|
|
## 🏗️ Architecture Overview
|
|
|
|
### System Components
|
|
|
|
```
|
|
EXTERNAL CLIENTS (Web, Mobile, Bot)
|
|
↓
|
|
API GATEWAY (FastAPI)
|
|
↓
|
|
MIDDLEWARE STACK
|
|
├─ Security Headers
|
|
├─ Rate Limiting
|
|
├─ HMAC Verification
|
|
├─ JWT Authentication
|
|
├─ RBAC Authorization
|
|
└─ Request Logging
|
|
↓
|
|
DOMAIN SERVICES
|
|
├─ AuthService
|
|
├─ TransactionService
|
|
├─ WalletService
|
|
├─ BudgetService
|
|
└─ NotificationService
|
|
↓
|
|
REPOSITORY LAYER (SQLAlchemy)
|
|
↓
|
|
DATABASE + REDIS + MESSAGE QUEUE
|
|
```
|
|
|
|
### Key Principles
|
|
|
|
| Principle | Implementation |
|
|
|-----------|-----------------|
|
|
| **Zero-Trust** | Every request requires JWT + HMAC verification |
|
|
| **Immutability** | No direct record deletion; use reversals + audit logs |
|
|
| **Isolation** | Family-level data isolation at service layer |
|
|
| **Observability** | Every action logged to event_log + access_log |
|
|
| **Stateless** | API calls don't depend on session state |
|
|
|
|
---
|
|
|
|
## 🔐 Security Model
|
|
|
|
### Token Types
|
|
|
|
#### 1. **Access Token (JWT)**
|
|
- **Purpose:** Authenticate API requests
|
|
- **Lifetime:** 15 minutes
|
|
- **Scope:** Contains family_ids user can access
|
|
- **Usage:**
|
|
```
|
|
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
```
|
|
|
|
#### 2. **Refresh Token**
|
|
- **Purpose:** Issue new access tokens without re-login
|
|
- **Lifetime:** 30 days
|
|
- **Usage:**
|
|
```
|
|
POST /api/v1/auth/refresh
|
|
{ "refresh_token": "..." }
|
|
```
|
|
|
|
#### 3. **Service Token**
|
|
- **Purpose:** Telegram bot → API communication
|
|
- **Lifetime:** 1 year
|
|
- **Scope:** "telegram_bot" service
|
|
- **Note:** Different from user tokens; issued separately
|
|
|
|
### HMAC Signature Verification
|
|
|
|
**Base String Format:**
|
|
```
|
|
METHOD:ENDPOINT:TIMESTAMP:BODY_HASH
|
|
POST:/api/v1/transactions:1702237800:a3f5d8c2e1b9...
|
|
```
|
|
|
|
**Headers Required:**
|
|
```
|
|
X-Signature: HMAC_SHA256(base_string, client_secret)
|
|
X-Timestamp: 1702237800
|
|
X-Client-Id: telegram_bot|web_frontend|ios_app
|
|
```
|
|
|
|
**Verification Steps:**
|
|
1. Check timestamp freshness (±30 seconds)
|
|
2. Reconstruct base_string
|
|
3. Compute HMAC with client secret
|
|
4. Compare with X-Signature
|
|
5. Check signature nonce (prevent replay)
|
|
|
|
**MVP Default:** HMAC disabled (`require_hmac_verification=false`)
|
|
|
|
### Encryption Strategy
|
|
|
|
| Data | Encryption | Notes |
|
|
|------|-----------|-------|
|
|
| Password Hash | bcrypt | Never store plain passwords |
|
|
| Phone Number | AES-256 | At rest, logged as masked |
|
|
| Notes/Descriptions | None (MVP) | Can add AES-256 for sensitive notes |
|
|
| Transit | HTTPS TLS 1.2+ | Enforced in production |
|
|
|
|
---
|
|
|
|
## 🔑 Authentication Flows
|
|
|
|
### User Login Flow
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 1. User submits credentials │
|
|
│ POST /api/v1/auth/login │
|
|
│ { "email": "user@example.com", "password": "..." } │
|
|
└─────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 2. Server verifies password hash with bcrypt │
|
|
│ Load user → Load family_ids → Create tokens │
|
|
└─────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ 3. Response │
|
|
│ { │
|
|
│ "access_token": "eyJhbGc...", │
|
|
│ "refresh_token": "eyJhbGc...", │
|
|
│ "user_id": 123, │
|
|
│ "expires_in": 900 │
|
|
│ } │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Telegram Binding Flow
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ STEP 1: User sends /start │
|
|
│ Bot chat_id: 12345 │
|
|
└─────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ STEP 2: Bot generates binding code │
|
|
│ POST /api/v1/auth/telegram/start │
|
|
│ Response: { "code": "ABC123XYZ...", "expires_in": 600 } │
|
|
└─────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ STEP 3: Bot sends link to user │
|
|
│ "Click: https://app.com/auth/telegram?code=ABC123&... │
|
|
└─────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ STEP 4: User clicks link │
|
|
│ (User must be logged in or create account) │
|
|
│ POST /api/v1/auth/telegram/confirm │
|
|
│ { "code": "ABC123", "chat_id": 12345 } │
|
|
│ Headers: Authorization: Bearer <user_jwt> │
|
|
└─────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ STEP 5: Server creates TelegramIdentity record │
|
|
│ TelegramIdentity { │
|
|
│ user_id: 123, │
|
|
│ chat_id: 12345, │
|
|
│ verified_at: now │
|
|
│ } │
|
|
│ │
|
|
│ Generate JWT for bot usage │
|
|
│ Response: { "jwt_token": "..." } │
|
|
└─────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ STEP 6: Bot stores JWT in Redis │
|
|
│ Redis key: chat_id:12345:jwt │
|
|
│ Redis key: chat_id:12345:jwt:exp │
|
|
│ TTL: 30 days │
|
|
└─────────────────────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ STEP 7: Bot can now make API calls │
|
|
│ POST /api/v1/transactions │
|
|
│ Authorization: Bearer <jwt_from_redis> │
|
|
│ X-Client-Id: telegram_bot │
|
|
│ X-Signature: HMAC_SHA256(...) │
|
|
│ X-Timestamp: unixtime │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 👥 RBAC & Permissions
|
|
|
|
### Role Hierarchy
|
|
|
|
```
|
|
OWNER (Full Control)
|
|
└─ Can manage everything
|
|
└─ Can approve/reject large transactions
|
|
└─ Can manage members
|
|
└─ Can delete family
|
|
|
|
ADULT
|
|
└─ Can create/edit transactions
|
|
└─ Can approve transactions (with owner)
|
|
└─ Can create budgets/goals
|
|
└─ Can invite members
|
|
|
|
MEMBER
|
|
└─ Can create/view own transactions
|
|
└─ Can view budgets/goals
|
|
└─ Can view shared reports
|
|
|
|
CHILD
|
|
└─ Can create/view limited transactions
|
|
└─ Can view their allowance
|
|
└─ Very restricted permissions
|
|
|
|
READ_ONLY
|
|
└─ Can view reports only
|
|
└─ Audit/observer role
|
|
```
|
|
|
|
### Permission Examples
|
|
|
|
| Action | Owner | Adult | Member | Child | Read-Only |
|
|
|--------|-------|-------|--------|-------|-----------|
|
|
| Create Transaction | ✓ | ✓ | ✓ | ✓ (limited) | ✗ |
|
|
| Edit Own Transaction | ✓ | ✓ | ✓ | ✗ | ✗ |
|
|
| Edit Any Transaction | ✓ | ✗ | ✗ | ✗ | ✗ |
|
|
| Delete Transaction | ✓ | ✗ | ✗ | ✗ | ✗ |
|
|
| Approve Transaction | ✓ | ✓ | ✗ | ✗ | ✗ |
|
|
| Create Budget | ✓ | ✓ | ✗ | ✗ | ✗ |
|
|
| Manage Members | ✓ | ✗ | ✗ | ✗ | ✗ |
|
|
| View Audit Log | ✓ | ✓ | ✓ | ✗ | ✓ |
|
|
| Delete Family | ✓ | ✗ | ✗ | ✗ | ✗ |
|
|
|
|
### RBAC Implementation
|
|
|
|
**In Code:**
|
|
```python
|
|
# Check permission
|
|
RBACEngine.check_permission(user_context, Permission.CREATE_TRANSACTION)
|
|
|
|
# Check family access
|
|
RBACEngine.check_family_access(user_context, family_id=1)
|
|
|
|
# Check resource ownership
|
|
RBACEngine.check_resource_ownership(user_context, owner_id=123)
|
|
```
|
|
|
|
**In Endpoint:**
|
|
```python
|
|
@router.post("/transactions")
|
|
async def create_transaction(
|
|
request: TransactionCreateRequest,
|
|
user_context: UserContext = Depends(get_user_context),
|
|
):
|
|
# Middleware already verified JWT
|
|
# RBAC middleware already checked family access
|
|
# Now just check specific permission
|
|
|
|
RBACEngine.check_permission(
|
|
user_context,
|
|
Permission.CREATE_TRANSACTION
|
|
)
|
|
|
|
# Proceed with business logic
|
|
...
|
|
```
|
|
|
|
---
|
|
|
|
## 📡 API Endpoints
|
|
|
|
### Authentication
|
|
|
|
| Method | Endpoint | Purpose |
|
|
|--------|----------|---------|
|
|
| POST | `/api/v1/auth/login` | User login |
|
|
| POST | `/api/v1/auth/refresh` | Refresh access token |
|
|
| POST | `/api/v1/auth/logout` | Revoke session |
|
|
| POST | `/api/v1/auth/telegram/start` | Generate binding code |
|
|
| POST | `/api/v1/auth/telegram/confirm` | Confirm Telegram binding |
|
|
|
|
### Transactions
|
|
|
|
| Method | Endpoint | Purpose | Auth |
|
|
|--------|----------|---------|------|
|
|
| POST | `/api/v1/transactions` | Create transaction | JWT + HMAC |
|
|
| GET | `/api/v1/transactions` | List transactions | JWT |
|
|
| GET | `/api/v1/transactions/{id}` | Get transaction | JWT |
|
|
| POST | `/api/v1/transactions/{id}/confirm` | Approve pending | JWT + HMAC |
|
|
| DELETE | `/api/v1/transactions/{id}` | Reverse transaction | JWT + HMAC |
|
|
|
|
### Wallets
|
|
|
|
| Method | Endpoint | Purpose |
|
|
|--------|----------|---------|
|
|
| POST | `/api/v1/wallets` | Create wallet |
|
|
| GET | `/api/v1/wallets` | List wallets |
|
|
| GET | `/api/v1/wallets/summary` | Balance summary |
|
|
| PUT | `/api/v1/wallets/{id}` | Update wallet |
|
|
|
|
### Budgets & Goals
|
|
|
|
| Method | Endpoint | Purpose |
|
|
|--------|----------|---------|
|
|
| POST | `/api/v1/budgets` | Create budget |
|
|
| GET | `/api/v1/budgets` | List budgets |
|
|
| POST | `/api/v1/goals` | Create goal |
|
|
| GET | `/api/v1/goals` | List goals |
|
|
|
|
### Events & Webhooks
|
|
|
|
| Method | Endpoint | Purpose |
|
|
|--------|----------|---------|
|
|
| GET | `/api/v1/events/stream/{family_id}` | WebSocket event stream |
|
|
| POST | `/api/v1/events/webhook/telegram-notification` | Send Telegram notification |
|
|
|
|
---
|
|
|
|
## 🤖 Telegram Bot Integration
|
|
|
|
### Bot Commands
|
|
|
|
```
|
|
/start - Begin account binding
|
|
/help - Show available commands
|
|
/balance - View wallet balances
|
|
/add - Add new transaction
|
|
/reports - View financial reports
|
|
```
|
|
|
|
### Bot API Communication Pattern
|
|
|
|
```python
|
|
# Get user JWT from Redis
|
|
jwt_token = redis.get(f"chat_id:{chat_id}:jwt")
|
|
|
|
# Make API request
|
|
async with aiohttp.ClientSession() as session:
|
|
async with session.post(
|
|
"https://api.example.com/api/v1/transactions",
|
|
headers={
|
|
"Authorization": f"Bearer {jwt_token}",
|
|
"X-Client-Id": "telegram_bot",
|
|
"X-Signature": hmac_signature,
|
|
"X-Timestamp": str(timestamp),
|
|
},
|
|
json=payload,
|
|
) as response:
|
|
result = await response.json()
|
|
```
|
|
|
|
### Event Handling
|
|
|
|
```
|
|
Bot listens to Redis Streams:
|
|
- transaction.created
|
|
- budget.alert
|
|
- goal.completed
|
|
- member.joined
|
|
|
|
Bot processes events → Sends Telegram messages
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Testing Strategy
|
|
|
|
### Unit Tests
|
|
- JWT token generation/verification
|
|
- HMAC signature creation/verification
|
|
- RBAC permission checks
|
|
- Service business logic
|
|
|
|
### Integration Tests
|
|
- Full request → response cycles
|
|
- Authentication flows
|
|
- RBAC in middleware
|
|
- Database transactions
|
|
|
|
### Security Tests
|
|
- Invalid token rejection
|
|
- HMAC signature verification
|
|
- Timestamp freshness
|
|
- Signature replay prevention
|
|
- Family isolation
|
|
|
|
### Load Testing Example (k6)
|
|
|
|
```javascript
|
|
import http from 'k6/http';
|
|
import { check } from 'k6';
|
|
|
|
export let options = {
|
|
vus: 10,
|
|
duration: '30s',
|
|
};
|
|
|
|
export default function() {
|
|
let url = 'http://localhost:8000/api/v1/wallets';
|
|
let params = {
|
|
headers: {
|
|
'Authorization': `Bearer ${__ENV.JWT_TOKEN}`,
|
|
'X-Client-Id': 'k6_test',
|
|
},
|
|
};
|
|
|
|
let res = http.get(url, params);
|
|
check(res, {
|
|
'status is 200': (r) => r.status === 200,
|
|
'response time < 500ms': (r) => r.timings.duration < 500,
|
|
});
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Deployment
|
|
|
|
### Docker Compose (MVP)
|
|
|
|
```yaml
|
|
version: '3.9'
|
|
|
|
services:
|
|
api:
|
|
image: finance-bot:latest
|
|
ports:
|
|
- "8000:8000"
|
|
environment:
|
|
- DATABASE_URL=postgresql://...
|
|
- REDIS_URL=redis://redis:6379
|
|
- JWT_SECRET_KEY=...
|
|
- HMAC_SECRET_KEY=...
|
|
depends_on:
|
|
- postgres
|
|
- redis
|
|
networks:
|
|
- finance
|
|
|
|
bot:
|
|
image: finance-bot-bot:latest
|
|
environment:
|
|
- BOT_TOKEN=...
|
|
- API_BASE_URL=http://api:8000
|
|
- REDIS_URL=redis://redis:6379
|
|
depends_on:
|
|
- api
|
|
- redis
|
|
networks:
|
|
- finance
|
|
|
|
worker:
|
|
image: finance-bot-worker:latest
|
|
environment:
|
|
- REDIS_URL=redis://redis:6379
|
|
- DATABASE_URL=postgresql://...
|
|
depends_on:
|
|
- postgres
|
|
- redis
|
|
networks:
|
|
- finance
|
|
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
environment:
|
|
POSTGRES_DB: finance_db
|
|
POSTGRES_USER: trevor
|
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
|
volumes:
|
|
- pgdata:/var/lib/postgresql/data
|
|
networks:
|
|
- finance
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
networks:
|
|
- finance
|
|
|
|
volumes:
|
|
pgdata:
|
|
|
|
networks:
|
|
finance:
|
|
```
|
|
|
|
### Kubernetes Deployment (Future)
|
|
|
|
```yaml
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: api-config
|
|
data:
|
|
JWT_SECRET_KEY: <secret>
|
|
HMAC_SECRET_KEY: <secret>
|
|
DATABASE_URL: postgresql://postgres/finance_db
|
|
|
|
---
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: api-server
|
|
spec:
|
|
replicas: 3
|
|
template:
|
|
spec:
|
|
containers:
|
|
- name: api
|
|
image: finance-bot:latest
|
|
ports:
|
|
- containerPort: 8000
|
|
envFrom:
|
|
- configMapRef:
|
|
name: api-config
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /health
|
|
port: 8000
|
|
initialDelaySeconds: 10
|
|
periodSeconds: 5
|
|
```
|
|
|
|
---
|
|
|
|
## ✅ Production Checklist
|
|
|
|
### Security
|
|
- [ ] Change JWT_SECRET_KEY from default
|
|
- [ ] Change HMAC_SECRET_KEY from default
|
|
- [ ] Enable HTTPS/TLS (Nginx reverse proxy)
|
|
- [ ] Enable CORS only for approved origins
|
|
- [ ] Set require_hmac_verification=true
|
|
- [ ] Implement password hashing (bcrypt)
|
|
- [ ] Implement token blacklisting
|
|
- [ ] Add rate limiting (current: 100 req/min)
|
|
- [ ] Enable audit logging (EventLog)
|
|
- [ ] Encrypt sensitive data at rest
|
|
|
|
### Deployment
|
|
- [ ] Run migrations in production
|
|
- [ ] Set app_env="production"
|
|
- [ ] Disable debug mode
|
|
- [ ] Configure proper logging
|
|
- [ ] Set up monitoring/alerts
|
|
- [ ] Configure backup strategy
|
|
- [ ] Test failover procedures
|
|
- [ ] Document runbooks
|
|
|
|
### Testing
|
|
- [ ] Unit tests coverage > 80%
|
|
- [ ] Integration tests for critical flows
|
|
- [ ] Security testing (OWASP Top 10)
|
|
- [ ] Load testing (identify bottlenecks)
|
|
- [ ] Penetration testing
|
|
- [ ] API contract testing
|
|
|
|
### Operations
|
|
- [ ] Set up CI/CD pipeline
|
|
- [ ] Configure health check endpoints
|
|
- [ ] Set up application monitoring
|
|
- [ ] Configure database backups
|
|
- [ ] Document API in OpenAPI/Swagger
|
|
- [ ] Set up error tracking (Sentry)
|
|
- [ ] Implement graceful shutdown
|
|
|
|
---
|
|
|
|
## 📚 Additional Resources
|
|
|
|
### OpenAPI Specification
|
|
```bash
|
|
# Auto-generated from FastAPI
|
|
GET /docs # Swagger UI
|
|
GET /redoc # ReDoc documentation
|
|
GET /openapi.json # OpenAPI spec
|
|
```
|
|
|
|
### Architecture Decision Records (ADR)
|
|
- ADR-001: JWT + HMAC for authentication (not just JWT)
|
|
- ADR-002: Redis Streams for event bus (vs RabbitMQ)
|
|
- ADR-003: Compensation transactions for reversals
|
|
- ADR-004: Family-level isolation in all queries
|
|
|
|
### Performance Targets
|
|
- API response time: < 200ms (p95)
|
|
- Transaction creation: < 100ms
|
|
- List queries: < 500ms (for 1000 items)
|
|
- HMAC verification: < 5ms
|
|
- JWT verification: < 2ms
|
|
|
|
---
|
|
|
|
## 🔄 Roadmap (Post-MVP)
|
|
|
|
### Phase 2: Enhanced Features
|
|
- [ ] Web Frontend (React/Vue)
|
|
- [ ] Mobile App (React Native/Flutter)
|
|
- [ ] Advanced reporting (PDF export, charts)
|
|
- [ ] Recurring transactions
|
|
- [ ] Currency conversion
|
|
- [ ] Multi-family support
|
|
- [ ] User notifications preferences
|
|
|
|
### Phase 3: Enterprise Features
|
|
- [ ] Kubernetes deployment
|
|
- [ ] Multi-region failover
|
|
- [ ] Advanced RBAC (custom roles)
|
|
- [ ] Audit webhook integrations
|
|
- [ ] API rate limiting (per-user)
|
|
- [ ] Data export (GDPR compliance)
|
|
- [ ] SSO integration (OAuth2)
|
|
|
|
---
|
|
|
|
**Document Version:** 1.0
|
|
**Last Updated:** 2025-12-10
|
|
**Status:** MVP Complete
|