From dfd09ab7f1940f170f13261e7af58d0a72a4abf9 Mon Sep 17 00:00:00 2001 From: sukhman Date: Mon, 23 Mar 2026 02:00:18 +0530 Subject: [PATCH 1/5] dockerize beast --- Dockerfile.app | 40 ++++++++++++++++++++++++++++++ Makefile | 61 ++++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 13 ++++++++++ setup.sh | 60 +++++++++++++++++++++++++++++++++++++-------- 4 files changed, 164 insertions(+), 10 deletions(-) create mode 100644 Dockerfile.app create mode 100644 docker-compose.yml diff --git a/Dockerfile.app b/Dockerfile.app new file mode 100644 index 00000000..83579750 --- /dev/null +++ b/Dockerfile.app @@ -0,0 +1,40 @@ +FROM golang:1.23 AS builder + +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . + +RUN CGO_ENABLED=0 GOOS=linux go build \ + -tags netgo \ + -o /beast \ + github.com/sdslabs/beastv4/cmd/beast + +FROM ubuntu:22.04 + +RUN apt-get update && apt-get install -y \ + ca-certificates \ + gcc \ + util-linux \ + docker.io \ + && rm -rf /var/lib/apt/lists/* + +COPY scripts/importenv.c /tmp/importenv.c +RUN gcc -o /usr/bin/importenv /tmp/importenv.c && rm /tmp/importenv.c + +COPY scripts/docker-enter /usr/bin/docker-enter +COPY scripts/docker_enter /usr/bin/docker_enter +RUN chmod +x /usr/bin/docker-enter && chmod u+s /usr/bin/docker_enter + +# Copy beast binary +COPY --from=builder /beast /usr/local/bin/beast + +# setup.sh handles both local dev and container startup +COPY setup.sh /usr/local/bin/setup.sh +RUN chmod +x /usr/local/bin/setup.sh + +EXPOSE 5005 + +ENTRYPOINT ["setup.sh"] diff --git a/Makefile b/Makefile index 00c9f9f8..feaa0652 100644 --- a/Makefile +++ b/Makefile @@ -81,3 +81,64 @@ installenv: @./scripts/installenv.sh .PHONY: build format test check_format tools docs installenv + +# ── Docker Compose Targets ──────────────────────────────────────────────────── +# Usage: make up NAME=myctf +# +# NAME (required, no spaces) — used to create a . folder on the host which +# is mounted as /root/.beast inside the beast container. This keeps each +# deployment isolated and named. +# +# Prerequisites: +# - config.toml must exist alongside this Makefile. +# - In config.toml set psql_config.host = "postgres" (the compose service name). +# +# Targets: +# make up NAME= — set up ./, copy config, start services +# make down NAME= — stop and remove services +# make logs NAME= — tail beast service logs + +check-name: + @if [ -z "$(NAME)" ]; then \ + echo "Error: NAME is required. Usage: make up NAME=myctf"; \ + exit 1; \ + fi + @if echo "$(NAME)" | grep -q "[[:space:]]"; then \ + echo "Error: NAME must not contain spaces"; \ + exit 1; \ + fi + +check-config: + @if [ ! -f "config.toml" ]; then \ + echo "Error: config.toml not found in current directory."; \ + echo "Place your config.toml here (see _examples/example.config.toml)."; \ + echo "Ensure psql_config.host = \"postgres\" for the compose network."; \ + exit 1; \ + fi + +setup-beast-dir: check-name check-config + @echo "[*] Setting up .$(NAME) directory..." + @mkdir -p .$(NAME)/assets/logo + @mkdir -p .$(NAME)/assets/mailTemplates + @mkdir -p .$(NAME)/remote + @mkdir -p .$(NAME)/uploads + @mkdir -p .$(NAME)/secrets + @mkdir -p .$(NAME)/scripts + @mkdir -p .$(NAME)/staging + @mkdir -p .$(NAME)/cache + @mkdir -p .$(NAME)/logs + @cp config.toml .$(NAME)/config.toml + @echo "[*] .$(NAME) ready (mounted as /root/.beast in container)" + +up: setup-beast-dir + @echo "[*] Starting beast services (project: $(NAME))..." + @BEAST_DIR=.$(NAME) docker compose --project-name $(NAME) up -d --build + @echo "[*] Beast API running at http://localhost:5005" + +down: check-name + @docker compose --project-name $(NAME) down + +logs: check-name + @docker compose --project-name $(NAME) logs -f beast + +.PHONY: check-name check-config setup-beast-dir up down logs diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..7d1f98f0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,13 @@ +services: + beast: + build: + context: . + dockerfile: Dockerfile.app + ports: + - "${BEAST_PORT:-5005}:5005" + volumes: + - ${BEAST_DIR}:/root/.beast + - /var/run/docker.sock:/var/run/docker.sock + environment: + - HOME=/root + restart: unless-stopped diff --git a/setup.sh b/setup.sh index ae8d4bab..5d96f2f5 100755 --- a/setup.sh +++ b/setup.sh @@ -1,35 +1,75 @@ #!/bin/bash +# Detect if running inside a Docker container +IN_CONTAINER=false +[ -f /.dockerenv ] && IN_CONTAINER=true + echo -e "Setting up sample environment for beast..." +# In container, HOME=/root; locally, use /home/$USER +if [ "$IN_CONTAINER" = true ]; then + BEAST_HOME="$HOME" +else + BEAST_HOME="/home/$USER" +fi + # Creating required directories -mkdir -p "/home/$USER/.beast" "/home/$USER/.beast/assets/logo" "/home/$USER/.beast/assets/mailTemplates" "/home/$USER/.beast/remote" "/home/$USER/.beast/uploads" "/home/$USER/.beast/secrets" "/home/$USER/.beast/scripts" "/home/$USER/.beast/staging" +mkdir -p \ + "${BEAST_HOME}/.beast" \ + "${BEAST_HOME}/.beast/assets/logo" \ + "${BEAST_HOME}/.beast/assets/mailTemplates" \ + "${BEAST_HOME}/.beast/remote" \ + "${BEAST_HOME}/.beast/uploads" \ + "${BEAST_HOME}/.beast/secrets" \ + "${BEAST_HOME}/.beast/scripts" \ + "${BEAST_HOME}/.beast/staging" \ + "${BEAST_HOME}/.beast/cache" \ + "${BEAST_HOME}/.beast/logs" -# Creating random authorized_keys and secret.key files -echo -e "auth_keys" >/home/$USER/.beast/authorized_keys -echo -e "auth_keys" >/home/$USER/.beast/secret.key +# Creating placeholder authorized_keys and secret.key files if absent +[ ! -f "${BEAST_HOME}/.beast/beast_authorized_keys" ] && touch "${BEAST_HOME}/.beast/beast_authorized_keys" +[ ! -f "${BEAST_HOME}/.beast/secret.key" ] && touch "${BEAST_HOME}/.beast/secret.key" -BEAST_GLOBAL_CONFIG=~/.beast/config.toml -EXAMPLE_CONFIG_FILE=./_examples/example.config.toml +BEAST_GLOBAL_CONFIG="${BEAST_HOME}/.beast/config.toml" +EXAMPLE_CONFIG_FILE="./_examples/example.config.toml" if [ -f "$BEAST_GLOBAL_CONFIG" ]; then echo -e "Found $BEAST_GLOBAL_CONFIG" else + if [ "$IN_CONTAINER" = true ]; then + echo -e "\e[31mconfig.toml not found at ${BEAST_GLOBAL_CONFIG}" + echo -e "\e[31mMount your config.toml to ${BEAST_GLOBAL_CONFIG} and retry." + exit 1 + fi + if [ -f "$EXAMPLE_CONFIG_FILE" ]; then echo -e "Copying example config file" - cp ./_examples/example.config.toml $BEAST_GLOBAL_CONFIG + cp ./_examples/example.config.toml "$BEAST_GLOBAL_CONFIG" else echo -e '\e[93mCould not find example.config.toml' echo -e 'Downloading example.config.toml' wget https://raw.githubusercontent.com/sdslabs/beast/master/_examples/example.config.toml - cp ./example.config.toml $BEAST_GLOBAL_CONFIG + cp ./example.config.toml "$BEAST_GLOBAL_CONFIG" exit fi - sed -i "s/vsts/$USER/g" $BEAST_GLOBAL_CONFIG + sed -i "s/vsts/$USER/g" "$BEAST_GLOBAL_CONFIG" fi echo -e "Created .beast folder..." +# ── Container path: binary already built, just start beast ─────────────────── +if [ "$IN_CONTAINER" = true ]; then + echo -e "Checking Docker socket..." + if [ ! -S /var/run/docker.sock ]; then + echo -e "\e[31mDocker socket not found at /var/run/docker.sock" + echo -e "\e[31mMount the host Docker socket and retry." + exit 1 + fi + echo -e "Docker socket available. Starting beast..." + exec beast run -v +fi + +# ── Local path: build then advise the user to run beast ────────────────────── echo -e "Building beast..." export GO111MODULES=on @@ -42,7 +82,7 @@ if [ -z "$GOPATH" ]; then fi echo -e 'checking if docker is running...' -# Checking if docker deamon is running or not by checking its PID +# Checking if docker daemon is running or not by checking its PID DOCKER_PID_FILE=/var/run/docker.pid if [ -f "$DOCKER_PID_FILE" ]; then echo -e "Docker is running." From 9eff114f8d470c9282566255247a06931640fe86 Mon Sep 17 00:00:00 2001 From: sukhman Date: Mon, 23 Mar 2026 03:09:49 +0530 Subject: [PATCH 2/5] Fix setup --- Dockerfile.app | 32 ++++++++++++-------------------- docker-compose.yml | 1 + setup.sh | 4 +++- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/Dockerfile.app b/Dockerfile.app index 83579750..1961b34b 100644 --- a/Dockerfile.app +++ b/Dockerfile.app @@ -1,5 +1,9 @@ FROM golang:1.23 AS builder +RUN apt-get update && apt-get install -y \ + make git gcc util-linux \ + && rm -rf /var/lib/apt/lists/* + WORKDIR /app COPY go.mod go.sum ./ @@ -7,31 +11,19 @@ RUN go mod download COPY . . -RUN CGO_ENABLED=0 GOOS=linux go build \ - -tags netgo \ - -o /beast \ - github.com/sdslabs/beastv4/cmd/beast +RUN cp scripts/docker-enter /usr/bin/docker-enter && \ + cp scripts/docker_enter /usr/bin/docker_enter && \ + chmod u+s /usr/bin/docker_enter && \ + gcc -o /usr/bin/importenv scripts/importenv.c + +RUN make build FROM ubuntu:22.04 -RUN apt-get update && apt-get install -y \ - ca-certificates \ - gcc \ - util-linux \ - docker.io \ +RUN apt-get update && apt-get install -y ca-certificates \ && rm -rf /var/lib/apt/lists/* -COPY scripts/importenv.c /tmp/importenv.c -RUN gcc -o /usr/bin/importenv /tmp/importenv.c && rm /tmp/importenv.c - -COPY scripts/docker-enter /usr/bin/docker-enter -COPY scripts/docker_enter /usr/bin/docker_enter -RUN chmod +x /usr/bin/docker-enter && chmod u+s /usr/bin/docker_enter - -# Copy beast binary -COPY --from=builder /beast /usr/local/bin/beast - -# setup.sh handles both local dev and container startup +COPY --from=builder /go/bin/beast /usr/local/bin/beast COPY setup.sh /usr/local/bin/setup.sh RUN chmod +x /usr/local/bin/setup.sh diff --git a/docker-compose.yml b/docker-compose.yml index 7d1f98f0..a77f20a2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,4 +10,5 @@ services: - /var/run/docker.sock:/var/run/docker.sock environment: - HOME=/root + - BEAST_FLAGS=${BEAST_FLAGS:--v} restart: unless-stopped diff --git a/setup.sh b/setup.sh index 5d96f2f5..76648c90 100755 --- a/setup.sh +++ b/setup.sh @@ -66,7 +66,9 @@ if [ "$IN_CONTAINER" = true ]; then exit 1 fi echo -e "Docker socket available. Starting beast..." - exec beast run -v + BEAST_FLAGS="${BEAST_FLAGS:--v}" + echo -e "Running: beast run ${BEAST_FLAGS}" + exec beast run ${BEAST_FLAGS} fi # ── Local path: build then advise the user to run beast ────────────────────── From 1378c71c4de4154e0a0c8f2fc5825b7e1074caf3 Mon Sep 17 00:00:00 2001 From: sukhman Date: Mon, 23 Mar 2026 03:33:58 +0530 Subject: [PATCH 3/5] fix network --- Makefile | 28 +++++++++++++++------------- docker-compose.yml | 2 ++ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index feaa0652..889df3ce 100644 --- a/Makefile +++ b/Makefile @@ -116,23 +116,25 @@ check-config: exit 1; \ fi +BEAST_DIR = $(HOME)/.$(NAME) + setup-beast-dir: check-name check-config - @echo "[*] Setting up .$(NAME) directory..." - @mkdir -p .$(NAME)/assets/logo - @mkdir -p .$(NAME)/assets/mailTemplates - @mkdir -p .$(NAME)/remote - @mkdir -p .$(NAME)/uploads - @mkdir -p .$(NAME)/secrets - @mkdir -p .$(NAME)/scripts - @mkdir -p .$(NAME)/staging - @mkdir -p .$(NAME)/cache - @mkdir -p .$(NAME)/logs - @cp config.toml .$(NAME)/config.toml - @echo "[*] .$(NAME) ready (mounted as /root/.beast in container)" + @echo "[*] Setting up $(BEAST_DIR)..." + @mkdir -p $(BEAST_DIR)/assets/logo + @mkdir -p $(BEAST_DIR)/assets/mailTemplates + @mkdir -p $(BEAST_DIR)/remote + @mkdir -p $(BEAST_DIR)/uploads + @mkdir -p $(BEAST_DIR)/secrets + @mkdir -p $(BEAST_DIR)/scripts + @mkdir -p $(BEAST_DIR)/staging + @mkdir -p $(BEAST_DIR)/cache + @mkdir -p $(BEAST_DIR)/logs + @cp config.toml $(BEAST_DIR)/config.toml + @echo "[*] $(BEAST_DIR) ready (mounted as /root/.beast in container)" up: setup-beast-dir @echo "[*] Starting beast services (project: $(NAME))..." - @BEAST_DIR=.$(NAME) docker compose --project-name $(NAME) up -d --build + @BEAST_DIR=$(BEAST_DIR) docker compose --project-name $(NAME) up -d --build @echo "[*] Beast API running at http://localhost:5005" down: check-name diff --git a/docker-compose.yml b/docker-compose.yml index a77f20a2..8df6e479 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,4 +11,6 @@ services: environment: - HOME=/root - BEAST_FLAGS=${BEAST_FLAGS:--v} + extra_hosts: + - "host.docker.internal:host-gateway" restart: unless-stopped From a4a55688f7b427c1fe1fb139ec8c184f4d6daced Mon Sep 17 00:00:00 2001 From: sukhman Date: Mon, 23 Mar 2026 03:44:28 +0530 Subject: [PATCH 4/5] fix network --- docker-compose.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 8df6e479..cf880bb6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,14 +3,11 @@ services: build: context: . dockerfile: Dockerfile.app - ports: - - "${BEAST_PORT:-5005}:5005" + network_mode: host volumes: - ${BEAST_DIR}:/root/.beast - /var/run/docker.sock:/var/run/docker.sock environment: - HOME=/root - BEAST_FLAGS=${BEAST_FLAGS:--v} - extra_hosts: - - "host.docker.internal:host-gateway" restart: unless-stopped From c2fddc7089826af53e1b2677e4d29b29c8751566 Mon Sep 17 00:00:00 2001 From: sukhman Date: Mon, 23 Mar 2026 04:35:04 +0530 Subject: [PATCH 5/5] Fix docker binding --- core/constants.go | 6 ++++++ core/manager/pipeline.go | 2 +- core/manager/static.go | 4 ++-- docker-compose.yml | 1 + 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/core/constants.go b/core/constants.go index 0fc10a06..d90d6cb4 100644 --- a/core/constants.go +++ b/core/constants.go @@ -11,6 +11,12 @@ var ( BEAST_GLOBAL_DIR = filepath.Join(os.Getenv("HOME"), ".beast") AUTHORIZED_KEYS_FILE = filepath.Join(os.Getenv("HOME"), ".ssh", "authorized_keys") BEAST_TEMP_DIR = filepath.Join(os.TempDir(), "beast") + BEAST_MOUNT_DIR = func() string { + if hostDir := os.Getenv("BEAST_HOST_DIR"); hostDir != "" { + return hostDir + } + return BEAST_GLOBAL_DIR + }() ) const ( //names diff --git a/core/manager/pipeline.go b/core/manager/pipeline.go index f13eb40d..7a5a6880 100644 --- a/core/manager/pipeline.go +++ b/core/manager/pipeline.go @@ -293,7 +293,7 @@ func deployChallenge(challenge *database.Challenge, config cfg.BeastChallengeCon staticMount := make(map[string]string) var staticMountDir string if challenge.ServerDeployed == core.LOCALHOST || challenge.ServerDeployed == "" { - staticMountDir = filepath.Join(core.BEAST_GLOBAL_DIR, core.BEAST_STAGING_DIR, config.Challenge.Metadata.Name, core.BEAST_STATIC_FOLDER) + staticMountDir = filepath.Join(core.BEAST_MOUNT_DIR, core.BEAST_STAGING_DIR, config.Challenge.Metadata.Name, core.BEAST_STATIC_FOLDER) } else { staticMountDir = filepath.Join("$HOME/.beast", core.BEAST_STAGING_DIR, config.Challenge.Metadata.Name, core.BEAST_STATIC_FOLDER) } diff --git a/core/manager/static.go b/core/manager/static.go index a45c3ef8..c94f9cee 100644 --- a/core/manager/static.go +++ b/core/manager/static.go @@ -50,14 +50,14 @@ func DeployStaticContentContainer() error { // Remove the prefix sha256: imageId := images[0].ID[7:] - stagingDirPath := filepath.Join(core.BEAST_GLOBAL_DIR, core.BEAST_STAGING_DIR) + stagingDirPath := filepath.Join(core.BEAST_MOUNT_DIR, core.BEAST_STAGING_DIR) err = utils.CreateIfNotExistDir(stagingDirPath) if err != nil { log.Errorf("Error in validating staging mount point : %s", err) return errors.New("INVALID_STAGING_AREA") } - beastStaticAuthFile := filepath.Join(core.BEAST_GLOBAL_DIR, core.BEAST_STATIC_AUTH_FILE) + beastStaticAuthFile := filepath.Join(core.BEAST_MOUNT_DIR, core.BEAST_STATIC_AUTH_FILE) err = utils.ValidateFileExists(beastStaticAuthFile) if err != nil { p := fmt.Errorf("BEAST STATIC: Authentication file does not exist for beast static container, cannot proceed deployment") diff --git a/docker-compose.yml b/docker-compose.yml index cf880bb6..c2c88216 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,4 +10,5 @@ services: environment: - HOME=/root - BEAST_FLAGS=${BEAST_FLAGS:--v} + - BEAST_HOST_DIR=${BEAST_DIR} restart: unless-stopped