
오픈소스, 자체 호스팅 방식의 AI 기반 SIEM, EDR 및 SOAR 플랫폼으로, 현대적인 보안 운영을 위해 설계되었습니다.
전담 SOC가 없는 중소 규모 팀을 위한 자체 호스팅 보안 스택입니다. 각 엔드포인트에 에이전트를 설치하고 서버를 가리키게 하면 SIEM 로그, 파일 무결성, 패키지 취약점, OpenSearch 기반 로그 탐색기, 자율 AI 트라이지, SOAR 플레이북 엔진을 모두 docker compose up 한 번으로 얻을 수 있습니다.
"AI" 부분은 로컬에서 실행되는 Ollama 모델(기본값 llama3.2:3b)입니다. 로그는 서버 밖으로 나가지 않습니다. OpenAI 키도, Anthropic 키도, 전화 집(home)도 없습니다. 더 똑똑한 모델을 원하고 RAM이 충분하다면 .env에서 교체하세요.

SIEM 이벤트, 알림, FIM, 패키지, 네트워크 연결, 열린 포트, Docker 활동, 화면 프레임.
엔드포인트에서 Sigma 규칙으로 탐지합니다. 23개의 MITRE ATT&CK 기법을 다루는 23개 규칙이 conf/sigma/builtin/에 포함되어 있습니다. 커뮤니티 규칙셋을 그 옆에 추가할 수 있습니다. Sigma는 텍스트가 아닌 명명된 필드를 매칭하므로 Image|endswith: '\vssadmin.exe'는 관련 없는 메시지에 "vssadmin"이라는 단어가 나타나는 것으로 우회할 수 없으며, CommandLine|utf16le|base64offset|contains는 일반 텍스트 명령줄에 래퍼만 보이는 base64 -EncodedCommand 페이로드 내부를 읽습니다. 평가 코퍼스 기준 측정 결과: 10건 중 9건의 공격이 Sigma만으로 탐지되었고, 9건의 하드 네거티브 중 0건이 오탐되었습니다. 이 계층은 결정적이며 모델을 사용할 수 없을 때도 계속 작동합니다.
이벤트 간 상관 분석을 수행합니다. 개별 이벤트 규칙으로는 할 수 없는 작업입니다. 단일 실패 로그온은 일상적이지만, 40초 안에 한 소스에서 5개 계정이 실패하면 패스워드 스프레이입니다. 그리고 그 5개 이벤트 중 하나만 봐서는 절대 알 수 없습니다. 스프레이, 무차별 대입, 반복 실패 후 도착한 성공, 계정 생성 또는 서비스 설치 폭증을 다룹니다 — 두 플랫폼 모두에서, Windows 이벤트 ID 또는 파싱된 auth.log 라인에서.
두 가지 관점에서 실행됩니다. 서로 다른 공격을 보기 때문입니다. 에이전트의 호스트별로, 한 머신에 대한 공격이 전체적으로 보입니다. 그리고 수집 경로의 호스트 간에서, 50대의 머신에 걸쳐 한 번에 하나씩 실패를 이동한 스프레이가 나타납니다 — 단일 에이전트는 하나 이상의 이벤트를 볼 수 없으며, 이것이 더 유능한 공격입니다. 넓고 얕게 스프레이하면 계정별 잠금과 호스트별 임계값 모두 아래에 머물기 때문입니다.
Sigma와의 총 커버리지: 27개 기법. 모든 창은 이벤트당 한 번이 아니라 한 번만 발생하며, 모든 카운터는 제한됩니다 — 공격자가 제공한 사용자 이름에 키가 지정된 카운터는 탐지가 아니라 메모리 고갈 프리미티브입니다.
규칙 자체에서 MITRE ATT&CK로 탐지를 매핑합니다. 규칙은 tags: attack.t1490을 전달하므로 오래될 수 있는 수동 유지 매핑 테이블이 없습니다. 커버리지 페이지는 단일 "커버리지 %"가 숨길 수 있는 세 가지 상태를 구분합니다: 커버되고 관찰됨, 커버되고 조용함, 그리고 전혀 커버되지 않음 — 마지막 상태만 콘솔의 침묵이 아무 의미도 없는 유일한 경우입니다.
로컬 LLM으로 모든 이벤트를 트라이지합니다. 세 개의 워커가 병렬로 실행됩니다: 하나는 들어오는 모든 이벤트를 실시간으로 감시하고, 하나는 운영자 주도 딥 스캔을 실행하며, 하나는 방어 조치(BLOCK_IP, ISOLATE_HOST, KILL_PROCESS 등)를 취할지 결정합니다.
방어 워커용 섀도우 모드. AI_SHADOW_MODE=1로 전환하면 모든 자율 판정이 실행되는 대신 SOAR 허브에서 인간 승인을 위해 대기합니다. 실제 트래픽에서 모델을 튜닝한 후 스스로 행동하게 하기에 유용합니다.
모든 것을 OpenSearch에 인덱싱합니다. 한 곳에서 퍼지/정확/접두어 쿼리로 플릿을 검색할 수 있습니다.
SOAR 플레이북을 실행합니다. 다단계, 노드별 결과 추적이 가능한 작은 비주얼 편집기로 구축되며, 수동 또는 AI 판정으로 트리거할 수 있습니다.
취약점 스캔. 각 에이전트의 설치된 패키지를 OSV(온라인 또는 내부 미러를 통해)에 대해 스캔합니다.
위협 인텔 피드를 가져옵니다. abuse.ch(Feodo, ThreatFox, URLhaus)에서 로컬 지표 테이블로, 오래된 데이터 정리와 에어갭 스위치가 포함됩니다.
에이전트 구성을 푸시하기 전에 검증합니다. YAML 파싱, 구조적 형태, 정규식 컴파일 — 잘못된 정규식은 유효한 YAML이며 해당 규칙을 포함하는 규칙을 조용히 비활성화합니다.
내장 원격 데스크톱. WebSocket JPEG 스트리밍을 통해, 엔드포인트에 별도 VNC 설치가 필요 없습니다.
사이드바는 모든 것을 세 개의 섹션으로 그룹화합니다: 텔레메트리(대시보드, 에이전트, 알림, 자산, FIM, 로그, AI), 자동화 대응(방어 조치, 플레이북, 자동화 규칙), 그리고 관리.
등록된 각 에이전트는 12개의 탭이 있는 자체 페이지를 가집니다. 개요는 실시간 리소스 미터, 가장 최근 SIEM 로그, 에이전트 메타데이터 및 위협 요약을 보여줍니다:

알림은 에이전트 자체 상관 규칙이 이미 플래그한 모든 것입니다. 심각도 색상, 필터 가능, 검색 가능:

AI 분석 탭은 로컬 LLM의 운영자 측면입니다. 수동 및 자동 스캔이 모두 여기에 표시됩니다. 각 인사이트에는 판정 칩, 신뢰도, MITRE 지표(모델이 반환할 때), IOC, 다음 단계, 그리고 AI가 본 정확한 로그 행을 여는 View Source 버튼이 포함됩니다:

에이전트별 하드웨어, 소프트웨어 및 네트워크 소켓. 하드웨어 탭은 모든 PnP 장치를 나열하고, 소프트웨어는 설치된 패키지를 나열하며, 네트워크는 소유 프로세스와 함께 모든 TCP/UDP 소켓을 나열합니다:


OpenSearch 기반 에이전트 간 검색. 에이전트를 선택하고, 데이터셋(SIEM 이벤트, 보안 알림, 프로세스 이벤트, 네트워크, FIM, 감사 로그)을 선택하고 검색합니다. 파워 유저를 위해 OpenSearch Dashboards(Kibana 포크)를 여는 버튼도 있습니다:

플랫폼 자체에 대한 모든 로그인 시도(로컬 및 LDAP 모두)로, 결과, 소스 IP 및 타임스탬프가 포함됩니다. "누가 언제 로그인했는지" 궁금할 때 유용합니다:

호스트에 Docker 24+와 Compose v2 및 Python 3.10+가 필요합니다(Python은 일회성 에이전트 빌드 단계에만 필요). 전체 스택은 약 16GB RAM을 요구합니다. 아래 시스템 요구 사항을 참조하세요.```bash git clone https://github.com/d3vhex/Sentora.git cd Sentora
cp .env.example .env
python scripts/init_secrets.py
cd Sentora ./build_agent.sh # on Linux/macOS/WSL
cd ..
docker compose up --build -d
Open <http://localhost:8000>. 기본 로그인은 `admin` / `admin123`입니다.
**Users & Roles**에서 즉시 변경하세요.
Ollama는 첫 부팅 시 `llama3.2:3b`를 자동으로 가져옵니다. 다음으로 확인하세요:```bash
docker exec sentora-ollama ollama list
Deploy Agent 페이지에서 원하는 OS용 원라이너를 복사하여 에이전트를 배포합니다. 대상 머신(관리자 셸)에 붙여넣으면 설치 프로그램이 바이너리를 다운로드하고, 설정을 내려받고, 서버에 등록한 다음, 예약 작업/systemd 유닛으로 자체 등록합니다.
| 서비스 | 포트 | 접근 가능 범위 | 용도 |
|---|---|---|---|
app | :8000 | 어디서나 | REST API + React UI |
ingest | :5001 | 어디서나 | TCP 로그 수집기(에이전트가 여기로 전송) |
db | :3307 | localhost | MySQL 8.0(네트워크 내부에서는 3306) |
rabbitmq | :5672 / :15672 | localhost | 작업 큐 + 관리 UI |
ollama | :11434 | localhost | 로컬 LLM 런타임 |
opensearch | :9200 | localhost | 전문(full-text) 로그 검색 |
opensearch-dashboards | :5601 | localhost | 선택적 Kibana 스타일 탐색기 |
ai-worker-{automation,manual,defensive} | — | LLM 분석 워커 |
app과 ingest만 모든 인터페이스에서 수신 대기합니다. 나머지는 BIND_ADDR(기본값 127.0.0.1)에 바인딩되는데, 기본 구성에서는 이들 중 어느 것도 인증을 수행하지 않기 때문입니다. OpenSearch는 보안 플러그인이 비활성화된 상태로 실행되며, Dashboards는 수집된 모든 로그에 대한 인증 없는 뷰입니다. 하나를 노출하려면 BIND_ADDR을 넓히는 대신 app과 동일한 리버스 프록시 및 인증 뒤에 배치하세요.
Log Explorer의 "Open Dashboards" 버튼은 서버 호스트 이름의 5601 포트를 가리키므로 호스트 자체에서는 작동합니다. 원격 운영자는 해당 리버스 프록시가 필요합니다.
| 프로필 | CPU | RAM | 디스크 | 비고 |
|---|---|---|---|---|
| 실험실(≤ 5개 에이전트) | 4코어 | 12 GB | 40 GB SSD | llama3.2:3b, OpenSearch 힙 1 GB |
| 소규모 팀(10–50개 에이전트) | 8코어 | 16 GB | 100 GB SSD | Compose 기본값으로 충분 |
| 프로덕션(50개 이상 에이전트) | 16+코어 | 32 GB+ | 250 GB+ NVMe | OpenSearch와 Ollama를 별도 호스트로 이동 |
유휴 상태 메모리 사용량:
llama3.2:3b): 약 3 GB, 추론 중에는 더 사용RAM이 부족하면 qwen2.5:1.5b 또는 다른 작은 Ollama 모델로 전환하고 OpenSearch 힙을 줄이세요. GPU는 필수가 아니지만, 있으면 Ollama가 자동으로 사용합니다.
방어형 워커의 판정이 ACT이고 신뢰도가 AI_AUTO_ACT_CONF(기본값 0.75) 이상이며, 권장 조치가 아래 안전 목록에 있을 때 워커는 해당 조치를 에이전트의 automations 테이블에 직접 큐에 넣습니다.```
BLOCK_IP KILL_PROCESS RESTART_SERVICE ISOLATE_HOST
DISABLE_USER QUARANTINE_FILE SUSPEND_PROCESS LOGOFF_USER
CONTAINER_ISOLATE CONTAINER_STOP CONTAINER_KILL
### 섀도우 모드
`.env`에서 `AI_SHADOW_MODE=1`을 설정하면 방어 워커가 실제 작업을 실행하지 않습니다. 자율 대응을 촉발했을 판정은 대신 **제안(proposal)** 으로 저장되며, `source_file = AI_DEFENSIVE_SHADOW` 및 `shadow_status = pending`으로 표시됩니다. 운영자는 **SOAR Hub > Shadow Queue**에서 각 제안을 검토하고 다음 중 하나를 수행합니다:
- **승인(Approve)** > 실제 SOAR 작업(`call_agent_soar`)이 실행되고 제안은 `approved`로 표시됩니다(타임스탬프 + 운영자 이름 포함).
- **거부(Reject)** > 제안은 선택적 메모와 함께 `rejected`로 표시됩니다. 아무 작업도 수행되지 않습니다.
제안은 만료되지 않으며, 누구도 대신 결정하지 않습니다. 실제 `BLOCK_IP` / `ISOLATE_HOST` 등을 실행하기 전에 모델의 판정에 대한 신뢰를 쌓는 동안 프로덕션 텔레메트리에서 모델을 실행하는 데 유용합니다.
---
## 보안 참고 사항
### 인증
UI는 서버 측 세션으로 인증합니다: 로그인 시 `HttpOnly` 쿠키에 불투명 토큰이 발급되며, `userdb.sessions`가 권위 소스입니다. 토큰의 SHA-256 해시만 저장되므로 데이터베이스 덤프로는 표시 가능한 정보를 얻을 수 없습니다.
두 가지 시계가 적용되며, 둘 다 `.env`에서 구성할 수 있습니다:
| 설정 | 기본값 | 의미 |
| :--- | :--- | :--- |
| `SESSION_IDLE_MINUTES` | `60` | 마지막 요청 후 이 시간이 지나면 세션이 종료됩니다 |
| `SESSION_ABSOLUTE_HOURS` | `12` | 활동 여부와 관계없는 하드 상한 |
| `SESSION_COOKIE_SECURE` | `0` | 앱 앞에서 TLS가 종료되면 `1`로 설정 |
| `SESSION_COOKIE_SAMESITE` | `Lax` | `Lax`는 CSRF에 필요한 교차 사이트 POST/XHR을 차단합니다 |
세션은 비밀번호 변경, 관리자 비밀번호 재설정, 역할 변경 및 계정 삭제 시 즉시 취소됩니다 — 관리자가 누군가의 접근 권한을 제거해도 열려 있는 탭이 계속 작동하지 않습니다.
모든 라우트는 **기본 거부(deny-by-default)** 입니다: 유효한 세션이 없으면 핸들러가 실행되기 전에 요청이 거부됩니다. 예외는 로그인 엔드포인트, SPA 셸, 정적 자산, 그리고 대신 `X-Agent-Key` 또는 등록 토큰으로 인증하는 에이전트용 엔드포인트입니다.
`X-User-ID`는 여전히 프론트엔드에서 전송되지만 더 이상 신원이 아닙니다 — 서버는 이를 세션과 대조하여 검증하고 불일치를 거부합니다. 브라우저는 CORS 사전 요청 없이 교차 사이트 요청에 사용자 정의 헤더를 첨부할 수 없으므로, 상태 변경 요청에 이를 요구하는 것은 `SameSite`를 두 번째 CSRF 제어 수단으로 보강합니다.
라우트 보호는 `@require_permission(...)`로 선언되고 레지스트리를 통해 미들웨어에 의해 강제되므로, 데코레이터가 `@app.route`의 어느 쪽에 있든 적용됩니다. 부팅 로그에 집계가 출력됩니다:```
[Auth] Routes: <n> permission-gated, <n> session-only, <n> public.
해당 줄에 0 permission-gated이 보고되면 RBAC가 적용되고 있지 않은 것이므로 — 이를 장애로 취급하십시오.
모든 라우트는 다음 세 가지 중 하나여야 합니다: permission-gated, _PUBLIC_HANDLERS에 나열, 또는 tests/test_auth_wiring.py의 SESSION_ONLY_HANDLERS에 세션만으로 충분한 이유를 설명하는 주석과 함께 명시. 테스트가 이를 검증하므로, 새 라우트가 조용히 관리 없이 추가될 수 없습니다 — 이것이 바로 run_playbook, delete_soar_action, test_ldap_connection이 로그인만 가능한 모든 계정에서 접근 가능하게 된 경로였습니다.
15분 이내에 한 계정에 대해 5회 실패, 또는 한 주소에서 20회 실패 시, 창이 지나갈 때까지 추가 시도는 429로 거부됩니다. 이미 모든 실패를 기록하고 있었지만 아무도 읽지 않던 login_logs에서 집계됩니다 — bcrypt가 온라인 추측을 막는 유일한 제동 장치였습니다.
| 설정 | 기본값 | 의미 |
|---|---|---|
LOGIN_MAX_FAILURES_USER | 5 | 창 내에서 허용되는 계정별 실패 횟수 |
LOGIN_MAX_FAILURES_IP | 20 | 주소별 실패 횟수; 사무실이 하나의 NAT 주소를 공유하므로 더 높음 |
LOGIN_LOCKOUT_WINDOW_MIN | 15 | 실패를 집계하는 과거 기간 |
검사는 비밀번호 비교 전에 실행되므로, 알려진 사용자 이름과 알려지지 않은 사용자 이름 간의 타이밍 차이도 제거합니다. login_logs에 접근할 수 없으면 열린 상태로 실패합니다: 감사 테이블이 다운되어 로그인 페이지에 접근할 수 없는 상황은 그 자체로 장애입니다.
X-Forwarded-For는 TRUSTED_PROXIES(쉼표로 구분된 주소 또는 CIDR, 기본값은 비어 있음)에 나열된 피어에서만 신뢰됩니다. 앱 앞에 아무것도 없으면 해당 헤더는 공격자가 제공한 것이므로, 이를 무조건 신뢰하는 것 — 이 기능이 대체한 방식 — 은 호출자가 감사 추적에 임의의 주소를 기록하고 동일한 요청에서 자신의 속도 제한을 초기화할 수 있게 했습니다.```
TRUSTED_PROXIES=10.0.0.0/8,192.168.1.5
앱에 직접 접근할 때는 비워 둡니다.
### 에이전트 자체 API
에이전트는 `0.0.0.0:9099`에서 수신 대기하며 SYSTEM 또는 root 권한으로 실행됩니다. 모든 라우트는 `X-Agent-Key`를 요구하며, `/self_destruct`는 특히 이 에이전트 자체의 등록 키를 요구하므로, 유출된 플릿 전체 비밀번호로 모든 엔드포인트를 한 번에 제거할 수 없습니다. `/health`는 키 없이도 활성 상태(liveness)에 응답하며, 키 없이는 그 이상의 정보를 공개하지 않습니다.
허용적인 폴백(fallback)은 없습니다. 이전 빌드는 호스트에서 `AGENT_MASTER_SECRET`이 설정되지 않았을 때 비어 있지 않은 키를 모두 수락했는데, 실제로 그 값을 설정한 곳이 없어 모든 곳에서 기본값으로 동작했습니다. 실패 시 열려 있는(fail-open) EDR은 EDR이 없는 것보다 더 나쁩니다. 콘솔이 엔드포인트를 보호 중이라고 보고하기 때문입니다.
`AGENT_BIND`는 수신 대기 주소를 변경합니다. 서버가 이 포트에서 HTTP로 에이전트에 연결하므로 여전히 기본값은 `0.0.0.0`입니다. 루프백에 바인딩하려면 설정 변경이 아닌 대체 전송(transport)이 필요합니다.
### CORS
`CORS_ORIGINS`는 기본적으로 비어 있습니다. 일반적인 배포에서는 이 앱이 SPA 자체를 제공하므로 요청이 동일 출처(same-origin)이며 항목이 필요 없습니다. 와일드카드는 완전히 거부됩니다. 브라우저는 쿠키를 포함한 모든 요청에서 `Access-Control-Allow-Origin: *`를 거부합니다. 출처가 분리된 배포에서는 명시적 출처를 나열하고 `SESSION_COOKIE_SAMESITE=None`과 `SESSION_COOKIE_SECURE=1`을 설정해야 합니다.
### 기본 비밀번호
`.env.example`에는 자리 표시자가 포함되어 있습니다. 실제 `.env`는 git-ignored 처리됩니다. 플랫폼을 `localhost` 이상에 노출하기 전에 다음 항목을 교체하세요:
- `DB_PASSWORD`
- `AGENT_SHARED_SECRET` (에이전트 인증 폴백). 설정되지 않은 경우 첫 부팅 시 자동 생성됩니다.
`admin / admin123` 로그인은 더 이상 기억할 필요가 없습니다. 시드 계정은 `must_change_password`로 생성되며, 이 값이 설정된 동안 세션은 `/change-password` 외에는 아무것도 접근할 수 없습니다. 이는 UI가 아닌 미들웨어에서 강제됩니다. 프런트엔드가 준수하도록 신뢰하는 플래그는 제안에 불과하고 API는 curl에도 응답하기 때문입니다.
### TLS 인증서
개인 키는 어떤 것도 포함하지 않습니다. 작동하는 `certs/server.key`와 `certs/rootCA.key`가 커밋되어 있었는데, 이는 모든 배포에 동일한 TLS ID를 부여하고 이를 공개했습니다. 저장소를 복제한 사람이라면 누구나 키를 보유하게 되어 인증서가 상대방이 누구인지 증명하지 못했습니다.
`TLS_ENABLED=1`이고 인증서가 없으면 앱은 첫 부팅 시 인증서를 생성합니다. 각 설치본은 자체 키를 가지며 키는 생성된 머신을 절대 떠나지 않습니다. `certs/*.key`와 `certs/*.crt`는 git-ignored 처리됩니다.
CA는 자체 서명이므로 명시적으로 신뢰하지 않으면 브라우저에서 경고가 표시됩니다. 그 경고는 정직합니다. 경고가 전혀 없는 공유 비밀번호보다 이를 선호하세요. 공개용으로 사용하는 경우 `TLS_CERT` / `TLS_KEY`를 실제 인증서로 지정하세요. 설정되었지만 파일이 없으면 앱은 자체 서명 인증서로 대체하지 않고 그 사실을 알려줍니다.
수동으로 재생성하려면:```bash
python certs/generate_certs.py --force
이전 키는 여전히 git 기록에 남아 있습니다. 이 변경 이전에 배포된 키 쌍은 폐기된 것으로 간주하세요. 새 설치에서는 더 이상 사용하지 않습니다.
서버는 두 개의 Fernet 키를 사용하며, 둘 다 첫 부팅 시 자동 생성됩니다:
| 키 | 위치 | 보호 대상 |
|---|---|---|
| 에이전트 키 | data/fernet.key (또는 FERNET_KEY_PATH) | 에이전트 원격 측정 데이터; /api/agents/bootstrap를 통해 배포 |
| 서버 키 | .env FERNET_KEY | 서버 내부 저장 필드 (예: 비밀번호 열) |
둘 다 chmod 600으로 설정하세요. 백업해 두세요. 둘 중 하나라도 잃으면 해당 암호화 데이터를 읽을 수 없게 됩니다. 현재는 제자리 회전(in-place rotation)이 없습니다.
두 가지 독립적인 메커니즘, 둘 다 선택 사항입니다:
판정별 강화 (ai/intel.py). AI 워커는 로그에서 발견된 지표를 AlienVault OTX 및 VirusTotal과 대조 확인합니다. OTX_API_KEY / VT_API_KEY가 필요하며, 설정되지 않으면 외부 호출이 전혀 이루어지지 않습니다.
지표 피드 (core/threat_feeds.py). abuse.ch에서 threat_intel 테이블을 매시간 채웁니다 — Feodo Tracker (봇넷 C2 주소), ThreatFox (신뢰도 점수가 있는 혼합 IoC) 및 URLhaus (악성코드 배포 URL).
지표는 last_seen을 보유하며 THREAT_INTEL_STALE_DAYS(기본값 30) 이후 정리됩니다: 지난 분기에 C2를 호스팅했던 주소는 일반적으로 이제 다른 사람의 것이며, 이를 유지하면 무기한으로 오탐이 발생합니다. 각 피드는 경고 경로에서 테이블을 읽기 때문에 THREAT_INTEL_MAX_PER_FEED 행으로 제한됩니다.
abuse.ch는 다운로드를 무료 계정 키 뒤로 옮기고 있습니다. 피드가 401/403을 반환하면 서버 로그에 그렇게 표시됩니다. THREAT_INTEL_AUTH_KEY를 설정하세요.
실제로 도착한 내용을 확인하세요:```bash docker logs sentora-server | grep ThreatIntel
### Air-gap mode```ini
OSV_MODE=mirror
OSV_MIRROR_URL=http://osv.internal
THREAT_INTEL_MODE=off
# or serve the feeds internally:
# THREAT_INTEL_FEODO_URL=http://mirror.internal/feodo.json
이 설정들과 함께 OTX_API_KEY / VT_API_KEY가 설정되지 않은 상태에서는 네트워크로 나가는 것이 없습니다. 폰트는 번들로 포함되고, Ollama는 로컬이며, CDN에 접촉하지 않습니다.
/api/exposure/report는 플릿 전체에서 패치되지 않은 패키지와 파일 무결성 이벤트를 에이전트별로 집계하여, 가장 심각한 것부터 나열합니다. 자체 커버리지도 보고합니다: 에이전트를 읽을 수 없으면 complete: false로 표시되는데, 플릿의 절반 이상이 총계가 아니기 때문입니다.
의도적으로 점수는 없습니다. 이 엔드포인트는 이전에 100 - vulns*2 - fim*5를 "규정 준수 점수"로 반환했지만, 이는 어떤 프레임워크에도 매핑되지 않고, 플릿 규모에 따라 확장되지 않으며, 실제 플릿에서는 0으로 고정됩니다. 심각도 등급도 같은 이유로 없습니다: vulnerabilities_report에는 심각도 열이 없고 해당 필드는 저장 시 암호화되므로, 어떤 등급이든 임의로 만들어야 했을 것입니다.
POST /<agent>/config/<type>은 센서에 도달하기 전에 모든 것을 검증합니다: YAML 파싱, 구조적 형태, 그리고 중요한 계층인 정규식 컴파일. 잘못된 정규식은 완벽하게 유효한 YAML이며 해당 카테고리를 조용히 비활성화하므로, 구문만 검사하면 바로 엔드포인트로 전달될 수 있습니다. 편집기는 입력하는 동안 동일한 엔드포인트에 대해 린트를 수행하고, 클릭 가능한 줄 번호와 함께 문제를 보고합니다.
Agent (Win / Linux) │ TCP frames + REST polling ▼ ingest (:5001) ──► RabbitMQ ──► AI worker fleet (3 modes) │ │ ▼ ▼ MySQL (per-agent _db) ai_analysis_results │ ▼ app (Sanic :8000) ──► React UI + REST + WebSocket screen proxy
더 깊은 버전(모듈별 레이아웃, 스키마, AI 파이프라인, SOAR
자율성, 에어갭 표면)은
[docs/Sentora_Architecture.md](https://github.com/d3vhex/sentora/blob/HEAD/docs/Sentora_Architecture.md)에 있습니다.
운영 문서:
| 문서 | 다루는 내용 |
| :--- | :--- |
| [아키텍처](https://github.com/d3vhex/sentora/blob/HEAD/docs/Sentora_Architecture.md) | 모듈 레이아웃, 데이터 흐름, 인증 모델, AI 파이프라인 |
| [프로덕션 배포](https://github.com/d3vhex/sentora/blob/HEAD/docs/production-deployment.md) | 용량 산정, 네트워크 토폴로지, TLS, 백업, 모니터링, 에어갭 |
| [업데이트 런북](https://github.com/d3vhex/sentora/blob/HEAD/docs/update-runbook.md) | 업그레이드, 에이전트 롤아웃, DB 마이그레이션, 롤백 |
| [진행 보고서](https://github.com/d3vhex/sentora/blob/HEAD/docs/PROGRESS_REPORT.md) | 변경된 사항과 그 이유 |
---
## 개발 환경 설정```bash
# 1. Database. Only init_userdb.sql — it creates and selects `userdb`.
#
# db/init.sql is NOT a server-init script. It is the per-agent schema
# template, applied by server.create_tables_if_not_exist() after
# connecting to that agent's own database, which is why it contains no
# CREATE DATABASE or USE. Running it standalone fails at line 5 with
# "No database selected" — the same way it broke every first-time
# `docker compose up` while it was mounted into the MySQL init directory.
mysql -u root -p < db/init_userdb.sql
# 2. Backend. requirements.lock pins every version the image is built
# from; requirements.txt is the loose list it was resolved from.
pip install -r requirements.lock
python app.py
# 3. Ingest (separate terminal)
python server.py
# 4. Frontend dev server
cd frontend
npm install
npm run dev
동일한 스크립트, 세 가지 역할:```bash WORKER_TYPE=automation python ai_worker.py WORKER_TYPE=manual python ai_worker.py WORKER_TYPE=defensive python ai_worker.py
Production: `docker-compose.yaml`가 처리하도록 하세요.
---
## 기여하기
PR은 언제나 환영합니다. 열기 전에:
1. Fork → branch → `main`에 대해 PR을 생성하세요.
2. 체크를 실행하세요:```bash
pytest -ra # no MySQL or RabbitMQ needed
python -m compileall -q app.py core security
cd frontend && npx tsc --noEmit && npm run build && cd ..
# With the stack up — enumerates every route and calls it twice
python scripts/api_smoke_test.py
@require_permission(...)로 감싸야 합니다. 부트 로그에
집계 결과가 출력되며, 0 permission-gated로 보고되면 라우트 문제가 아니라
배선(wiring) 문제입니다.수정보다 큰 작업은 먼저 이슈를 열어 접근 방식을 맞춰야 합니다.
. ├── app.py # Sanic API + React SPA host ├── server.py # TCP ingest ├── ai_worker.py # AI worker fleet (3 modes) ├── ai/ │ ├── utils.py # LLM helpers, AI cache, SOAR queueing │ └── intel.py # OTX / VT per-verdict enrichment (opt-in) ├── core/ │ ├── mq.py # RabbitMQ publisher │ ├── opensearch.py # OpenSearch index/search │ ├── config_validation.py # Agent YAML validation (parse, shape, regex) │ └── threat_feeds.py # abuse.ch indicator feeds ├── security/ │ ├── session.py # Server-side session store │ └── ssrf.py # Proxy destination rules ├── scanners/ │ └── vuln.py # Server-side OSV scanner ├── scripts/ │ ├── init_secrets.py # Generate the secrets .env needs │ ├── rotate_db_password.py # Rotate the MySQL root password safely │ └── api_smoke_test.py # Exercise every route against a live server ├── tests/ # pytest; no MySQL or RabbitMQ required ├── frontend/ # React 18 + TS SPA │ └── src/lib/ # Shared logic (playbook action catalogue) ├── Sentora/ # Cross-platform agent ├── certs/ # Self-signed dev certs ├── docs/ # Architecture + screenshots └── docker-compose.yaml
---
## 라이선스
AGPL-3.0. [LICENSE](https://github.com/d3vhex/sentora/blob/HEAD/LICENSE) 참조.
사용, 수정, 재배포 가능. AGPL이 일반 GPL에 추가하는 부분:
수정된 버전을 다른 사용자가 상호작용하는 네트워크 서버에서 실행하는 경우,
수정 사항도 AGPL 조건으로 공개해야 합니다.
- 내부용 자체 호스팅 → 소스 공개 의무 없음.
- 수정된 Sentora 기반의 공개 SaaS → 수정 사항을 공개해야 함.
- 폐쇄 소스 파생물을 배포하거나 네트워크 카피레프트 조항을 건너뛰고 싶은 경우?
상업용 라이선스 면제가 제공됩니다. 작성자에게 문의하세요.
"Sentora" 이름과 로고는 프로젝트 작성자의 상표이며
AGPL의 적용을 받지 않습니다. 자유롭게 포크하되, 자체 제품으로 재배포할 경우 이름을 변경하세요.
---
## Community Edition에 포함되지 않는 것
Community Edition에는 인위적인 제한이 전혀 없습니다: 에이전트 수 제한 없음,
보존 기간 제한 없음, 핵심 기능 게이팅 없음. 하드웨어가 허용하는 한 넓게 실행하세요.
유료 Pro / Enterprise 배포판은 엔터프라이즈 통합 기능(SAML/SCIM SSO, 멀티 테넌시,
규정 준수 보고서, HA, WORM 감사, 서명된 에어갭 업데이트 번들, 4-eyes SOAR 승인,
프리미엄 티켓팅/SIEM 포워더)을 추가합니다. 핵심 탐지 기능은 절대 그 벽 뒤로 옮겨지지 않습니다.
이 중 어떤 것이 배포 환경에 중요하다면
[문의하세요](mailto:[email protected]).