核心功能: - 6 层检测管线: L0 结构分析 → L1 ClamAV → L2 文档深度检测 → L3 关键词匹配 → L4 YARA → L5 PE/二进制 - FastAPI + PostgreSQL + Redis + Docker Compose 架构 - 客户端 HMAC-SHA256 签名鉴权 + 限流 + 幂等性 - 控制台 UI (登录/Dashboard/诊断中心/策略管理/任务列表/测试中心/产品介绍页) - 三层诊断定时器 (error_scan 30s / db_aggregate 30s / container_check 5min) 并发与稳定性修复: - 诊断定时器 Redis 时间槽位锁 (多 worker 同一槽位只有一个执行) - JSONL 存储 fcntl 跨进程排他锁 + 容错解码 + 原子重写 - 移除 SQLite fallback, 统一 PostgreSQL - API_CLIENTS 脱敏为环境变量, .env 已 .gitignore
127 lines
3.8 KiB
Python
127 lines
3.8 KiB
Python
"""启动时 Docker 能力检测(用 python docker SDK)。
|
||
|
||
返回三档:
|
||
full — docker.sock 可访问,日志和 inspect 都能用
|
||
partial — 能连 socket 但权限受限
|
||
none — 完全不可用(没挂 socket / 包没装)
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import os
|
||
from datetime import datetime, timezone
|
||
from typing import Any, Dict, List, Optional
|
||
|
||
|
||
_PROBE_CONTAINER = "meshsafe-api"
|
||
|
||
|
||
def _try_client() -> Optional["docker.DockerClient"]:
|
||
"""尝试创建 Docker client。失败返回 None。"""
|
||
try:
|
||
import docker # noqa: F401
|
||
except ImportError:
|
||
return None
|
||
|
||
try:
|
||
import docker
|
||
# from_env() 会自动读 DOCKER_HOST,没设的话走 unix:///var/run/docker.sock
|
||
client = docker.from_env(timeout=5)
|
||
client.ping() # 真正连一下
|
||
return client
|
||
except Exception: # noqa: BLE001
|
||
return None
|
||
|
||
|
||
def detect_docker_access(mode: str = "auto") -> Dict[str, Any]:
|
||
now = datetime.now(timezone.utc).isoformat()
|
||
|
||
sock_exists = os.path.exists("/var/run/docker.sock")
|
||
client = _try_client()
|
||
|
||
if mode == "false":
|
||
return {
|
||
"mode": "false", "status": "none",
|
||
"docker.sock_exists": sock_exists,
|
||
"docker_python_available": client is not None,
|
||
"can_logs": False, "can_inspect": False,
|
||
"containers": None,
|
||
"message": "配置强制关闭 Docker 能力(diagnostics.docker.enabled=false)",
|
||
"detected_at": now,
|
||
}
|
||
|
||
if client is None:
|
||
if mode == "true":
|
||
msg = "配置强制启用但 Docker Python SDK 不可用 — pip install docker"
|
||
else:
|
||
msg = "Docker SDK 未就绪 — 日志匹配/容器状态类规则已跳过"
|
||
return {
|
||
"mode": mode, "status": "none",
|
||
"docker.sock_exists": sock_exists,
|
||
"docker_python_available": False,
|
||
"can_logs": False, "can_inspect": False,
|
||
"containers": None,
|
||
"message": msg,
|
||
"detected_at": now,
|
||
}
|
||
|
||
# 真测
|
||
can_logs = False
|
||
can_inspect = False
|
||
containers: Optional[List[str]] = None
|
||
|
||
try:
|
||
c = client.containers.get(_PROBE_CONTAINER)
|
||
c.logs(tail=1)
|
||
can_logs = True
|
||
c.attrs # 读取属性
|
||
can_inspect = True
|
||
except Exception: # noqa: BLE001
|
||
pass
|
||
|
||
try:
|
||
containers = [c.name for c in client.containers.list(all=True)]
|
||
except Exception: # noqa: BLE001
|
||
containers = None
|
||
|
||
if can_logs and can_inspect:
|
||
status = "full"
|
||
msg = "Docker 访问正常 — 日志匹配 + 容器状态检测全部启用"
|
||
elif can_logs or can_inspect:
|
||
status = "partial"
|
||
msg = f"Docker SDK 可用但权限受限(logs={can_logs}, inspect={can_inspect})"
|
||
else:
|
||
status = "none"
|
||
msg = "docker.sock 未挂或权限不足 — 日志匹配类规则已跳过"
|
||
|
||
if mode == "true" and status != "full":
|
||
msg = f"配置强制启用但检测结果为 {status} — 检查 docker.sock 挂载"
|
||
|
||
return {
|
||
"mode": mode, "status": status,
|
||
"docker.sock_exists": sock_exists,
|
||
"docker_python_available": True,
|
||
"can_logs": can_logs,
|
||
"can_inspect": can_inspect,
|
||
"containers": containers,
|
||
"message": msg,
|
||
"detected_at": now,
|
||
}
|
||
|
||
|
||
def status_message(status: str) -> str:
|
||
return {
|
||
"full": "✅ Docker 能力完整",
|
||
"partial": "⚠️ Docker 访问受限",
|
||
"none": "ℹ️ Docker 日志检测未启用",
|
||
}.get(status, status)
|
||
|
||
|
||
def get_client():
|
||
"""获取共享 docker client(给 dumper / rules 用)。失败返回 None。"""
|
||
try:
|
||
import docker
|
||
return docker.from_env(timeout=10)
|
||
except Exception: # noqa: BLE001
|
||
return None
|