Initial commit: Rampart v0.2.0
Multi-layer DDoS protection for Minecraft servers. - rampart-core: Edge node with XDP/eBPF + Rust L7 filtering - rampart-manager: REST API with JWT auth, Redis sync - rampart-cli: CLI tool for operators - velocity-plugin: Domain check, HMAC verify, server registry, load balancer - paper-plugin: Auto-registration, heartbeat, HMAC verify - dashboard: React + Vite web UI for management
This commit is contained in:
commit
cf9608ce5d
159 changed files with 15341 additions and 0 deletions
262
docs/research/security.md
Normal file
262
docs/research/security.md
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
# Security - STRIDE, mTLS, Zero Trust, Supply Chain
|
||||
|
||||
> Актуально: v0.2+
|
||||
|
||||
---
|
||||
|
||||
## STRIDE Threat Model
|
||||
|
||||
| Угроза | Конкретно | Защита |
|
||||
|---|---|---|
|
||||
| **S**poofing | Атакующий подделывает IP edge ноды | mTLS (сертификат не подделать) + WireGuard |
|
||||
| **T**ampering | Подмена HMAC в hostname | HMAC-SHA256 + constant-time compare |
|
||||
| **R**epudiation | Нет доказательств кто добавил IP в блэклист | Аудит лог (user, ts, action, IP) в ClickHouse |
|
||||
| **I**nfo Disclosure | Утечка реального IP backend | Всё за WireGuard + iptables DROP |
|
||||
| **D**oS | Перегрузка edge ноды | XDP + rate limit + challenge |
|
||||
| **E**scalation | Доступ к Manager API без авторизации | JWT + mTLS + IP whitelist + rate limit |
|
||||
|
||||
---
|
||||
|
||||
## Zero Trust - принципы
|
||||
|
||||
```
|
||||
1. Никому не доверяй по умолчанию - даже внутри WireGuard сети
|
||||
2. Проверяй каждый компонент - mTLS между всеми сервисами
|
||||
3. Минимальные привилегии - каждый компонент видит только нужное
|
||||
4. Логируй всё - аудит лог каждого действия
|
||||
|
||||
Применение в Rampart:
|
||||
Edge нода → HAProxy/LB: mTLS (сертификат edge ноды)
|
||||
LB → Velocity: mTLS (сертификат LB)
|
||||
Velocity → Redis: пароль + только WireGuard IP
|
||||
Manager API: JWT + mTLS + IP whitelist
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## mTLS - схема сертификатов
|
||||
|
||||
```
|
||||
Root CA (rampart-ca)
|
||||
├── Intermediate CA (edge-ca)
|
||||
│ ├── edge-eu-1.crt
|
||||
│ ├── edge-us-1.crt
|
||||
│ └── edge-as-1.crt
|
||||
├── Intermediate CA (infra-ca)
|
||||
│ ├── haproxy.crt
|
||||
│ ├── velocity-1.crt ... velocity-20.crt
|
||||
│ ├── manager.crt
|
||||
│ └── dashboard.crt
|
||||
└── Intermediate CA (game-ca)
|
||||
├── hub-1.crt ... hub-100.crt
|
||||
└── (game серверам не нужен mTLS - они за Velocity)
|
||||
```
|
||||
|
||||
### Генерация через CLI
|
||||
|
||||
```bash
|
||||
# Инициализация PKI (один раз)
|
||||
rampart pki init \
|
||||
--root-ca rampart-ca \
|
||||
--output /etc/rampart/pki/
|
||||
|
||||
# Выпуск сертификата для новой edge ноды
|
||||
rampart pki issue \
|
||||
--ca edge-ca \
|
||||
--name edge-us-2 \
|
||||
--ip 10.0.100.5 \
|
||||
--san "edge-us-2.rampart.internal" \
|
||||
--output /etc/rampart/pki/edge-us-2/
|
||||
|
||||
# Ротация (раз в год, автоматически через cron)
|
||||
rampart pki rotate --role edge --days-before-expiry 30
|
||||
```
|
||||
|
||||
### Реализация в Rust (rustls)
|
||||
|
||||
```rust
|
||||
// tls.rs
|
||||
|
||||
use rustls::{ServerConfig, ClientConfig, RootCertStore};
|
||||
use tokio_rustls::{TlsAcceptor, TlsConnector};
|
||||
|
||||
pub fn server_config(cert: &str, key: &str, ca: &str) -> Arc<ServerConfig> {
|
||||
let mut root_store = RootCertStore::empty();
|
||||
root_store.add(load_cert(ca)).unwrap();
|
||||
|
||||
Arc::new(ServerConfig::builder()
|
||||
// Требуем клиентский сертификат (mutual)
|
||||
.with_client_cert_verifier(
|
||||
WebPkiClientVerifier::builder(Arc::new(root_store))
|
||||
.build().unwrap()
|
||||
)
|
||||
.with_single_cert(load_certs(cert), load_key(key))
|
||||
.unwrap())
|
||||
}
|
||||
|
||||
pub fn client_config(cert: &str, key: &str, ca: &str) -> Arc<ClientConfig> {
|
||||
let mut root_store = RootCertStore::empty();
|
||||
root_store.add(load_cert(ca)).unwrap();
|
||||
|
||||
Arc::new(ClientConfig::builder()
|
||||
.with_root_certificates(root_store)
|
||||
.with_client_auth_cert(load_certs(cert), load_key(key))
|
||||
.unwrap())
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## HMAC - правильная реализация
|
||||
|
||||
```rust
|
||||
// hmac/signer.rs
|
||||
|
||||
use hmac::{Hmac, Mac};
|
||||
use sha2::Sha256;
|
||||
// ВАЖНО: subtle для constant-time сравнения (защита от timing атак)
|
||||
use subtle::ConstantTimeEq;
|
||||
|
||||
type HmacSha256 = Hmac<Sha256>;
|
||||
|
||||
pub fn sign(hostname: &str, secret: &[u8]) -> String {
|
||||
let mut mac = HmacSha256::new_from_slice(secret)
|
||||
.expect("HMAC accepts any key length");
|
||||
mac.update(hostname.as_bytes());
|
||||
hex::encode(mac.finalize().into_bytes())
|
||||
}
|
||||
|
||||
pub fn verify(hostname: &str, provided_sig: &str, secret: &[u8]) -> bool {
|
||||
let expected = sign(hostname, secret);
|
||||
// constant_time_eq - время сравнения не зависит от содержимого
|
||||
// Без этого атакующий может угадать HMAC по времени ответа
|
||||
expected.as_bytes().ct_eq(provided_sig.as_bytes()).into()
|
||||
}
|
||||
|
||||
// Добавляем к hostname: "play.server.com\0shield\0<hex_hmac>"
|
||||
pub fn sign_hostname(raw: &str, secret: &[u8]) -> String {
|
||||
// Берём только domain часть (без Forge суффиксов)
|
||||
let domain = raw.split('\0').next().unwrap_or(raw);
|
||||
let sig = sign(domain, secret);
|
||||
format!("{}\0shield\0{}", raw, sig) // сохраняем Forge суффикс
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Аудит лог
|
||||
|
||||
```rust
|
||||
// Каждое административное действие записывается
|
||||
|
||||
#[derive(Serialize, Deserialize, Clickhouse)]
|
||||
pub struct AuditEntry {
|
||||
pub ts: DateTime<Utc>,
|
||||
pub user: String, // кто сделал
|
||||
pub action: String, // "blacklist.add" / "server.remove" / "config.change"
|
||||
pub target: String, // "1.2.3.4" / "survival_47"
|
||||
pub details: String, // JSON с деталями
|
||||
pub src_ip: String, // откуда был запрос
|
||||
pub success: bool,
|
||||
}
|
||||
|
||||
// Вставляем в ClickHouse (не в Redis - нужна долгосрочная история)
|
||||
pub async fn audit(entry: AuditEntry) {
|
||||
clickhouse_client
|
||||
.insert("rampart.audit_log")
|
||||
.write(&entry)
|
||||
.await
|
||||
.ok(); // не прерываем основной флоу если аудит упал
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Защита Redis
|
||||
|
||||
```bash
|
||||
# redis.conf
|
||||
bind 10.0.0.1 # только WireGuard IP (не 0.0.0.0!)
|
||||
requirepass "LONG_RANDOM_PASSWORD_HERE"
|
||||
protected-mode yes
|
||||
rename-command FLUSHALL "" # запрещаем опасные команды
|
||||
rename-command FLUSHDB ""
|
||||
rename-command DEBUG ""
|
||||
rename-command CONFIG "CONFIG_RESTRICTED_CMD"
|
||||
|
||||
# Firewall - дополнительный слой
|
||||
iptables -A INPUT -p tcp --dport 6379 -s 10.0.0.0/16 -j ACCEPT
|
||||
iptables -A INPUT -p tcp --dport 6379 -j DROP
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Supply Chain Security (v0.5+)
|
||||
|
||||
```yaml
|
||||
# .github/workflows/supply-chain.yml
|
||||
|
||||
cargo-audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: cargo install cargo-audit
|
||||
- run: cargo audit # проверяем CVE в зависимостях
|
||||
|
||||
cargo-deny:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: EmbarkStudios/cargo-deny-action@v1
|
||||
with:
|
||||
command: check all # лицензии, дублирования, CVE
|
||||
|
||||
sbom:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: anchore/sbom-action@v0 # генерируем SBOM
|
||||
with:
|
||||
format: spdx-json
|
||||
|
||||
sign-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: sigstore/cosign-installer@v3
|
||||
- run: |
|
||||
cosign sign --yes \
|
||||
ghcr.io/yourname/rampart-core:${{ github.sha }}
|
||||
```
|
||||
|
||||
### Совместимость лицензий
|
||||
|
||||
```
|
||||
Наш код: MIT или Apache-2.0
|
||||
|
||||
Ключевые зависимости:
|
||||
tokio: MIT ✅
|
||||
rustls: MIT/Apache ✅
|
||||
libbpf-rs: LGPL-2.1 ✅ (динамическая линковка)
|
||||
libbpf-sys: LGPL-2.1 ✅
|
||||
XDP C код: GPL-2.0 ✅ (kernel module, отдельная сборка)
|
||||
|
||||
Потенциальная проблема:
|
||||
XDP .c файлы компилируются в eBPF bytecode и загружаются в ядро.
|
||||
Сам .c файл под GPL - это нормально для kernel interaction.
|
||||
Rust loader (userspace) - MIT, не загрязняется GPL.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Утечка реального IP - чеклист
|
||||
|
||||
```
|
||||
☐ DNS история очищена (проверь через SecurityTrails, Shodan)
|
||||
☐ Reverse DNS не раскрывает хостинг
|
||||
☐ Старые firewall правила удалены
|
||||
☐ game серверы не пингуют внешние ресурсы со своего IP
|
||||
(обновления плагинов, curl запросы - через proxy или не извне)
|
||||
☐ Email заголовки (если сервер шлёт письма) - проверить что не раскрывают IP
|
||||
☐ Error pages, краш репорты - не выводить IP
|
||||
☐ MC команды типа /ip - отключить или ограничить
|
||||
☐ Доступ членов команды - минимальный, только нужные люди знают IP
|
||||
☐ Pterodactyl/панель управления - закрыта за VPN или IP whitelist
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue