375 lines
14 KiB
Markdown
375 lines
14 KiB
Markdown
# 📐 Architecture Secure Proxy
|
||
|
||
## Vue d'Ensemble
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ Internet / External Users │
|
||
└────────────────────────────┬────────────────────────────────────┘
|
||
│ https://secure.k2r.ovh
|
||
│
|
||
┌────────▼────────┐
|
||
│ Nginx/SSL │
|
||
│ (Reverse Proxy)│
|
||
└────────┬────────┘
|
||
│ http://localhost:3000
|
||
┌────────────────────▼──────────────────────┐
|
||
│ Secure Proxy (Node.js) │
|
||
│ ┌──────────────────────────────────────┐ │
|
||
│ │ Express Server │ │
|
||
│ │ - OIDC Authentication (Keycloak) │ │
|
||
│ │ - Session Management │ │
|
||
│ │ - Rate Limiting & Security │ │
|
||
│ └──────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌──────────────────────────────────────┐ │
|
||
│ │ Routes │ │
|
||
│ │ - /auth/* (Authentification) │ │
|
||
│ │ - /api/* (Admin API) │ │
|
||
│ │ - /admin (Panel Admin) │ │
|
||
│ │ - /* (Reverse Proxy) │ │
|
||
│ └──────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌──────────────────────────────────────┐ │
|
||
│ │ Middleware │ │
|
||
│ │ - OIDC Middleware │ │
|
||
│ │ - Proxy Middleware │ │
|
||
│ │ - Security Middleware │ │
|
||
│ └──────────────────────────────────────┘ │
|
||
│ │
|
||
│ ┌──────────────────────────────────────┐ │
|
||
│ │ Database (SQLite) │ │
|
||
│ │ - Services Management │ │
|
||
│ │ - Audit Logs │ │
|
||
│ │ - Access Logs │ │
|
||
│ └──────────────────────────────────────┘ │
|
||
└──────────────┬──────────────┬──────────────┘
|
||
│ │
|
||
┌──────────────▼──┐ ┌───────▼──────────────┐
|
||
│ Keycloak OIDC │ │ Internal Services │
|
||
│ (Authentication)│ │ - API Server │
|
||
│ │ │ - Grafana │
|
||
└─────────────────┘ │ - React App │
|
||
│ - Custom Services │
|
||
└─────────────────────┘
|
||
```
|
||
|
||
## Structure des Fichiers
|
||
|
||
```
|
||
openidv2/
|
||
│
|
||
├── 📁 src/ # Code source principal
|
||
│ ├── server.js # Serveur Express principal
|
||
│ ├── config.js # Configuration centralisée
|
||
│ ├── db.js # Gestion SQLite
|
||
│ │
|
||
│ ├── 📁 middleware/
|
||
│ │ ├── oidcMiddleware.js # Authentification OIDC/Keycloak
|
||
│ │ ├── security.js # Rate limit, CSRF, headers, logs
|
||
│ │ └── proxyMiddleware.js # Logique du reverse proxy
|
||
│ │
|
||
│ ├── 📁 routes/
|
||
│ │ ├── authRoutes.js # Routes d'authentification
|
||
│ │ ├── adminRoutes.js # API admin (CRUD services)
|
||
│ │ └── dashboardRoutes.js # Routes dashboard
|
||
│ │
|
||
│ ├── 📁 controllers/
|
||
│ │ ├── authController.js # Logique auth (login, callback)
|
||
│ │ ├── serviceController.js # CRUD des services
|
||
│ │ └── adminController.js # Stats et logs
|
||
│ │
|
||
│ ├── 📁 services/
|
||
│ │ └── serviceManager.js # Business logic (DB interactions)
|
||
│ │
|
||
│ └── 📁 utils/
|
||
│ └── logger.js # Logging centralisé
|
||
│
|
||
├── 📁 public/
|
||
│ └── admin.html # Interface admin (UI complète)
|
||
│
|
||
├── 📁 db/
|
||
│ └── services.db # Base de données SQLite
|
||
│
|
||
├── 📁 scripts/
|
||
│ ├── initDb.js # Initialiser la DB
|
||
│ └── seedDb.js # Charger données d'exemple
|
||
│
|
||
├── 📁 sessions/ # Sessions utilisateur (créé à runtime)
|
||
│
|
||
├── Configuration
|
||
│ ├── .env # Variables d'environnement
|
||
│ ├── .env.example # Modèle de configuration
|
||
│ ├── package.json # Dépendances Node.js
|
||
│ ├── docker-compose.yml # Stack Docker (dev)
|
||
│ ├── Dockerfile # Image Docker
|
||
│ └── nginx.example.conf # Config Nginx
|
||
│
|
||
└── Documentation
|
||
├── README.md # Documentation complète
|
||
├── INSTALLATION.md # Guide installation détaillé
|
||
├── QUICKSTART.md # Démarrage rapide
|
||
├── ARCHITECTURE.md # Ce fichier
|
||
└── test-api.sh # Tests API
|
||
```
|
||
|
||
## Flux de Requête
|
||
|
||
### 1️⃣ Authentification OIDC
|
||
|
||
```
|
||
Utilisateur → http://localhost:3000/
|
||
↓
|
||
Pas d'authentification ?
|
||
↓
|
||
Redirect → /auth/login
|
||
↓
|
||
Utilisateur clique "Login"
|
||
↓
|
||
GET /auth/login
|
||
↓
|
||
Redirect vers Keycloak Authorization Endpoint
|
||
↓
|
||
Utilisateur s'authentifie sur Keycloak
|
||
↓
|
||
Keycloak redirige vers /callback avec code
|
||
↓
|
||
POST /auth/callback
|
||
↓
|
||
Exchange code → Token
|
||
↓
|
||
Récupérer userInfo
|
||
↓
|
||
Créer session utilisateur
|
||
↓
|
||
Redirect vers page demandée originalement
|
||
```
|
||
|
||
### 2️⃣ Accès à un Service Protégé
|
||
|
||
```
|
||
Utilisateur (authentifié) → GET /myapp
|
||
↓
|
||
Trouve service dans DB
|
||
↓
|
||
Service nécessite auth ?
|
||
↓
|
||
Utilisateur a session ?
|
||
↓
|
||
OUI → Proxifier vers target
|
||
↓
|
||
Utilisateur (anonyme) → GET /public
|
||
↓
|
||
Service trouvé
|
||
↓
|
||
Service nécessite auth ?
|
||
↓
|
||
NON → Proxifier directement
|
||
```
|
||
|
||
### 3️⃣ Management Admin
|
||
|
||
```
|
||
Admin → GET /admin
|
||
↓
|
||
Vérifier : req.session.user.isAdmin ?
|
||
↓
|
||
NON → 403 Forbidden
|
||
↓
|
||
OUI → Servir interface admin.html
|
||
↓
|
||
Admin clique "+ New Service"
|
||
↓
|
||
POST /api/services (avec CSRF token)
|
||
↓
|
||
Valider les données
|
||
↓
|
||
Insérer dans DB
|
||
↓
|
||
Log action d'audit
|
||
↓
|
||
Retourner service créé
|
||
↓
|
||
Réponse affichée dans l'UI
|
||
```
|
||
|
||
## Flux de Données
|
||
|
||
### Services Table (SQLite)
|
||
|
||
```sql
|
||
services {
|
||
id VARCHAR PRIMARY KEY -- UUID unique
|
||
name VARCHAR UNIQUE -- Nom du service
|
||
path VARCHAR UNIQUE -- Chemin public (/myapp)
|
||
target_url VARCHAR -- URL cible (http://localhost:8080)
|
||
require_auth BOOLEAN -- Authentification requise ?
|
||
description TEXT -- Description
|
||
enabled BOOLEAN -- Service actif ?
|
||
created_at DATETIME -- Date création
|
||
updated_at DATETIME -- Date modification
|
||
}
|
||
```
|
||
|
||
### Audit Logs Table
|
||
|
||
```sql
|
||
audit_logs {
|
||
id INTEGER PRIMARY KEY AUTO_INCREMENT
|
||
action VARCHAR -- SERVICE_CREATED, UPDATED, DELETED
|
||
user_id VARCHAR -- ID Keycloak de l'admin
|
||
service_id VARCHAR FK -- Service affecté
|
||
ip_address VARCHAR -- IP de l'admin
|
||
details JSON -- Détails (données modifiées)
|
||
timestamp DATETIME -- Quand
|
||
}
|
||
```
|
||
|
||
### Access Logs Table
|
||
|
||
```sql
|
||
access_logs {
|
||
id INTEGER PRIMARY KEY AUTO_INCREMENT
|
||
service_id VARCHAR FK -- Service accédé
|
||
user_id VARCHAR -- Utilisateur (si auth)
|
||
path VARCHAR -- Chemin complet
|
||
method VARCHAR -- GET, POST, etc.
|
||
status_code INTEGER -- Code réponse (200, 404, etc.)
|
||
response_time_ms INTEGER -- Temps réponse en ms
|
||
ip_address VARCHAR -- IP du client
|
||
timestamp DATETIME -- Quand
|
||
}
|
||
```
|
||
|
||
## Flux de Sécurité
|
||
|
||
### OIDC Flow (Authorization Code)
|
||
|
||
```
|
||
┌─────────────┐ ┌────────────────┐ ┌──────────────┐
|
||
│ Browser │ │ Secure Proxy │ │ Keycloak │
|
||
└──────┬──────┘ └────────┬───────┘ └──────┬───────┘
|
||
│ │ │
|
||
│──GET /auth/login───────►│ │
|
||
│ │──GET /auth/authorize│
|
||
│ │ (with state, nonce)─►│
|
||
│ │ │
|
||
│◄────────────────────────────────────────Redirect with code
|
||
│ (to /callback) │ │
|
||
│ │ │
|
||
│──GET /callback?code────►│ │
|
||
│ │──POST token───────►│
|
||
│ │◄──ID+Access Token──│
|
||
│ │ │
|
||
│◄────User data in session| │
|
||
│ │ │
|
||
```
|
||
|
||
### Rate Limiting & Security
|
||
|
||
```
|
||
Request → Check IP in rate limit store
|
||
↓
|
||
Count exceeded ?
|
||
↓
|
||
OUI → 429 Too Many Requests
|
||
↓
|
||
NON → Continue
|
||
↓
|
||
CSRF check (POST/PUT/DELETE)
|
||
↓
|
||
Security headers added
|
||
↓
|
||
Request logged
|
||
↓
|
||
Response sent
|
||
```
|
||
|
||
## Performance & Scalabilité
|
||
|
||
### Optimisations Actuelles
|
||
|
||
- **Reverse Proxy** : http-proxy avec streaming
|
||
- **Rate Limiting** : En-mémoire (scalable avec Redis)
|
||
- **Logs** : SQLite (adapté pour small-medium)
|
||
- **Sessions** : File-based (pour dev)
|
||
|
||
### Pour la Production
|
||
|
||
```
|
||
┌─────────────┐
|
||
│ Nginx │ ← Load balancer + SSL termination
|
||
└─────┬───────┘
|
||
│
|
||
├─► [Proxy 1] ←► Redis (sessions)
|
||
├─► [Proxy 2] ←► +
|
||
└─► [Proxy 3] ←► PostgreSQL (logs & services)
|
||
```
|
||
|
||
## Sécurité en Couches
|
||
|
||
### Couche 1 : Transport
|
||
- SSL/TLS avec Nginx
|
||
- HSTS headers
|
||
|
||
### Couche 2 : Authentification
|
||
- OIDC avec Keycloak
|
||
- Sessions sécurisées (httpOnly, sameSite)
|
||
|
||
### Couche 3 : Autorisation
|
||
- Vérification admin pour /admin et /api
|
||
- Service auth check avant proxy
|
||
|
||
### Couche 4 : Validation
|
||
- CSRF tokens
|
||
- Input validation sur tous les endpoints
|
||
- SQL injections protection (parameterized queries)
|
||
|
||
### Couche 5 : Monitoring
|
||
- Audit logs de toutes les actions
|
||
- Access logs de tous les services
|
||
- Rate limiting anti-DDoS
|
||
|
||
## Extensibilité
|
||
|
||
### Ajouter un Nouveau Middleware
|
||
|
||
```javascript
|
||
// 1. Créer src/middleware/myMiddleware.js
|
||
export function myMiddleware(req, res, next) {
|
||
// Your logic
|
||
next();
|
||
}
|
||
|
||
// 2. Dans server.js
|
||
import { myMiddleware } from './middleware/myMiddleware.js';
|
||
app.use(myMiddleware);
|
||
```
|
||
|
||
### Ajouter une Nouvelle Route
|
||
|
||
```javascript
|
||
// 1. Créer route handler
|
||
export function myHandler(req, res) {
|
||
res.json({ message: 'Hello' });
|
||
}
|
||
|
||
// 2. Créer route file src/routes/myRoutes.js
|
||
const router = express.Router();
|
||
router.get('/myendpoint', myHandler);
|
||
|
||
// 3. Dans server.js
|
||
import myRoutes from './routes/myRoutes.js';
|
||
app.use('/api/my', myRoutes);
|
||
```
|
||
|
||
### Modifier l'UI Admin
|
||
|
||
- Éditer `public/admin.html`
|
||
- Ajouter sections, boutons, formulaires
|
||
- Le JavaScript charge automatiquement l'API
|
||
|
||
---
|
||
|
||
**Architecture modulaire, sécurisée et extensible** ✨
|