Files
LiquidCode.Tester/ISOLATE_INTEGRATION.md
2025-11-04 20:22:51 +04:00

312 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Isolate Sandbox Integration
## Обзор
Интеграция Isolate sandbox обеспечивает безопасное выполнение пользовательского кода с изоляцией на уровне ядра Linux.
## Что было сделано
### 1. Docker Security Hardening
**compose.yaml:**
- ✅ Gateway: `cap_drop: ALL`, `no-new-privileges:true`
- ✅ Worker: `cap_drop: ALL` + минимальные capabilities (`SYS_ADMIN`, `SETUID`, `SETGID`)
- ✅ Worker: `tmpfs` для `/tmp` (4GB)
- ✅ Worker: `ulimits` (nproc: 1024, nofile: 2048)
- ✅ AppArmor profile
### 2. Worker Dockerfile
**Установлено:**
- ✅ Isolate sandbox (с libcap-dev, libsystemd-dev)
- ✅ Unprivileged user `workeruser` (uid: 1001)
- ✅ Конфигурация isolate (`/usr/local/etc/isolate`)
**Структура:**
```
/var/local/lib/isolate/ - Isolate box root
/app/ - Worker приложение (chown workeruser)
/tmp/testing/ - Temp directory (chown workeruser)
```
### 3. Новые сервисы
**`IsolateService`** - Основной сервис для работы с Isolate:
- `InitBoxAsync(boxId)` - Инициализация sandbox
- `RunAsync(options)` - Выполнение программы
- `CleanupBoxAsync(boxId)` - Очистка sandbox
- Парсинг metadata (CPU time, memory, context switches)
**`IsolateBoxPool`** - Управление параллельными box'ами:
- Пул из N box IDs (конфигурируется)
- Thread-safe acquire/release
- Автоматическое ожидание при занятости всех box'ов
**`CppExecutionServiceIsolate`** - Реализация IExecutionService с Isolate:
- Копирование executable в box
- Выполнение с ограничениями (CPU, memory, processes)
- Mapping результатов Isolate → ExecutionResult
### 4. Конфигурация
**appsettings.json:**
```json
{
"Isolate": {
"Enabled": true,
"MaxBoxes": 100
}
}
```
**Environment переменные (compose.yaml):**
```yaml
environment:
- Isolate__Enabled=true
- Isolate__MaxBoxes=100
```
## Что защищает Isolate
| Угроза | Без Isolate | С Isolate |
|--------|-------------|-----------|
| Fork bomb | ❌ Убьёт контейнер | ✅ БЛОК (process limit) |
| Network attack | ❌ Полный доступ | ✅ БЛОК (no network) |
| File access | ❌ Видит весь контейнер | ✅ БЛОК (mount namespace) |
| Memory bomb | ⚠️ Неточно (PeakWorkingSet64) | ✅ ТОЧНО (cgroups) |
| CPU bomb | ⚠️ Wall time | ✅ CPU time (справедливо) |
| Syscall abuse | ❌ Любые syscalls | ✅ ФИЛЬТР (seccomp) |
## Архитектура безопасности
```
┌─────────────────────────────────────────────┐
│ HOST OS (Linux) │
│ ┌───────────────────────────────────────┐ │
│ │ Docker Container (Worker) │ │
│ │ • cap_drop: ALL │ │
│ │ • no-new-privileges │ │
│ │ • AppArmor │ │
│ │ │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ Worker Process (uid 1001) │ │ │
│ │ │ │ │ │
│ │ │ ┌───────────────────────────┐ │ │ │
│ │ │ │ Isolate Box │ │ │ │
│ │ │ │ • PID namespace │ │ │ │
│ │ │ │ • Network isolation │ │ │ │
│ │ │ │ • Mount namespace │ │ │ │
│ │ │ │ • cgroups (CPU, mem) │ │ │ │
│ │ │ │ • seccomp-bpf │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ USER CODE RUNS HERE │ │ │ │
│ │ │ └───────────────────────────┘ │ │ │
│ │ └─────────────────────────────────┘ │ │
│ └───────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
```
## Тестирование
### Запуск с Isolate
```bash
# 1. Rebuild контейнеров
docker-compose down
docker-compose build --no-cache worker
docker-compose up
# 2. Проверка установки Isolate
docker exec liquidcode-tester-worker isolate --version
# 3. Проверка прав
docker exec liquidcode-tester-worker whoami # должно быть: workeruser
# 4. Проверка box директории
docker exec liquidcode-tester-worker ls -la /var/local/lib/isolate
```
### Тестовые сценарии
#### 1. Простая программа (C++)
```bash
curl -X POST http://localhost:8081/api/test \
-F "id=1" \
-F "missionId=100" \
-F "language=c++" \
-F "sourceCode=#include <iostream>
int main() { std::cout << \"Hello World\"; }" \
-F "callbackUrl=http://localhost/callback" \
-F "package=@test_package.zip"
```
#### 2. Fork bomb (должен быть ЗАБЛОКИРОВАН)
```cpp
#include <unistd.h>
int main() {
while(1) fork();
}
```
#### 3. Network attack (должен быть ЗАБЛОКИРОВАН)
```cpp
#include <iostream>
#include <cstdlib>
int main() {
system("curl http://evil.com");
}
```
#### 4. Memory bomb (должен быть ОСТАНОВЛЕН)
```cpp
#include <vector>
int main() {
std::vector<int> v;
while(1) v.push_back(1);
}
```
#### 5. Time limit
```cpp
#include <unistd.h>
int main() {
sleep(10);
}
```
### Проверка логов
```bash
# Проверка использования Isolate
docker logs liquidcode-tester-worker 2>&1 | grep "Isolate"
# Проверка box acquire/release
docker logs liquidcode-tester-worker 2>&1 | grep "box"
# Проверка метрик
docker logs liquidcode-tester-worker 2>&1 | grep "Isolate stats"
```
### Проверка безопасности
```bash
# 1. Проверка capabilities контейнера
docker inspect liquidcode-tester-worker | jq '.[0].HostConfig.CapDrop'
docker inspect liquidcode-tester-worker | jq '.[0].HostConfig.CapAdd'
# 2. Проверка security_opt
docker inspect liquidcode-tester-worker | jq '.[0].HostConfig.SecurityOpt'
# 3. Проверка ulimits
docker inspect liquidcode-tester-worker | jq '.[0].HostConfig.Ulimits'
```
## Производительность
### Overhead на один запуск:
| Операция | Время |
|----------|-------|
| Init box | ~10-15ms |
| Run program | 0ms (в пределах погрешности) |
| Cleanup | ~5-10ms |
| **Total overhead** | **~25ms** |
### Для задачи с 100 тестами (1s TL каждый):
- Overhead: 25ms × 100 = 2.5s
- Типичное время: 100s
- Увеличение: **+2.5%** (незначительно!)
### Pool statistics:
```bash
# Monitoring через API endpoint (TODO)
curl http://localhost:8081/api/monitoring/isolate-pool
```
## Отключение Isolate
Для отключения Isolate (вернуться к старому поведению):
**appsettings.json:**
```json
{
"Isolate": {
"Enabled": false
}
}
```
Или через environment:
```yaml
environment:
- Isolate__Enabled=false
```
## Следующие шаги
### Фаза 2: Full execution integration (неделя 2)
- [ ] Интегрировать Isolate в JavaExecutionService
- [ ] Интегрировать Isolate в KotlinExecutionService
- [ ] Интегрировать Isolate в CSharpExecutionService
- [ ] Интегрировать Isolate в PythonExecutionService
### Фаза 3: Compilation + Checker (неделя 3)
- [ ] Изолировать компиляцию (CppCompilationService и др.)
- [ ] Изолировать checker (CheckerService)
- [ ] Тестирование с реальными Polygon пакетами
### Улучшения
- [ ] Monitoring endpoint для статистики box pool
- [ ] Graceful degradation при недоступности Isolate
- [ ] Кэширование executable в box (для checker)
- [ ] Custom AppArmor profile (advanced)
- [ ] Metrics (Prometheus)
## Известные ограничения
1. **Только Linux** - Isolate работает только на Linux kernel
2. **CAP_SYS_ADMIN** - Worker контейнер требует повышенных прав
3. **Box pool limit** - Максимум 100 параллельных заданий (конфигурируется)
4. **Workeruser permissions** - Некоторые операции могут требовать root
## Troubleshooting
### Isolate not found
```bash
# Проверка установки
docker exec liquidcode-tester-worker which isolate
docker exec liquidcode-tester-worker isolate --version
```
### Permission denied
```bash
# Проверка владельца директорий
docker exec liquidcode-tester-worker ls -la /var/local/lib/isolate
docker exec liquidcode-tester-worker ls -la /app
```
### Box initialization failed
```bash
# Проверка capabilities
docker inspect liquidcode-tester-worker | jq '.[0].HostConfig.CapAdd'
# Должны быть: SYS_ADMIN, SETUID, SETGID
```
### Cgroups not working
```bash
# Проверка cgroup v2
docker exec liquidcode-tester-worker ls -la /sys/fs/cgroup
# Проверка конфигурации isolate
docker exec liquidcode-tester-worker cat /usr/local/etc/isolate
```
## Ссылки
- [Isolate GitHub](https://github.com/ioi/isolate)
- [Isolate Documentation](https://github.com/ioi/isolate/blob/master/isolate.1.txt)
- [CMS (Contest Management System)](https://github.com/cms-dev/cms)
- [Docker Security Best Practices](https://docs.docker.com/engine/security/)