mirror of
https://github.com/nextcloud/all-in-one.git
synced 2026-07-22 06:02:54 +00:00
00db9a9af0
This mitigates possible misuse better than before. Signed-off-by: Pablo Zmdl <pablo@nextcloud.com> AI-assistant: Claude code (Sonnet 5)
81 lines
4.8 KiB
INI
81 lines
4.8 KiB
INI
# Inspiration: https://github.com/Tecnativa/docker-socket-proxy/blob/master/haproxy.cfg
|
|
|
|
global
|
|
maxconn 10
|
|
|
|
defaults
|
|
timeout connect 30s
|
|
timeout client 30s
|
|
timeout server 1800s
|
|
|
|
frontend http
|
|
mode http
|
|
bind :::2375 v4v6
|
|
http-request deny unless { src 127.0.0.1 } || { src ::1 } || { src NC_IPV4_PLACEHOLDER } || { src NC_IPV6_PLACEHOLDER }
|
|
# ACL to detect JSON \uXXXX unicode escape sequences in the request body.
|
|
# All values we accept (names, types, etc.) are restricted to plain ASCII
|
|
# (e.g. ^nc_app_[a-zA-Z0-9_.-]+), so a legitimate request never needs one.
|
|
# Without this, an attacker can hide literal strings such as "device" or
|
|
# "Binds" from the other regex-based ACLs below by encoding a character as
|
|
# e.g. "\u0064evice", bypassing those keyword checks entirely.
|
|
acl body_has_unicode_escape req.body -m reg -i "\\\\u[0-9a-f]{4}"
|
|
http-request deny if body_has_unicode_escape
|
|
|
|
# docker system _ping
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/_ping$ } METH_GET
|
|
# docker inspect image: GET images/%s/json
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/images/.*/json } METH_GET
|
|
# container inspect: GET containers/%s/json
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/json } METH_GET
|
|
# container inspect: GET containers/%s/logs
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/logs } METH_GET
|
|
# container start/stop: POST containers/%s/start containers/%s/stop
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/((start)|(stop)) } METH_POST
|
|
# container rm: DELETE containers/%s
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+ } METH_DELETE
|
|
# container update/exec: POST containers/%s/update containers/%s/exec
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/((update)|(exec)) } METH_POST
|
|
# container put: PUT containers/%s/archive
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/nc_app_[a-zA-Z0-9_.-]+/archive } METH_PUT
|
|
# run exec instance: POST exec/%s
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/exec/[a-zA-Z0-9_.-]+/start } METH_POST
|
|
|
|
# container create: POST containers/create?name=%s
|
|
# ACL to restrict container name to nc_app_[a-zA-Z0-9_.-]+
|
|
acl nc_app_container_name url_param(name) -m reg -i "^nc_app_[a-zA-Z0-9_.-]+"
|
|
|
|
# ACL to restrict the number of Mounts to 1
|
|
acl one_mount_volume req.body -m reg -i "\"Mounts\"\s*:\s*\[\s*(?:(?!\"Mounts\"\s*:\s*\[)[^}]*)}[^}]*\]"
|
|
# ACL to deny if there are any binds
|
|
acl binds_present req.body -m reg -i "\"HostConfig\"\s*:.*\"Binds\"\s*:"
|
|
# ACL to restrict the type of Mounts to volume
|
|
acl type_not_volume req.body -m reg -i "\"Mounts\"\s*:\s*\[[^\]]*(\"Type\"\s*:\s*\"(?!volume\b)\w+\"[^\]]*)+\]"
|
|
# Deny if HostConfig.Binds is present, independently of other mounts or volumes
|
|
http-request deny if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/create } nc_app_container_name binds_present
|
|
# Deny if required conditions are not met.
|
|
http-request deny if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/create } nc_app_container_name !one_mount_volume type_not_volume METH_POST
|
|
|
|
# ACL to restrict container creation, that it has HostConfig.Privileged(by searching for "Privileged" word in all payload)
|
|
acl no_privileged_flag req.body -m reg -i "\"Privileged\""
|
|
# ACL to allow mount volume with strict pattern for name: nc_app_[a-zA-Z0-9_.-]+_data
|
|
acl nc_app_volume_data_only req.body -m reg -i "\"Mounts\"\s*:\s*\[\s*{[^}]*\"Source\"\s*:\s*\"nc_app_[a-zA-Z0-9_.-]+_data\""
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/create } nc_app_container_name !no_privileged_flag nc_app_volume_data_only METH_POST
|
|
# end of container create
|
|
|
|
# volume create: POST volumes/create
|
|
# restrict name
|
|
acl nc_app_volume_data req.body -m reg -i "\"Name\"\s*:\s*\"nc_app_[a-zA-Z0-9_.-]+_data\""
|
|
# do not allow to use "device" word e.g., "--opt device=:/path/to/dir"
|
|
acl volume_no_device req.body -m reg -i "\"device\""
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/volumes/create } nc_app_volume_data !volume_no_device METH_POST
|
|
# volume rm: DELETE volumes/%s
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/volumes/nc_app_[a-zA-Z0-9_.-]+_data } METH_DELETE
|
|
# image pull: POST images/create?fromImage=%s
|
|
http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/images/create } METH_POST
|
|
http-request deny
|
|
default_backend dockerbackend
|
|
|
|
backend dockerbackend
|
|
mode http
|
|
server dockersocket /var/run/docker.sock
|