コンテンツにスキップ

Feature 39: 監査ログシステム

Author: Masahiro Aoki

実装日: 2026年2月20日
バージョン: 1.0.0
ステータス: ✅ 実装済み

概要

EvoSpikeNet の監査ログシステム(Feature 39)は、SHA-256 ハッシュチェーンを利用した改ざん検知機能付きの監査ログを提供します。コンプライアンス要件(SOC 2・ISO 27001 等)への対応と、セキュリティインシデントの事後調査を支援します。

全 HTTP リクエストは Starlette ミドルウェアによって自動的に記録されます。


ハッシュチェーンの仕組み

AuditEntry は以下の情報を含み、前エントリのハッシュを参照することで改ざんを検知できます。

Entry N-1:  hash = SHA256(id + timestamp + action + ... + prev_hash)
                    │
                    ▼  prev_hash
Entry N:    hash = SHA256(id + timestamp + action + ... + prev_hash_N)
                    │
                    ▼  prev_hash
Entry N+1:  hash = SHA256(id + timestamp + action + ... + prev_hash_N+1)

一つのエントリが改ざんされると、それ以降の全エントリのハッシュが不整合となり、verify_chain() で検出されます。


コアコンポーネント

AuditEntry

一件の監査ログレコードです。SHA-256 ハッシュで整合性を保証します。

<!-- from evospikenet.audit_log import AuditEntry, AuditAction, AuditResult -->
from datetime import datetime, timezone

entry = AuditEntry(
    action=AuditAction.MODEL_LOAD,
    actor="admin_user",
    resource="/api/models/load",
    result=AuditResult.SUCCESS,
    detail={"model": "genome_v3"},
    prev_hash="d9e8f7a6...",
)
print(entry.entry_hash)  # SHA256 ハッシュ

フィールド:

フィールド 説明
id str UUID v4 自動生成
timestamp str UTC ISO-8601 タイムスタンプ
action str (AuditAction) 実行アクション
actor str 操作者 (username, system, etc.)
resource str 対象リソース (パス等)
result str (AuditResult) success / failure / partial
detail dict 追加情報(任意)
ip_address str クライアント IP(任意)
prev_hash str 前エントリのハッシュ(チェーン)
entry_hash str このエントリの SHA-256 ハッシュ

AuditLogManager

監査ログの管理クラスです。NDJSON 形式でファイルに永続化します。

<!-- TODO: update or remove - import failuditLogManager, AuditAction -->

# インスタンス生成(通常はシングルトンを使用)
log = AuditLogManager(
    log_dir="data/audit_logs",   # ログディレクトリ
    max_memory=10000,            # インメモリ保持件数
)

# エントリ書き込み
entry = log.log(
    action=AuditAction.MODEL_TRAIN,
    actor="admin_user",
    resource="/api/models/genome_v3",
    result="success",
    detail={"version": "3.2.1"},
)

# 検索
entries = log.query(
    actor="admin_user",
    action_prefix="model.",
    result="success",
    since=datetime(2026, 2, 1, tzinfo=timezone.utc),
    limit=100,
)

# ハッシュチェーン検証
valid, checked, error = log.verify_chain()

# エクスポート
json_data = log.export_json()   # list of dicts
csv_data = log.export_csv()     # CSV 文字列

AuditAction 一覧

class AuditAction(str, Enum):
    # Auth
    AUTH_LOGIN = "auth.login"
    AUTH_LOGOUT = "auth.logout"
    AUTH_FAILED = "auth.failed"
    API_KEY_CREATE = "auth.api_key.create"
    API_KEY_REVOKE = "auth.api_key.revoke"

    # Model / inference
    MODEL_LOAD = "model.load"
    MODEL_INFERENCE = "model.inference"
    CHECKPOINT_SAVE = "checkpoint.save"
    CHECKPOINT_RESTORE = "checkpoint.restore"

    # Evolution / genome
    EVOLUTION_START = "evolution.start"
    EVOLUTION_STOP = "evolution.stop"
    GENOME_SAVE = "genome.save"
    GENOME_APPLY = "genome.apply"
    FITNESS_OVERRIDE = "evolution.fitness_override"

    # Data
    DATA_READ = "data.read"
    DATA_WRITE = "data.write"
    DATA_DELETE = "data.delete"
    DATA_EXPORT = "data.export"

    # Configuration
    CONFIG_CHANGE = "config.change"
    SECURITY_CHANGE = "security.change"

    # Infrastructure
    NODE_REGISTER = "node.register"
    NODE_DEREGISTER = "node.deregister"
    FAILOVER = "infra.failover"
    SNAPSHOT_CREATE = "snapshot.create"
    SNAPSHOT_RESTORE = "snapshot.restore"
    SNAPSHOT_DELETE = "snapshot.delete"

    # Recovery
    RECOVERY_INCIDENT = "recovery.incident"
    RECOVERY_ACTION = "recovery.action"

    # Generic
    HTTP_REQUEST = "http.request"
    SYSTEM_EVENT = "system.event"

HTTP 自動ログ(ミドルウェア)

make_audit_middleware() によって (Starlette/FastAPI) 全 HTTP リクエストが 自動的に記録されます。

# api.py での設定(起動時に実行)
<!-- モジュール 'evospikenet' が見つかりませんパッケージ内の移動/名前変更を確認してください -->
<!-middleware("http")(make_audit_middleware(audit_log))

自動ログのフォーマット: - actor: X-API-Key ヘッダーから取得、存在しない場合は "anonymous"。 返される値は先頭12文字を取り "..." を付加(例 abcd1234efgh...)。 - action: AuditAction.HTTP_REQUEST - resource: リクエストパス (request.url.path) - detail: 辞書。現在の実装では以下のキーを含む。

{
  "method": "POST",
  "path": "/api/models/train",
  "status_code": 200,
  "query": "foo=bar"  // 空の場合は空文字列
}
- result: 2xx/3xx → success、それ以外 → failure - ip_address: クライアント IP (request.client.host があれば)


REST API

GET /api/audit/logs

クエリパラメータ:

パラメータ 説明
actor str 指定文字列を含む操作者でフィルタ
action str 完全一致または前方一致 (例 model.auth.login)
resource str リソースパスの部分一致
result str success / failure / partial
since str ISO-8601 形式開始時刻
until str ISO-8601 形式終了時刻
limit int 最大件数 (デフォルト100, 最大1000)
offset int ページオフセット

レスポンス例:

{
  "total": 1,
  "offset": 0,
  "limit": 100,
  "entries": [
    {
      "id": "550e8400-...",
      "timestamp": "2026-02-20T10:00:00.000Z",
      "action": "model.load",
      "actor": "admin_user",
      "resource": "/api/models/load",
      "result": "success",
      "detail": { "model": "genome_v3" },
      "ip_address": "203.0.113.5",
      "prev_hash": "d9e8f7a6...",
      "entry_hash": "a3f1b2c4..."
    }
  ]
}

GET /api/audit/stats

監査ログ統計を返します。

レスポンス例:

{
  "total_entries_in_memory": 1500,
  "log_files": 5,
  "current_log_file": "data/audit_logs/audit_20260220T123456Z.ndjson",
  "entries_in_current_file": 1234,
  "by_action": {
    "http.request": 800,
    "model.load": 300,
    "auth.login": 50
  },
  "by_result": {
    "success": 1400,
    "failure": 80,
    "partial": 20
  }
}

GET /api/audit/verify

ハッシュチェーン整合性を検証します。max_entries クエリパラメータ (省略時1000)で検査件数を指定できます。

レスポンス例 (整合):

{ "valid": true, "checked": 1500, "broken_at": null, "message": "Chain intact" }

レスポンス例 (破損検知):

{
  "valid": false,
  "checked": 750,
  "broken_at": 750,
  "message": "Chain broken at position 750"
}

GET /api/audit/export

ログを json または csv 形式でエクスポートします。

  • format: json(既定)または csv
  • since, until: ISO-8601

返却は Content-Disposition ヘッダ付きのプレーンテキスト応答。

POST /api/audit/log

手動でエントリを書き込みます。外部サービスや SDK から利用。

リクエストボディ例:

{
  "action": "model.inference",
  "actor": "service-account",
  "resource": "/api/generate",
  "result": "success",
  "detail": { "latency_ms": 120 }
}

レスポンス例:

{
  "status": "logged",
  "entry_id": "550e8400-e29b-41d4-a716-446655440001",
  "entry_hash": "a3f1b2c4..."
}


ハッシュチェーンの整合性を検証します。

レスポンス (正常):

{ "valid": true, "checked": 1500, "error": null }

レスポンス (改ざん検出):

{
  "valid": false,
  "checked": 750,
  "error": "Hash mismatch at entry 750: expected abc..., got xyz..."
}

GET /api/audit/export

クエリパラメータ: format = json または csv


ファイル構造

data/
  audit_logs/
    audit_2026-02-20.ndjson   ← 日次ローテーション
    audit_2026-02-19.ndjson
    ...

NDJSON 形式(1行1エントリ のJSON)で永続化されます。


性能指標

メトリクス 目標値 テスト参照
書き込みスループット ≥ 1,000 エントリ/秒 test_write_throughput_1000_entries
並行書き込み (8スレッド) ≥ 500 エントリ/秒/スレッド test_concurrent_writes_throughput
ハッシュチェーン検証 (1,000件) < 5,000 ms test_hash_chain_verify_1000_entries
クエリレイテンシ (500件ヒット) < 200 ms test_query_latency_1000_entries

テスト

# ユニットテスト
pytest tests/unit/test_audit_log.py -v

# 結合テスト
pytest tests/integration/test_features_36_39_40_integration.py::TestAuditLogEndpoints -v

# システムテスト(並行書き込み)
pytest tests/system/test_features_36_39_40_system.py::TestConcurrentAuditLog -v

# 性能テスト
pytest tests/performance/test_features_36_39_40_performance.py::TestAuditLogPerformance -v

関連ドキュメント