
オープンソースでセルフホスト型の、AIを活用したSIEM、EDR、SOARプラットフォーム。現代のセキュリティ運用向けに設計されています。
専任のSOCを持たない中小規模チーム向けのセルフホスト型セキュリティスタック。各エンドポイントにエージェントを配置し、サーバーに向けるだけで、SIEMログ、ファイル整合性、パッケージの脆弱性、OpenSearchベースのログエクスプローラー、自律型AIトリアージ、SOARプレイブックエンジンをすべてdocker compose up一つで利用できます。
「AI」部分はローカルで動作するOllamaモデル(デフォルトはllama3.2:3b)です。ログが外部に出ることはありません。OpenAIキーもAnthropicキーも不要で、外部への通信もありません。より高性能なモデルが必要でRAMに余裕がある場合は、.envで切り替えられます。

WindowsおよびLinuxエージェントから単一のTCPチャネルでテレメトリを収集します。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秒以内に1つのソースから5つのアカウントが失敗した場合はパスワードスプレー攻撃であり、その5つのイベントのいずれか1つだけを見てもそれを知ることはできません。スプレー攻撃、ブルートフォース、繰り返しの失敗後に成功が発生するケース、アカウント作成やサービスインストールのバーストをカバーします。両プラットフォームで、WindowsイベントIDまたは解析済みのauth.log行から検出します。
攻撃の種類が異なるため、2つの視点で実行されます。エージェント上のホスト単位では、1台のマシンに対する攻撃が完全に可視化されます。また、インジェストパス上のホスト間では、50台のマシンに対して1回ずつ失敗を繰り返すスプレー攻撃が検出されます。単一のエージェントは1つ以上のイベントを見ることはなく、これはより巧妙な攻撃です。広く浅くスプレーする攻撃は、アカウントごとのロックアウトとホストごとのしきい値の両方の下に留まるためです。
Sigmaとの合計カバレッジ: 27テクニック。各ウィンドウはイベントごとではなく1回だけ発火し、すべてのカウンターには上限があります。攻撃者が指定したユーザー名をキーとするカウンターは、メモリ枯渇のプリミティブであり、検出ではありません。
ルール自体からMITRE ATT&CKへの検出マッピングを行います。ルールにはtags: attack.t1490が含まれているため、手動で保守するマッピングテーブルが陳腐化することはありません。カバレッジページでは、単一の「カバレッジ%」では隠れてしまう3つの状態を区別します: カバーされ検出された状態、カバーされているが静かな状態、まったくカバーされていない状態。最後の状態だけが、コンソールの沈黙が何も意味しない唯一のケースです。
ローカルLLMで全イベントをトリアージします。3つのワーカーが並行して実行されます: 1つはすべての受信イベントをリアルタイムで監視し、1つはオペレーター主導のディープスキャンを実行し、1つは防御アクション(BLOCK_IP、ISOLATE_HOST、KILL_PROCESSなど)を実行するかどうかを決定します。
防御ワーカーのシャドウモード。AI_SHADOW_MODE=1に切り替えると、すべての自律的な判定は実行される代わりにSOARハブで人間の承認用にステージングされます。実際のトラフィックでモデルを調整してから自律動作させるのに役立ちます。
すべてをOpenSearchにインデックス化し、1つの場所からファジー/完全一致/前方一致クエリでフリートを検索できます。
SOARプレイブックを実行します。小さなビジュアルエディターで構築され、マルチステップのノードごとの結果追跡を備え、手動またはAI判定でトリガーできます。
脆弱性スキャンは、各エージェントのインストール済みパッケージをOSV(オンラインまたは内部ミラー経由)に対してスキャンします。
脅威インテルフィードをabuse.ch(Feodo、ThreatFox、URLhaus)からローカルのインジケーターテーブルに取り込み、陳腐化プルーニングとエアギャップスイッチを備えています。
エージェント設定をプッシュする前に検証します。YAMLパース、構造的形状、正規表現のコンパイル。無効な正規表現は有効なYAMLであり、それを含むルールを静かに無効化します。
組み込みのリモートデスクトップ。WebSocket JPEGストリーミング経由で、エンドポイントに別途VNCインストールは不要です。
サイドバーはすべてを3つのセクションにグループ化します: テレメトリ(ダッシュボード、エージェント、アラート、アセット、FIM、ログ、AI)、自動応答(防御アクション、プレイブック、自動化ルール)、および管理。
登録された各エージェントには、12のタブを持つ専用ページがあります。概要には、ライブリソースメーター、最新のSIEMログ、エージェントメタデータ、脅威サマリーが表示されます:

アラートは、エージェント自身の相関ルールがすでにフラグ付けしたすべてのものです。重大度で色分けされ、フィルタリング可能、検索可能です:

AI分析タブは、ローカルLLMのオペレーター向け側面です。手動スキャンと自動スキャンの両方がここに表示されます。各インサイトには、判定チップ、信頼度、MITREインジケーター(モデルが返す場合)、IOC、次のステップ、およびAIが参照した正確なログ行を開くソースを表示ボタンが含まれます:

エージェントごとのハードウェア、ソフトウェア、ネットワークソケット。ハードウェアタブにはすべてのPnPデバイスがリストされ、ソフトウェアにはインストール済みパッケージ、ネットワークには所有プロセスを含むすべてのTCP/UDPソケットがリストされます:


OpenSearchをバックエンドとするクロスエージェント検索。エージェントを選択し、データセット(SIEMイベント、セキュリティアラート、プロセスイベント、ネットワーク、FIM、監査ログ)を選択して検索します。パワーユーザー向けにOpenSearch Dashboards(Kibanaフォーク)を開くボタンもあります:

プラットフォーム自体へのすべてのログイン試行(ローカルとLDAPの両方)で、結果、送信元IP、タイムスタンプが記録されます。「誰がいつログインしたか」を確認したいときに役立ちます:

ホストにDocker 24+(Compose v2対応)とPython 3.10+が必要です(Pythonは1回限りのエージェントビルド手順のみに使用)。フルスタックには約16 GBの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 | 全文ログ検索 |
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` を設定すると、防御ワーカーは実際のアクションの発火を停止します。自律応答をトリガーしていたであろう判定結果は、代わりに **提案** として保存され、`source_file = AI_DEFENSIVE_SHADOW` と `shadow_status = pending` が設定されます。オペレーターは **SOAR Hub > Shadow Queue** から各提案をレビューし、次のいずれかを実行します:
- **承認** > 実際の SOAR アクション (`call_agent_soar`) が発火し、提案は `approved` とマークされます (タイムスタンプ + オペレーター名付き)。
- **拒否** > 提案は任意のメモ付きで `rejected` とマークされます。アクションは実行されません。
提案は期限切れになりません。あなたに代わって判断するものは何もありません。実際の `BLOCK_IP` / `ISOLATE_HOST` などを解き放つ前に、モデルを本番テレメトリで実行させ、その判定に自信をつけるのに役立ちます。
---
## セキュリティノート
### 認証
UI はサーバーサイドセッションで認証します。ログインは `HttpOnly` クッキーに不透明なトークンを発行し、`userdb.sessions` が権威となります。トークンの SHA-256 のみが保存されるため、データベースのダンプから提示可能なものは何も得られません。
2 つのクロックが適用され、どちらも `.env` で設定可能です:
| 設定 | デフォルト | 意味 |
| :--- | :--- | :--- |
| `SESSION_IDLE_MINUTES` | `60` | 最後のリクエストからこの時間が経過するとセッションは失効します |
| `SESSION_ABSOLUTE_HOURS` | `12` | アクティビティに関係なく適用されるハードな上限 |
| `SESSION_COOKIE_SECURE` | `0` | アプリの前で TLS が終端されたら `1` に設定します |
| `SESSION_COOKIE_SAMESITE` | `Lax` | `Lax` は CSRF に必要なクロスサイト POST/XHR をブロックします |
セッションは、パスワード変更、管理者パスワードリセット、ロール変更、アカウント削除時に即座に失効します。管理者が誰かのアクセス権を削除しても、開いたままのタブが機能し続けることはありません。
すべてのルートは **デフォルトで拒否** です。有効なセッションがない場合、リクエストはハンドラーが実行される前に拒否されます。例外は、ログインエンドポイント、SPA シェル、静的アセット、およびエージェント向けエンドポイントで、これらは代わりに `X-Agent-Key` または登録トークンで認証します。
`X-User-ID` は引き続きフロントエンドから送信されますが、これはもはや ID ではありません。サーバーはこれをセッションに対して検証し、不一致を拒否します。ブラウザーは CORS プリフライトなしではクロスサイトリクエストにカスタムヘッダーを添付できないため、状態変更リクエストでこれを必須にすることで、`SameSite` を 2 番目の CSRF 制御として補強します。
ルート保護は `@require_permission(...)` で宣言され、レジストリを通じてミドルウェアによって強制されるため、デコレーターが `@app.route` のどちら側に配置されていても適用されます。ブートログに集計が出力されます:```
[Auth] Routes: <n> permission-gated, <n> session-only, <n> public.
その行が 0 permission-gated と報告する場合、RBACは強制されていないことになる——それを障害として扱うこと。
すべてのルートは、次の3つのいずれかでなければならない: 権限ゲート付き、_PUBLIC_HANDLERS に記載、または tests/test_auth_wiring.py 内の SESSION_ONLY_HANDLERS に、セッションだけで十分な理由をコメント付きで記載。テストがこれを検証するため、新しいルートが静かに統制なしに追加されることはない——これが、run_playbook、delete_soar_action、test_ldap_connection が、ログインできるアカウントなら誰でも到達可能になっていた経緯である。
15分以内に、1つのアカウントで5回の失敗、または1つのアドレスから20回の失敗があると、ウィンドウが経過するまで以降の試行は 429 で拒否される。カウントは login_logs から取得されるが、これはすでにすべての失敗を記録しており、誰も読み取っていなかった——bcryptだけがオンライン推測に対する唯一のブレーキだった。
| 設定 | デフォルト | 意味 |
|---|---|---|
LOGIN_MAX_FAILURES_USER | 5 | ウィンドウ内で許可されるアカウント単位の失敗数 |
LOGIN_MAX_FAILURES_IP | 20 | アドレス単位の失敗数。オフィスが1つの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`はキーなしで生存確認に応答し、キーなしではそれ以上の情報は開示しません。
寛容なフォールバックはありません。以前のビルドでは、ホスト上で`AGENT_MASTER_SECRET`が未設定の場合に空でないキーをすべて受け入れていましたが、実際には何も設定されていなかったため、デフォルトでどこでも有効になっていました。フェイルオープンするEDRはEDRがないより悪いです。コンソールがエンドポイントを保護済みとして報告するからです。
`AGENT_BIND`でリスナーを移動できます。サーバーがこのポートでHTTP経由でエージェントに到達するため、デフォルトは依然として`0.0.0.0`です。ループバックにバインドするには、設定変更ではなく代替トランスポートが必要です。
### CORS
`CORS_ORIGINS`はデフォルトで空です。通常のデプロイではこのアプリがSPA自体を配信するため、リクエストは同一オリジンとなり、エントリは不要です。ワイルドカードは完全に拒否されます。ブラウザはCookieを伴うリクエストで`Access-Control-Allow-Origin: *`を拒否するためです。分割オリジンのデプロイでは、明示的なオリジンを列挙し、`SESSION_COOKIE_SAMESITE=None`と`SESSION_COOKIE_SECURE=1`を設定する必要があります。
### デフォルトのシークレット
`.env.example`にはプレースホルダーが同梱されています。実際の`.env`はgit-ignoreされています。プラットフォームを`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-ignoreされています。
CAは自己署名であるため、明示的に信頼しない限りブラウザは警告します。その警告は正直です。まったく警告を出さない共有シークレットよりもそれを優先してください。公開用のものには、`TLS_CERT` / `TLS_KEY`を実際の証明書に向けてください。それらが設定されているのに存在しない場合、アプリは自己署名証明書に置き換えるのではなく、その旨を明示します。
手動で再生成するには:```bash
python certs/generate_certs.py --force
古いキーは依然としてgit履歴に残っています。 この変更より前に配布されたペアは破棄されたものとして扱ってください。新しいインストールでは使用されません。
サーバーは2つのFernetキーを使用し、どちらも初回起動時に自動生成されます:
| キー | 場所 | 保護対象 |
|---|---|---|
| エージェントキー | data/fernet.key(またはFERNET_KEY_PATH) | エージェントのテレメトリ。/api/agents/bootstrap経由で配布 |
| サーバーキー | .envのFERNET_KEY | サーバー内部の保存時フィールド(例: パスワード列) |
両方にchmod 600を設定してください。バックアップも行ってください。どちらかを失うと、対応する暗号化データが読み取れなくなります。現在のところ、その場でのローテーションはありません。
2つの独立したメカニズムがあり、どちらもオプションです:
判定ごとのエンリッチメント(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(信頼度スコア付きの混合IoCs)、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
### エアギャップモード```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 を返していましたが、これはどのフレームワークにも対応しておらず、フリートの規模に応じてスケールせず、実際のフリートではゼロに固定されます。深刻度の評価も同じ理由で存在しません。vulnerabilities_report には深刻度の列がなく、そのフィールドは保存時に暗号化されているため、評価を付けるには捏造する必要があります。
POST /<agent>/config/<type> は、センサーに到達する前に検証を行います。YAML の解析、構造的な形状、そして重要な層である 正規表現のコンパイル です。無効な正規表現は完全に有効な YAML であり、それを含むカテゴリを静かに無効化するため、構文のみのチェックではそのままエンドポイントに送信されてしまいます。エディタは入力中に同じエンドポイントに対して lint を実行し、クリック可能な行番号付きで問題を報告します。
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
The deeper version (per-module layout, schema, AI pipeline, SOAR
autonomy, air-gap surfaces) lives in
[docs/Sentora_Architecture.md](https://github.com/d3vhex/sentora/blob/HEAD/docs/Sentora_Architecture.md).
Operational docs:
| Document | Covers |
| :--- | :--- |
| [Architecture](https://github.com/d3vhex/sentora/blob/HEAD/docs/Sentora_Architecture.md) | Module layout, data flow, auth model, AI pipeline |
| [Production deployment](https://github.com/d3vhex/sentora/blob/HEAD/docs/production-deployment.md) | Sizing, network topology, TLS, backup, monitoring, air-gap |
| [Update runbook](https://github.com/d3vhex/sentora/blob/HEAD/docs/update-runbook.md) | Upgrades, agent rollout, DB migrations, rollback |
| [Progress report](https://github.com/d3vhex/sentora/blob/HEAD/docs/PROGRESS_REPORT.md) | What has changed and why |
---
## Development setup```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
同じスクリプト、3つの役割:```bash WORKER_TYPE=automation python ai_worker.py WORKER_TYPE=manual python ai_worker.py WORKER_TYPE=defensive python ai_worker.py
本番環境では、`docker-compose.yaml` に任せましょう。
---
## コントリビューション
PR は歓迎します。作成前に以下を確認してください:
1. Fork → ブランチ作成 → `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 と報告された場合、問題はルートではなく配線にあります。修正以上の規模のものについては、先に issue を開いてアプローチを調整しましょう。
. ├── 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眼SOAR承認、プレミアムチケット/SIEMフォワーダー) を
追加します。コアの検知機能がその壁の背後に移されることは決してありません。
これらのいずれかがデプロイメントに関係する場合は、
[連絡してください](mailto:[email protected])。