开源OSINT调查平台Flowsint的安装

简介

什么是 Flowsint ?

Flowsint 是一个开源的 OSINT(开源情报)图形化调查平台,专为道德调查、透明度和验证而设计。它允许用户通过可视化图形界面探索实体之间的关系,并使用自动化 enrichers 进行数据丰富化。

主要特点

  • 图形化探索:通过可视化图形界面探索实体之间的关系
  • 自动化 Enrichers:内置多种自动化数据丰富化工具
  • 本地存储:所有数据存储在本地,保护隐私
  • 无默认账号:不预设任何账号,需要自行注册
  • 多数据源支持:支持连接 PostgreSQLRedisNeo4j 等数据库
  • 开源免费:基于 Apache 2.0 协议开源,可免费使用和修改

应用场景

  • 网络安全分析:网络安全分析师可以使用 Flowsint 进行情报调查和关联分析
  • 事件调查:调查人员可以使用图形化方式梳理事件脉络
  • 开源情报收集OSINT 研究人员可以自动化收集和整理公开情报
  • 关系分析:可视化了解决策实体之间的复杂关系

Flowsint 是一个专注于伦理调查的开源 OSINT 工具,适合网络安全分析师和调查人员使用。

安装

在群晖上以 Docker 方式安装。

官方在 ghcr.io 上有预编译的镜像,flowsint-app

flowsint-apilatest 对应的均为 1.2.7

但是如果你按照官方提供的 docker-compose.yml 部署,大概率不会成功,会卡在注册用户时遇到 405 错误

虽然我们设置了 VITE_API_URL,但前端运行时并没有把 API 地址指向后端,而是仍然在同源地请求前端服务本身。原因可能是前端镜像里代码在构建时没读到该变量,或者代码里写死了相对路径

所以老苏在官方基础上增加了 nginx 容器来处理地址转发,现在设不设置 VITE_API_URL 应该已经无所谓了

准备文件

该项目包含多个服务,需要准备以下文件:

  1. docker-compose.yml - Docker 容器编排文件
  2. env.txt - 环境变量配置
  3. nginx.conf - Nginx 反向代理配置

目录结构

在群晖上新建文件夹 flowsint,并在其中创建必要的子目录:

1
2
# 新建文件夹 flowsint 和子目录
mkdir -p /volume1/docker/flowsint/{data,import,logs,plugins,pgdata}
文件夹 路径 说明
data /volume1/docker/flowsint/data Neo4j 数据目录
import /volume1/docker/flowsint/import Neo4j 导入目录
logs /volume1/docker/flowsint/logs Neo4j 日志目录
plugins /volume1/docker/flowsint/plugins Neo4j 插件目录
pgdata /volume1/docker/flowsint/pgdata PostgreSQL 数据目录

docker-compose 安装

将以下三个文件放入 /volume1/docker/flowsint 目录:

env.txt

env.txt 存放所有敏感配置和运行时参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
NODE_ENV=production
AUTH_SECRET=n8sZgJ6DmhxCYFvXnFwnm22v44iqspQg

POSTGRES_USER=flowsint
POSTGRES_PASSWORD=flowsint
POSTGRES_DB=flowsint

# Generate your own master key by running: python3 -c "import os, base64; key = os.urandom(32); print('base64:' + base64.b64encode(key).decode('utf-8'))"
MASTER_VAULT_KEY_V1=base64:qnHTmwYb+uoygIw9MsRMY22vS5YPchY+QOi/E79GAvM=

NEO4J_URI_BOLT=bolt://neo4j:7687
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=password

VITE_API_URL=http://127.0.0.1:5001
REDIS_URL=redis://redis:6379/0

nginx.conf

nginx.confNginx 反向代理配置,用于将外部请求路由到内部服务,同时设置了 WebSocket 支持和最大上传文件大小(50MB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
server {
listen 80;
server_name _;

client_max_body_size 50m;

location /api/ {
proxy_pass http://api:5001;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

location / {
proxy_pass http://app:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

docker-compose.yml

定义了 7 个容器服务,比官方增加了 1 反向代理容器 nginx

服务 镜像 用途
postgres postgres:15-alpine 关系型数据库,存储业务数据
redis redis:7-alpine 缓存 + Celery 消息队列
neo4j neo4j:5 图数据库,存储实体关系图
api ghcr.io/reconurge/flowsint-api Flask 后端 API
celery api 异步任务处理器
app ghcr.io/reconurge/flowsint-app Vue.js 前端
nginx nginx:alpine 反向代理 + 负载均衡
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
services:
postgres:
image: postgres:15-alpine
container_name: flowsint-postgres-prod
restart: always
environment:
POSTGRES_USER: ${POSTGRES_USER:-flowsint}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-flowsint}
POSTGRES_DB: ${POSTGRES_DB:-flowsint}
volumes:
- ./pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-flowsint}"]
interval: 10s
timeout: 5s
retries: 5

redis:
image: redis:7-alpine
container_name: flowsint-redis-prod
restart: always
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5

neo4j:
image: neo4j:5
container_name: flowsint-neo4j-prod
restart: always
ports:
- "7474:7474"
- "7687:7687"
environment:
- NEO4J_AUTH=${NEO4J_USERNAME}/${NEO4J_PASSWORD}
- NEO4J_PLUGINS=["apoc"]
- NEO4J_apoc_export_file_enabled=true
- NEO4J_apoc_import_file_enabled=true
- NEO4J_apoc_import_file_use__neo4j__config=true
volumes:
- ./data:/data
- ./logs:/logs
- ./import:/var/lib/neo4j/import
- ./plugins:/plugins
healthcheck:
test: cypher-shell -u ${NEO4J_USERNAME} -p ${NEO4J_PASSWORD} "RETURN 1"
interval: 5s
timeout: 5s
retries: 10

api:
image: ghcr.io/reconurge/flowsint-api:latest
container_name: flowsint-api-prod
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- DATABASE_URL=postgresql://${POSTGRES_USER:-flowsint}:${POSTGRES_PASSWORD:-flowsint}@postgres:5432/${POSTGRES_DB:-flowsint}
- NEO4J_URI_BOLT=${NEO4J_URI_BOLT}
- NEO4J_USERNAME=${NEO4J_USERNAME}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
- AUTH_SECRET=${AUTH_SECRET}
- MASTER_VAULT_KEY_V1=${MASTER_VAULT_KEY_V1}
- REDIS_URL=${REDIS_URL}
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
neo4j:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:5001/health || exit 1"]
interval: 10s
timeout: 5s
retries: 5

celery:
image: ghcr.io/reconurge/flowsint-api:latest
container_name: flowsint-celery-prod
restart: always
command:
[
"celery",
"-A",
"flowsint_core.core.celery",
"worker",
"--loglevel=info",
"--pool=threads",
"--concurrency=10",
]
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- DATABASE_URL=postgresql://${POSTGRES_USER:-flowsint}:${POSTGRES_PASSWORD:-flowsint}@postgres:5432/${POSTGRES_DB:-flowsint}
- NEO4J_URI_BOLT=${NEO4J_URI_BOLT}
- NEO4J_USERNAME=${NEO4J_USERNAME}
- NEO4J_PASSWORD=${NEO4J_PASSWORD}
- AUTH_SECRET=${AUTH_SECRET}
- MASTER_VAULT_KEY_V1=${MASTER_VAULT_KEY_V1}
- REDIS_URL=${REDIS_URL}
- SKIP_MIGRATIONS=true
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
neo4j:
condition: service_healthy
api:
condition: service_healthy

app:
image: ghcr.io/reconurge/flowsint-app:latest
container_name: flowsint-app-prod
restart: always
expose:
- "8080"
depends_on:
api:
condition: service_healthy

nginx:
image: nginx:alpine
container_name: flowsint-nginx-prod
restart: always
ports:
- "5173:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- app
- api

启动服务

通过 SSH 登录到群晖,执行以下命令启动:

1
2
3
4
5
# 进入 flowsint 目录
cd /volume1/docker/flowsint

# 一键启动
docker-compose --env-file env.txt up -d

群晖上 docker 版本比较低,所以 service_healthy 很容易失败

多等一会儿再执行一键启动 docker-compose --env-file env.txt up -d 即可

提示:首次启动可能需要较长时间拉取 Docker 镜像,请耐心等待。

另外容器 neo4j 可能会阵发性的出现高 CPU 占用,系统稳定后就好了

运行

在浏览器中访问 http://<群晖IP>:5173 即可进入登录界面。

第一次要点 Create an account 注册账号

登录成功后的主界面

具体的使用请参考官方的使用说明: https://www.flowsint.io/docs/developers/getting-started

注意事项

  1. 隐私保护OSINT 调查需要高度隐私保护,Flowsint 所有数据都存储在本地
  2. 端口占用:默认使用 5173 端口,确保该端口未被占用;Neo4j74747687 端口也一样
  3. 环境变量安全AUTH_SECRETMASTER_VAULT_KEY_V1 是敏感信息,建议在生产环境中修改为随机生成的密钥
  4. 首次注册:系统没有默认账号,首次访问需要先注册账号
  5. 资源需求:该平台依赖 PostgreSQLRedisNeo4j,对资源有一定需求
  6. 道德使用:请阅读项目自带的 ETHICS.md 文件,了解伦理使用准则

参考文档

Flowsint: A modern platform for visual, flexible, and extensible graph-based investigations
地址:https://github.com/reconurge/flowsint

Flowsint Official Website
地址:https://flowsint.io

reconurge/flowsint-app - Docker Image | Docker Hub
地址:https://ghcr.io/reconurge/flowsint-app