-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathdocker-compose-stack.yml
More file actions
158 lines (153 loc) · 5.69 KB
/
Copy pathdocker-compose-stack.yml
File metadata and controls
158 lines (153 loc) · 5.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
# Portions derived from the XNAT docker-compose project
# Copyright (c) 2020, Washington University School of Medicine
# Licensed under the BSD 2-Clause License.
# SPDX-License-Identifier: BSD-2-Clause
#
# Modifications Copyright (c) 2026,
# Guy's and St Thomas' NHS Foundation Trust & King's College London
# version: '3.7'
services:
xnat-web:
image: ${DOCKER_REGISTRY}xnat-web:${XNAT_TAG}
deploy:
replicas: 1
restart_policy:
condition: any
placement:
constraints: [node.role == manager]
ports:
- ${XNAT_PORT}:8080
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
environment:
- CATALINA_OPTS=-Xms${XNAT_MIN_HEAP} -Xmx${XNAT_MAX_HEAP} -Dxnat.home=${XNAT_HOME} -XX:+UseG1GC -Djava.awt.headless=true -XX:+ParallelRefProcEnabled -XX:ParallelGCThreads=6 -XX:+UseStringDeduplication
- XNAT_HOME=${XNAT_HOME}
- XNAT_ADMIN_USER=${XNAT_ADMIN_USER}
- XNAT_ADMIN_INITIAL_PASSWORD=${XNAT_ADMIN_INITIAL_PASSWORD}
- XNAT_ADMIN_PASSWORD=${XNAT_ADMIN_PASSWORD}
- XNAT_SERVICE_USER=${XNAT_SERVICE_USER}
- XNAT_SERVICE_PASSWORD=${XNAT_SERVICE_PASSWORD}
- XNAT_PORT=${XNAT_PORT}
- PACS_DICOM_PORT=${PACS_DICOM_PORT}
# Dual-homed: the trust overlay for everything else, plus the stack-scoped
# socket-proxy network — the only route to the Docker API proxy below.
networks:
- default
- socket-proxy
xnat-db:
image: ${DOCKER_REGISTRY}xnat-db:${XNAT_TAG}
# Raise max_connections above the Postgres default (100). During a bulk DQR
# import XNAT opens many concurrent build connections, and an xnat-web restart
# briefly doubles the count (the old task's connections linger until reaped),
# which exhausted the pool and locked out even admin queries (FLIP#662).
command:
- postgres
- -c
- max_connections=300
- -c
- shared_buffers=512MB
deploy:
replicas: 1
restart_policy:
condition: any
placement:
constraints: [node.role == manager]
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- DAC_OVERRIDE
- FOWNER
- SETUID
- SETGID
environment:
- POSTGRES_PASSWORD=${XNAT_DATASOURCE_ADMIN_PASSWORD}
- POSTGRES_DB=${XNAT_DATASOURCE_NAME}
# variables for the sql script
- XNAT_DATASOURCE_USERNAME=${XNAT_DATASOURCE_USERNAME}
- XNAT_DATASOURCE_PASSWORD=${XNAT_DATASOURCE_PASSWORD}
xnat-nginx:
image: ${DOCKER_REGISTRY}xnat-nginx:${XNAT_TAG}
deploy:
replicas: 1
restart_policy:
condition: any
placement:
constraints: [node.role == manager]
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- CHOWN
- NET_BIND_SERVICE
# ports:
# - "80:80"
# Filtered gateway to the host Docker API for the Container Service plugin.
# xnat-web does not mount the Docker socket: the plugin reaches Docker over
# tcp://xnat-socket-proxy:2375 (set in xnat/config/container-service-backend-
# configuration.json), and only this proxy holds the (root-equivalent) socket.
# The proxy lives on the stack-scoped internal socket-proxy network (below),
# NOT the shared trust overlay — only the dual-homed xnat-web can reach it;
# trust-api, imaging-api, data-access-api, fl-client etc. have no route.
# A compromised xnat-web is left with the allowlisted API groups below —
# notably it can no longer exec into containers or reach the container,
# volume, network and secret APIs at all. It is a choke point, not a sandbox:
# the services API that dcm2niix launches require can itself create services
# with host bind mounts (FLIP#485).
xnat-socket-proxy:
image: tecnativa/docker-socket-proxy:v0.4.2
deploy:
replicas: 1
restart_policy:
condition: any
placement:
# The services API is only served by a manager's Docker socket.
constraints: [node.role == manager]
security_opt:
- no-new-privileges:true
# No cap_add at all: haproxy (v0.4.2) runs as root, which owns the socket,
# so it connects with an empty capability set.
cap_drop:
- ALL
environment:
# The Container Service (swarm mode) launches dcm2niix as a one-shot swarm
# service: create/inspect/logs/remove need SERVICES (+ POST for the
# mutating calls), job state tracking needs TASKS, scheduling info needs
# NODES, and pull-images-on-xnat-init needs IMAGES. PING/VERSION/EVENTS
# are the proxy's defaults; the container, exec, volume, network, secret,
# config, plugin and build APIs all stay blocked (verified 403 from
# xnat-web).
- POST=1
- SERVICES=1
- TASKS=1
- NODES=1
- IMAGES=1
- INFO=1
# The Container Service's swarm-mode connection test is a swarm inspect
# (GET /swarm) — without this the /xapi/docker/server/ping gate in
# configure-dcm2niix.sh fails 403. The proxy's POST switch is global, so
# this also exposes POST /swarm/* (join/leave/update); that is strictly
# weaker than the services API the Container Service already requires,
# which can create services with arbitrary host mounts.
- SWARM=1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- socket-proxy
networks:
default:
name: ${DOCKER_NETWORK_NAME}
external: true
# Dedicated network for xnat-web -> xnat-socket-proxy traffic. Swarm prefixes
# it per stack (<stack>_socket-proxy), so each trust's proxy is reachable only
# from its own xnat-web. internal: the proxy needs no egress, only the socket.
socket-proxy:
driver: overlay
internal: true