Xu ly SSO
This commit is contained in:
366
doc/DEPLOYMENT_GUIDE.md
Normal file
366
doc/DEPLOYMENT_GUIDE.md
Normal file
@@ -0,0 +1,366 @@
|
||||
# 🚀 Hướng dẫn Triển khai & Cấu hình Hệ thống
|
||||
|
||||
> Tài liệu này hướng dẫn cấu hình manual, biến môi trường, và các lưu ý khi triển khai từ PoC lên Production.
|
||||
|
||||
---
|
||||
|
||||
## 1. Cấu hình Azure AD App Registration (MANUAL)
|
||||
|
||||
### 1.1 Tạo App Registration (nếu chưa có)
|
||||
|
||||
1. Vào **Azure Portal** → **Azure Active Directory** → **App registrations** → **New registration**
|
||||
2. Điền thông tin:
|
||||
- **Name:** `VibeCode-RAG-PoC` (hoặc tên tuỳ chọn)
|
||||
- **Supported account types:** `Single tenant` (chỉ tenant công ty)
|
||||
- **Redirect URI:** Để trống, sẽ thêm sau
|
||||
3. Bấm **Register**
|
||||
4. Ghi lại:
|
||||
- **Application (client) ID** → dùng cho `CLIENT_ID`
|
||||
- **Directory (tenant) ID** → dùng cho `TENANT_ID`
|
||||
|
||||
### 1.2 Tạo Client Secret
|
||||
|
||||
1. App Registration → **Certificates & secrets** → **New client secret**
|
||||
2. Điền Description: `RAG PoC Secret`
|
||||
3. Chọn thời hạn: `24 months` (hoặc tuỳ nhu cầu)
|
||||
4. Bấm **Add**
|
||||
5. **Copy ngay giá trị Secret** → dùng cho `CLIENT_SECRET` (chỉ hiện 1 lần)
|
||||
|
||||
### 1.3 Cấp quyền Application Permissions
|
||||
|
||||
1. App Registration → **API permissions** → **Add a permission**
|
||||
2. Chọn **Microsoft Graph** → **Application permissions**
|
||||
3. Tìm và tích:
|
||||
- `Sites.Read.All` (đọc SharePoint sites)
|
||||
- `Files.Read.All` (đọc files trong drives)
|
||||
4. Bấm **Add permissions**
|
||||
5. **Quan trọng:** Bấm **Grant admin consent for [tenant]** → Confirm
|
||||
|
||||
### 1.4 Cấu hình Redirect URI cho SSO (khi cần login)
|
||||
|
||||
1. App Registration → **Authentication** → **Add a platform** → **Web**
|
||||
2. Nhập Redirect URI:
|
||||
- **PoC (localhost):** `http://localhost:8000/auth/callback`
|
||||
- **Production:** `https://your-domain.com/auth/callback`
|
||||
3. Tích chọn: ✅ **ID tokens** (implicit grant)
|
||||
4. Bấm **Save**
|
||||
|
||||
### 1.5 Kiểm tra Token Claims
|
||||
|
||||
Sau khi cấu hình xong, decode token JWT và kiểm tra:
|
||||
|
||||
```text
|
||||
aud : https://graph.microsoft.com
|
||||
appid : <client-id-của-bạn>
|
||||
idtyp : app
|
||||
roles :
|
||||
- Sites.Read.All
|
||||
- Files.Read.All
|
||||
```
|
||||
|
||||
Nếu token **không có `roles`** → quyền chưa đúng, kiểm tra lại bước 1.3.
|
||||
|
||||
---
|
||||
|
||||
## 2. Biến môi trường (.env)
|
||||
|
||||
### 2.1 File mẫu
|
||||
|
||||
```env
|
||||
# ===== Azure AD / Microsoft Graph =====
|
||||
TENANT_ID=your-tenant-id-guid
|
||||
CLIENT_ID=your-client-id-guid
|
||||
CLIENT_SECRET=your-client-secret-value
|
||||
|
||||
# ===== SharePoint =====
|
||||
# Site path để ingestion (đổi thành site SharePoint của bạn)
|
||||
# Format: hostname:/sites/site-name
|
||||
# Ví dụ: 285pdg.sharepoint.com:/sites/poc_system
|
||||
|
||||
# ===== OpenSearch =====
|
||||
OPENSEARCH_HOST=opensearch # Docker: "opensearch", Local: "localhost"
|
||||
OPENSEARCH_PORT=9200
|
||||
OPENSEARCH_USER=admin
|
||||
OPENSEARCH_PASS=admin
|
||||
|
||||
# ===== VLM OCR Server (Vintern-3B) =====
|
||||
VLM_ENDPOINT=http://10.202.50.3:8080/v1/chat/completions
|
||||
VLM_TEMPERATURE=0.1
|
||||
VLM_MAX_TOKENS=2000
|
||||
VLM_TIMEOUT=120.0
|
||||
|
||||
# ===== Chat LLM =====
|
||||
LLM_PROVIDER=gemini # Options: gemini, groq, local
|
||||
GEMINI_API_KEY=your-gemini-api-key
|
||||
GROQ_API_KEY=your-groq-api-key
|
||||
GROQ_MODEL=llama-3.3-70b-versatile
|
||||
LOCAL_LLM_ENDPOINT=http://10.202.50.3:8081/v1/chat/completions
|
||||
|
||||
# ===== General =====
|
||||
LOG_LEVEL=INFO
|
||||
ENVIRONMENT=development # development hoặc production
|
||||
```
|
||||
|
||||
### 2.2 Giải thích từng biến
|
||||
|
||||
| Biến | Bắt buộc | Mô tả |
|
||||
|------|----------|-------|
|
||||
| `TENANT_ID` | ✅ | Azure AD Tenant ID |
|
||||
| `CLIENT_ID` | ✅ | Azure AD App Registration Client ID |
|
||||
| `CLIENT_SECRET` | ✅ | Azure AD App Registration Client Secret |
|
||||
| `OPENSEARCH_HOST` | ✅ | Hostname OpenSearch |
|
||||
| `OPENSEARCH_PORT` | ✅ | Port OpenSearch (mặc định 9200) |
|
||||
| `VLM_ENDPOINT` | ✅ | URL server VLM OCR (Vintern-3B) |
|
||||
| `LLM_PROVIDER` | ✅ | LLM provider: `gemini`, `groq`, hoặc `local` |
|
||||
| `GEMINI_API_KEY` | Nếu dùng Gemini | API key từ Google AI Studio |
|
||||
| `GROQ_API_KEY` | Nếu dùng Groq | API key từ Groq Console |
|
||||
| `ENVIRONMENT` | ✅ | `development` hoặc `production` |
|
||||
|
||||
---
|
||||
|
||||
## 3. Kết nối SharePoint khác
|
||||
|
||||
### 3.1 Thay đổi Site Path
|
||||
|
||||
Chỉnh sửa trong file `ingestion/providers/sharepoint_provider.py`:
|
||||
|
||||
```python
|
||||
# Dòng 14 - Thay đổi hostname và site_path
|
||||
def __init__(self, hostname: str = "your-company.sharepoint.com", site_path: str = "/sites/your-site-name"):
|
||||
```
|
||||
|
||||
Hoặc gọi từ bên ngoài:
|
||||
|
||||
```python
|
||||
provider = SharePointProvider(
|
||||
hostname="your-company.sharepoint.com",
|
||||
site_path="/sites/your-site-name"
|
||||
)
|
||||
```
|
||||
|
||||
### 3.2 Kiểm tra quyền truy cập
|
||||
|
||||
App Registration phải có quyền trên site mới:
|
||||
1. Nếu dùng **Application Permissions** (`Sites.Read.All`) → tự động truy cập mọi site
|
||||
2. Nếu muốn giới hạn site cụ thể → dùng **SharePoint App-Only Policy** (nâng cao)
|
||||
|
||||
### 3.3 Xoá dữ liệu cũ
|
||||
|
||||
Khi đổi SharePoint site, cần xoá index cũ:
|
||||
|
||||
```bash
|
||||
curl -X DELETE -u admin:admin "http://localhost:9200/poc_sharepoint_docs"
|
||||
```
|
||||
|
||||
Sau đó chạy lại `python3 test_rag_pipeline.py` để nạp dữ liệu mới.
|
||||
|
||||
---
|
||||
|
||||
## 4. Triển khai Production
|
||||
|
||||
### 4.1 Yêu cầu hạ tầng
|
||||
|
||||
| Component | Yêu cầu tối thiểu | Khuyến nghị |
|
||||
|-----------|-------------------|-------------|
|
||||
| Server chính | 4 CPU, 8GB RAM | 8 CPU, 16GB RAM |
|
||||
| OpenSearch | 2 CPU, 4GB RAM | 4 CPU, 8GB RAM |
|
||||
| VLM OCR Server | GPU 8GB VRAM | GPU 16GB VRAM |
|
||||
| Domain | Có SSL certificate | Let's Encrypt |
|
||||
|
||||
### 4.2 Docker Compose Production
|
||||
|
||||
```yaml
|
||||
# docker-compose.prod.yml
|
||||
version: '3.8'
|
||||
services:
|
||||
opensearch:
|
||||
image: opensearchproject/opensearch:2.11.1
|
||||
environment:
|
||||
- discovery.type=single-node
|
||||
- OPENSEARCH_INITIAL_ADMIN_PASSWORD=StrongPassword123!
|
||||
ports:
|
||||
- "9200:9200"
|
||||
volumes:
|
||||
- opensearch-data:/usr/share/opensearch/data
|
||||
|
||||
rag-api:
|
||||
build: .
|
||||
ports:
|
||||
- "8000:8000"
|
||||
env_file: .env
|
||||
environment:
|
||||
- ENVIRONMENT=production
|
||||
- OPENSEARCH_HOST=opensearch
|
||||
depends_on:
|
||||
- opensearch
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./certs:/etc/nginx/certs
|
||||
- ./frontend:/usr/share/nginx/html
|
||||
depends_on:
|
||||
- rag-api
|
||||
|
||||
volumes:
|
||||
opensearch-data:
|
||||
```
|
||||
|
||||
### 4.3 Nginx config mẫu
|
||||
|
||||
```nginx
|
||||
# nginx.conf
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name your-domain.com;
|
||||
|
||||
ssl_certificate /etc/nginx/certs/fullchain.pem;
|
||||
ssl_certificate_key /etc/nginx/certs/privkey.pem;
|
||||
|
||||
# Frontend
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# API
|
||||
location /api/ {
|
||||
proxy_pass http://rag-api:8000/;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
# Redirect HTTP → HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 Thay đổi khi Production
|
||||
|
||||
1. **Frontend:** Sửa `API_BASE` trong `app.js`:
|
||||
```javascript
|
||||
const API_BASE = '/api'; // Thay vì 'http://localhost:8000'
|
||||
```
|
||||
|
||||
2. **SSO Redirect URI:** Cập nhật trong Azure AD:
|
||||
```
|
||||
https://your-domain.com/auth/callback
|
||||
```
|
||||
|
||||
3. **.env:**
|
||||
```env
|
||||
OPENSEARCH_HOST=opensearch
|
||||
ENVIRONMENT=production
|
||||
```
|
||||
|
||||
4. **OpenSearch password:** Đổi password mặc định:
|
||||
```env
|
||||
OPENSEARCH_USER=admin
|
||||
OPENSEARCH_PASS=YourStrongPassword123!
|
||||
```
|
||||
|
||||
5. **CORS:** Giới hạn origins trong `api/main.py`:
|
||||
```python
|
||||
allow_origins=["https://your-domain.com"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Kiểm tra sau triển khai
|
||||
|
||||
### 5.1 Kiểm tra kết nối
|
||||
|
||||
```bash
|
||||
# 1. OpenSearch
|
||||
curl -u admin:admin http://localhost:9200/_cluster/health
|
||||
|
||||
# 2. API
|
||||
curl http://localhost:8000/health
|
||||
|
||||
# 3. Frontend
|
||||
curl -I http://localhost/
|
||||
```
|
||||
|
||||
### 5.2 Kiểm tra SSO
|
||||
|
||||
1. Mở `https://your-domain.com`
|
||||
2. Bấm "Đăng nhập Microsoft SSO"
|
||||
3. Đăng nhập bằng tài khoản Microsoft 365
|
||||
4. Kiểm tra user info hiển thị đúng
|
||||
|
||||
### 5.3 Kiểm tra Pipeline
|
||||
|
||||
```bash
|
||||
# Trigger sync
|
||||
curl -X POST http://localhost:8000/sync
|
||||
|
||||
# Kiểm tra sync status
|
||||
curl http://localhost:8000/sync/status
|
||||
|
||||
# Kiểm tra chunks trong OpenSearch
|
||||
curl -u admin:admin http://localhost:9200/poc_sharepoint_docs/_count
|
||||
```
|
||||
|
||||
### 5.4 Kiểm tra ACL
|
||||
|
||||
```bash
|
||||
# Test search với user có quyền
|
||||
curl -X POST http://localhost:8000/chat \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-User-Email: user@yourcompany.com" \
|
||||
-H "X-User-Role: user" \
|
||||
-d '{"query": "test"}'
|
||||
|
||||
# Test search với admin (bypass ACL)
|
||||
curl -X POST http://localhost:8000/chat \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-User-Role: admin" \
|
||||
-d '{"query": "test"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Xử lý lỗi thường gặp
|
||||
|
||||
| Lỗi | Nguyên nhân | Giải pháp |
|
||||
|-----|-------------|-----------|
|
||||
| SSO redirect_uri_mismatch | Redirect URI chưa đúng | Kiểm tra URI trong Azure AD khớp với callback URL |
|
||||
| Token không có `roles` | App dùng Delegated thay vì Application permissions | Đổi sang Application permissions + Grant admin consent |
|
||||
| OpenSearch connection refused | Chưa khởi động Docker | `docker-compose up -d opensearch` |
|
||||
| VLM OCR timeout | Server VLM quá tải hoặc offline | Kiểm tra `VLM_ENDPOINT` có truy cập được |
|
||||
| Search trả 0 kết quả | Chưa nạp dữ liệu hoặc sai index name | Chạy `python3 test_rag_pipeline.py` |
|
||||
|
||||
---
|
||||
|
||||
## 7. Checklist trước khi Production
|
||||
|
||||
- [ ] Azure AD App Registration đã cấu hình đúng permissions
|
||||
- [ ] Client Secret còn hạn sử dụng
|
||||
- [ ] Redirect URI đã thêm cho production domain
|
||||
- [ ] OpenSearch đã đổi password mặc định
|
||||
- [ ] SSL certificate đã cài đặt
|
||||
- [ ] CORS đã giới hạn origins
|
||||
- [ ] `.env` đã cấu hình cho production
|
||||
- [ ] Docker Compose production đã test
|
||||
- [ ] Backup strategy cho OpenSearch data
|
||||
- [ ] Monitoring (CPU, RAM, disk) đã setup
|
||||
|
||||
---
|
||||
|
||||
*Tài liệu này cần được cập nhật khi có thay đổi về hạ trúc hoặc cấu hình.*
|
||||
Reference in New Issue
Block a user