first commit

This commit is contained in:
2026-10-09 02:48:31 +07:00
commit 8db22bfaa6
17 changed files with 1722 additions and 0 deletions
@@ -0,0 +1,104 @@
# =============================================================================
# docker-socket-proxy + gateway nginx (api-key) — per host SiCABE.
#
# Control-panel (sicabe-control-panel) TIDAK pernah menyentuh /var/run/docker.sock
# langsung. Di setiap host yang dikelola dipasang stack ini; panel berbicara ke
# endpoint HTTP gateway (lihat desain:
# docs/desain-kontrol-multi-host-docker-socket-proxy.md).
#
# Arsitektur:
# panel ──HTTP + X-Api-Key──► gateway (nginx, allowlist path)
# └──► docker-proxy (docker-socket-proxy, ACL)
# └──► /var/run/docker.sock (:ro)
#
# Keamanan (jangan longgarkan tanpa kebutuhan):
# * Socket daemon di-mount READ-ONLY (:ro).
# * docker-socket-proxy TIDAK punya auth — container tsb HANYA di jaringan
# internal compose (expose, tanpa port host). Yang diekspos ke host hanyalah
# gateway nginx.
# * nginx memeriksa header `X-Api-Key` (wajib sama dengan PROXY_API_KEY) dan
# allowlist path (hanya route yang dibutuhkan kontrol, sisanya 403).
# * ACL docker-socket-proxy hanya mengizinkan yang dibutuhkan:
# CONTAINERS (list/inspect/restart/stop/start/logs/top), POST (restart),
# INFO (version/ping), SYSTEM (/events).
# Kategori lain (EXEC, BUILD, IMAGES, NETWORKS, VOLUMES, ...) DIMATIKAN.
# * Versi image DIPATOK (bukan :latest) untuk produksi.
#
# Mode alternatif SSH-tunnel / single-host (tanpa api-key):
# Hapus/komentari service `gateway`, lalu pada service `docker-proxy` ganti
# `expose` dengan port publik:
# ports:
# - "127.0.0.1:${PROXY_PORT:-22375}:2375"
#
# Cara pakai (HTTP + api-key):
# PROXY_API_KEY='<secret-acak-kuat>' PROXY_BIND_IP=127.0.0.1 PROXY_PORT=22375 \
# docker compose up -d
# - PROXY_API_KEY WAJIB diisi (compose akan error bila kosong). Ini secret —
# jangan di-commit; isi via env/deploy.
# - PROXY_BIND_IP: 127.0.0.1 utk single-host/SSH-tunnel; IP internal host bila
# panel di host lain dalam network tepercaya. JANGAN expose ke internet.
# - Panel: SICABE_HOSTS=[{"name":"...","proxyUrl":"http://<bind-ip>:<port>",
# "apiKey":"<PROXY_API_KEY>","enabled":true}]
# =============================================================================
name: sicabe-docker-proxy
services:
# --- docker-socket-proxy: ACL, hanya di jaringan internal compose ---------
docker-proxy:
image: tecnativa/docker-socket-proxy:v0.5.0
container_name: sicabe-docker-proxy
environment:
# --- ACL: hanya yang dibutuhkan kontrol ---
CONTAINERS: "1" # list/inspect/restart/stop/start/logs/top
POST: "1" # dibutuhkan utk restart/start/stop
INFO: "1" # info daemon (version, /_ping, healthcheck)
SYSTEM: "1" # /events (feed Observability). Set "0" bila tak dipakai
# --- matikan semua yang tidak perlu ---
EXEC: "0"
SWARM: "0"
SERVICES: "0"
SECRETS: "0"
CONFIGS: "0"
NETWORKS: "0"
VOLUMES: "0"
IMAGES: "0"
BUILD: "0"
GRPC: "0"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
expose:
- "2375" # hanya reachable dari gateway (network compose)
read_only: true
tmpfs:
- /tmp
- /run # HAProxy menulis pidfile /run/haproxy.pid
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
# --- gateway nginx: api-key + allowlist path (satu-satunya port ke host) --
gateway:
image: nginx:1.30.4-alpine3.24
container_name: sicabe-docker-proxy-gateway
depends_on:
- docker-proxy
environment:
# WAJIB: compose error bila PROXY_API_KEY tidak di-set.
PROXY_API_KEY: ${PROXY_API_KEY:?PROXY_API_KEY wajib diisi (secret acak kuat)}
ports:
- "${PROXY_BIND_IP:-127.0.0.1}:${PROXY_PORT:-22375}:80"
volumes:
# Template di-substitute oleh envsubst docker-entrypoint nginx saat start
# (${PROXY_API_KEY} diganti nilai env; $http_* tetap utuh) → output ke
# /etc/nginx/conf.d/default.conf (menggantikan default bawaan image).
- ./nginx/gateway.conf.template:/etc/nginx/templates/default.conf.template:ro
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
@@ -0,0 +1,54 @@
# nginx gateway untuk docker-socket-proxy.
#
# File ini adalah TEMPLATE: pada container start, docker-entrypoint nginx
# menjalankan envsubst dan mengganti ${PROXY_API_KEY} dengan nilai env
# PROXY_API_KEY (variabel nginx seperti $http_x_api_key TIDAK ikut diganti),
# lalu menulis hasilnya ke /etc/nginx/conf.d/default.conf.
#
# Kebijakan:
# * Semua request WAJIB membawa header `X-Api-Key` == PROXY_API_KEY (401 bila
# salah/kosong). nginx membalas 401 TANPA meneruskan ke proxy.
# * Allowlist path (desain §2): hanya route yang dibutuhkan KONTROL oleh
# control-panel. Selain itu di-block 403 — termasuk route berbahaya
# (exec, create, images, networks, volumes, dll) sekalipun ACL proxy longgar.
# * Aksi tulis restart/start/stop hanya via POST (selainnya 405).
server {
listen 80 default_server;
server_name _;
# ==== API-key check (sebelum diproses location mana pun) ====
if ($http_x_api_key != "${PROXY_API_KEY}") {
return 401;
}
# ==== Route yang diizinkan (allowlist) ====
# Health/info daemon + event stream
location = /_ping { proxy_pass http://docker-proxy:2375; }
location = /version { proxy_pass http://docker-proxy:2375; }
location = /info { proxy_pass http://docker-proxy:2375; }
location = /events { proxy_pass http://docker-proxy:2375; }
# List container (tanpa id) — GET /containers/json
location = /containers/json { proxy_pass http://docker-proxy:2375; }
# Operasi per-container yang dibutuhkan kontrol/observability
location ~ ^/containers/[^/]+/json$ { proxy_pass http://docker-proxy:2375; }
location ~ ^/containers/[^/]+/logs$ { proxy_pass http://docker-proxy:2375; }
location ~ ^/containers/[^/]+/stats$ { proxy_pass http://docker-proxy:2375; }
location ~ ^/containers/[^/]+/top$ { proxy_pass http://docker-proxy:2375; }
# Aksi tulis — hanya POST (restart/start/stop)
location ~ ^/containers/[^/]+/(restart|start|stop)$ {
if ($request_method != POST) {
return 405;
}
proxy_pass http://docker-proxy:2375;
}
# ==== Semua path lain di-block ====
location / {
return 403;
}
}