Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
228 lines (221 loc) · 8.69 KB
/
Copy pathdocker-compose.yml
File metadata and controls
228 lines (221 loc) · 8.69 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
services:
postgres:
image: postgres:16-alpine
ports:
- "127.0.0.1:5432:5432"
env_file: .env
environment:
POSTGRES_DB: ${DB_NAME:-mirage}
POSTGRES_USER: ${DB_USER:-mirage}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-mirage} -d ${DB_NAME:-mirage}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
deploy:
resources:
limits:
memory: 1024M
mirage-core:
build:
context: .
dockerfile: Dockerfile
depends_on:
postgres:
condition: service_healthy
env_file: .env
environment:
DB_HOST: postgres
DB_PORT: 5432
DB_USER: ${DB_USER:-mirage}
DB_NAME: ${DB_NAME:-mirage}
# Adaptive deception -- off by default (see .env.example).
# Deliberately NOT a `depends_on` on mirage-deception below: the SSH
# server must start and run identically whether or not that service
# exists, builds, or is healthy. deception.Client fails safe to
# ActionMinimal on any error, so this is safe to leave wired even when
# MIRAGE_DECEPTION_ENABLED is false or the service is briefly down.
MIRAGE_DECEPTION_ENABLED: "${MIRAGE_DECEPTION_ENABLED:-false}"
MIRAGE_DECEPTION_URL: "http://mirage-deception:8787"
MIRAGE_DECEPTION_TIMEOUT_MS: "${MIRAGE_DECEPTION_TIMEOUT_MS:-200}"
MIRAGE_DECEPTION_APPLY_ACTIONS: "${MIRAGE_DECEPTION_APPLY_ACTIONS:-false}"
# LLM shell-completion fallback -- independent of the RL policy above.
# Off by default; when on, a command with no builtin may be answered by
# a generated response instead of "command not found". Never fires for
# builtins, compound lines, or egress-flavoured commands (see
# internal/deception/completion.go).
MIRAGE_LLM_SHELL_ENABLED: "${MIRAGE_LLM_SHELL_ENABLED:-false}"
MIRAGE_LLM_SHELL_TIMEOUT_MS: "${MIRAGE_LLM_SHELL_TIMEOUT_MS:-4000}"
# Identifies this deployment's heartbeat rows for the data-validity
# dashboard's downtime-vs-silence check (internal/validity). Only
# matters once more than one sensor writes into a shared/aggregated
# setup -- a single deployment can leave this at the default.
SENSOR_ID: "${SENSOR_ID:-default}"
# Off by default -- unset MIRAGE_FLEET_API_KEY makes fleet.Client a
# no-op (see internal/fleet), so this sensor behaves identically
# whether or not a mirage-fleet instance exists or is reachable, same
# fail-safe pattern as MIRAGE_DECEPTION_ENABLED above.
MIRAGE_FLEET_URL: "${MIRAGE_FLEET_URL:-}"
MIRAGE_FLEET_API_KEY: "${MIRAGE_FLEET_API_KEY:-}"
MIRAGE_FLEET_TIMEOUT_MS: "${MIRAGE_FLEET_TIMEOUT_MS:-3000}"
MIRAGE_FLEET_HEARTBEAT_INTERVAL_SECONDS: "${MIRAGE_FLEET_HEARTBEAT_INTERVAL_SECONDS:-60}"
MIRAGE_FLEET_QUEUE_PATH: "/app/data/fleet_queue.jsonl"
MIRAGE_FLEET_QUEUE_MAX_BYTES: "${MIRAGE_FLEET_QUEUE_MAX_BYTES:-67108864}"
volumes:
- ./config/hostkey:/app/config/hostkey:ro
# Optional: offered alongside ed25519 like a stock Ubuntu sshd. Run
# scripts/generate_hostkey.sh first; if missing, the sensor warns and
# serves ed25519 only.
- ./config/hostkey_rsa:/app/config/hostkey_rsa:ro
- ./config/hostkey_ecdsa:/app/config/hostkey_ecdsa:ro
# Must survive container restarts: this is where an undelivered
# session's data lives while mirage-fleet is unreachable (see
# DECISIONS.md "delivery reliability" in mirage-fleet) -- losing it on
# every redeploy would defeat the point of queuing at all.
- fleet_queue:/app/data
ports:
- "22:2222"
restart: unless-stopped
deploy:
resources:
limits:
memory: 256M
ml-worker:
build:
context: .
dockerfile: bridge/Dockerfile
depends_on:
postgres:
condition: service_healthy
env_file: .env
environment:
PYTHONUNBUFFERED: "1"
DB_HOST: postgres
DB_PORT: 5432
DB_USER: ${DB_USER:-mirage}
DB_NAME: ${DB_NAME:-mirage}
BRIDGE_POLL_INTERVAL_S: "10"
BRIDGE_BATCH_SIZE: "32"
# MIRAGE_MODEL_CHECKPOINT: /app/artifacts/embedder/best.pt
# MIRAGE_TOKENIZER_DIR: /app/artifacts/embedder/tokenizer
# MIRAGE_MODEL_VERSION: mirage-emb-v1
# Phase-4 LLM threat-intel summaries -- off by default since it costs
# real API calls. To enable, uncomment and put ANTHROPIC_API_KEY in .env:
# MIRAGE_INTEL_USE_LLM: "1"
# MIRAGE_INTEL_MODEL: claude-opus-4-8
# STIX 2.1 export is pure-stdlib, deterministic, and has no external
# dependency or cost, so unlike the LLM flag above it's on by default.
MIRAGE_STIX_ENABLED: "1"
volumes:
- ./artifacts:/app/artifacts:ro
restart: unless-stopped
deploy:
resources:
limits:
memory: 1024M
mirage-deception:
# Reuses the bridge image -- `pip install /app/ml` in bridge/Dockerfile
# already installs mirage.deception, so no new Dockerfile is needed; only
# the entrypoint differs (serve.py's HTTP loop instead of the bridge's
# poll loop).
build:
context: .
dockerfile: bridge/Dockerfile
entrypoint: ["python", "-m", "mirage.deception.serve"]
# No depends_on and no external port publish: mirage-core reaches this by
# service name on the compose network, and it needs nothing from
# postgres. Not required for mirage-core to start -- see the comment on
# mirage-core's MIRAGE_DECEPTION_* block above.
env_file: .env
environment:
PYTHONUNBUFFERED: "1"
# Checkpoints are committed under ml/mirage/deception/ and land at
# /app/ml/mirage/deception/ inside the image via bridge/Dockerfile's
# `COPY ml/ /app/ml/` -- no host-side artifact file needed by default.
# Override to /app/artifacts/deception/<file> (and populate ./artifacts/)
# to run a newer checkpoint without rebuilding the image.
MIRAGE_DECEPTION_CHECKPOINT: "${MIRAGE_DECEPTION_CHECKPOINT:-/app/ml/mirage/deception/ppo.pt}"
MIRAGE_DECEPTION_ALGO: "${MIRAGE_DECEPTION_ALGO:-ppo}"
MIRAGE_DECEPTION_PORT: "8787"
MIRAGE_DECEPTION_MAX_STEPS: "${MIRAGE_DECEPTION_MAX_STEPS:-25}"
MIRAGE_DECEPTION_SESSION_TTL_SECONDS: "${MIRAGE_DECEPTION_SESSION_TTL_SECONDS:-900}"
# LLM shell completion. Providers are declared as JSON; each entry names
# the ENV VAR holding its key, never the key itself. With none declared
# the /complete endpoint simply reports itself unavailable.
MIRAGE_LLM_SHELL_PROVIDERS_JSON: "${MIRAGE_LLM_SHELL_PROVIDERS_JSON:-}"
MIRAGE_LLM_SHELL_ACTIVE_PROVIDER: "${MIRAGE_LLM_SHELL_ACTIVE_PROVIDER:-}"
MIRAGE_LLM_SHELL_MAX_PER_SESSION: "${MIRAGE_LLM_SHELL_MAX_PER_SESSION:-25}"
MIRAGE_LLM_SHELL_GLOBAL_RATE_LIMIT: "${MIRAGE_LLM_SHELL_GLOBAL_RATE_LIMIT:-600}"
ANTHROPIC_API_KEY: "${ANTHROPIC_API_KEY:-}"
OPENAI_API_KEY: "${OPENAI_API_KEY:-}"
volumes:
- ./artifacts:/app/artifacts:ro
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8787/health', timeout=2)"]
interval: 15s
timeout: 5s
retries: 5
start_period: 10s
restart: unless-stopped
deploy:
resources:
limits:
memory: 512M
mirage-api:
build:
context: .
dockerfile: Dockerfile.api
depends_on:
postgres:
condition: service_healthy
env_file: .env
environment:
DB_HOST: postgres
DB_PORT: 5432
DB_USER: ${DB_USER:-mirage}
DB_NAME: ${DB_NAME:-mirage}
API_KEY: ${API_KEY}
# Read-only: the dashboard's LLM panel lists/switches providers through
# the deception service. Not a depends_on -- the panel degrades to
# "not configured" when that service isn't running.
MIRAGE_DECEPTION_URL: "http://mirage-deception:8787"
ports:
- "127.0.0.1:8080:8080"
restart: unless-stopped
deploy:
resources:
limits:
memory: 768M
mirage-telnet:
build:
context: .
dockerfile: Dockerfile.telnet
depends_on:
postgres:
condition: service_healthy
env_file: .env
environment:
DB_HOST: postgres
DB_PORT: 5432
DB_USER: ${DB_USER:-mirage}
DB_NAME: ${DB_NAME:-mirage}
SENSOR_ID: "${TELNET_SENSOR_ID:-telnet}"
ports:
- "23:2323"
restart: unless-stopped
deploy:
resources:
limits:
memory: 512M
volumes:
postgres_data:
fleet_queue:
networks:
default:
# Named explicitly so mirage-web's separate compose file (own repo) can
# join it as an `external` network by a stable name instead of guessing
# compose's auto-generated "<project>_default".
name: mirage_net