Skip to content

Commit

Permalink
Refactor Docker setup
Browse files Browse the repository at this point in the history
Follow best-practices and make caldera easier to use
  • Loading branch information
daw1012345 committed Dec 26, 2024
1 parent 4b57658 commit ce513fb
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 106 deletions.
20 changes: 20 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,23 @@ tests/
**/release.sh
**/requirements-dev.txt
**/tox.ini

# Artifacts from previous use/compilation
**/__pycache__/
**/node_modules/
**/plugins/magma/dist/
**/plugins/atomic/data/atomic-red-team
**/plugins/emu/data/adversary-emulation-plans
**/plugins/emu/payloads/*

# Artifacts from previous caldera use
data/*_store
data/abilities/*
data/adversaries
data/results/*
data/payloads/*
data/facts/*
data/sources/*
data/objectives/*
data/backup/*
data/planners/*
32 changes: 27 additions & 5 deletions .github/workflows/publish_docker_image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,38 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
- name: Extract metadata (tags, labels) for Docker (slim variant)
id: meta-slim
uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
latest=auto
prefix=slim-,onlatest=true
suffix=
- name: Build and push Docker image (slim)
uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825
with:
context: .
push: true
tags: ${{ steps.meta-slim.outputs.tags }}
labels: ${{ steps.meta-slim.outputs.labels }}
build-args: |
VARIANT=slim
- name: Extract metadata (tags, labels) for Docker (full variant)
id: meta-full
uses: docker/metadata-action@818d4b7b91585d195f67373fd9cb0332e31a7175
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
- name: Build and push Docker image (full)
uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ steps.meta-full.outputs.tags }}
labels: ${{ steps.meta-full.outputs.labels }}
build-args: |
VARIANT=full
145 changes: 71 additions & 74 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,95 +1,92 @@
FROM ubuntu:23.04
SHELL ["/bin/bash", "-c"]

ARG TZ="UTC"
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone
# This file uses a staged build, using a different stage to build the UI (magma)
# Build the UI
FROM node:23 as ui-build

WORKDIR /usr/src/app

# Make sure user cloned caldera recursively before installing anything.
ADD . .
RUN if [ -z "$(ls plugins/stockpile)" ]; then echo "stockpile plugin not downloaded - please ensure you recursively cloned the caldera git repository and try again."; exit 1; fi

RUN apt-get update && \
apt-get -y install python3 python3-pip python3-venv git curl golang-go


#WIN_BUILD is used to enable windows build in sandcat plugin
ARG WIN_BUILD=false
RUN if [ "$WIN_BUILD" = "true" ] ; then apt-get -y install mingw-w64; fi

# Set up python virtualenv
ENV VIRTUAL_ENV=/opt/venv/caldera
RUN python3 -m venv $VIRTUAL_ENV
ENV PATH="$VIRTUAL_ENV/bin:$PATH"

# Install pip requirements
RUN pip3 install --no-cache-dir -r requirements.txt

# Set up config file and disable atomic by default
RUN python3 -c "import app; import app.utility.config_generator; app.utility.config_generator.ensure_local_config();"; \
sed -i '/\- atomic/d' conf/local.yml;
# Build VueJS front-end
RUN (cd plugins/magma; npm install && npm run build)
# This stage contains all dependencies for

FROM debian:bookworm-slim as runtime
# There are two variants - slim and full
# The slim variant excludes some dependencies of *emu* and *slim* that can be downloaded on-demand if needed
# They are very large
ARG VARIANT=full
ENV VARIANT=${VARIANT}

# Display an error if variant is set incorrectly, otherwise just print information regarding which variant is in use
RUN if [ "$VARIANT" = "full" ]; then \
echo "Building \"full\" container suitable for offline use!"; \
elif [ "$VARIANT" = "slim" ]; then \
echo "Building slim container - some plugins (emu, atomic) may not be available without an internet connection!"; \
else \
echo "Invalid Docker build-arg!"; \
exit 1; \
fi

# Compile default sandcat agent binaries, which will download basic golang dependencies.
WORKDIR /usr/src/app

# Install Go dependencies
WORKDIR /usr/src/app/plugins/sandcat/gocat
RUN go mod tidy && go mod download
# Copy in source code and compiled UI
# IMPORTANT NOTE: the .dockerignore file is very important in preventing weird issues.
# Especially if caldera was ever compiled outside of Docker - we don't want those files to interfere with this build process,
# which should be repeatable.
ADD . .
COPY --from=ui-build /usr/src/app/plugins/magma/dist /usr/src/app/plugins/magma/dist

WORKDIR /usr/src/app/plugins/sandcat
# From https://docs.docker.com/build/building/best-practices/
# Install caldera dependencies
RUN apt-get update && \
apt-get --no-install-recommends -y install git curl unzip python3-dev python3-pip golang-go mingw-w64 zlib1g gcc && \
rm -rf /var/lib/apt/lists/*

# Fix line ending error that can be caused by cloning the project in a Windows environment
RUN if [ "$WIN_BUILD" = "true" ] ; then cp ./update-agents.sh ./update-agents-copy.sh; fi
RUN if [ "$WIN_BUILD" = "true" ] ; then tr -d '\15\32' < ./update-agents-copy.sh > ./update-agents.sh; fi
RUN if [ "$WIN_BUILD" = "true" ] ; then rm ./update-agents-copy.sh; fi

RUN ./update-agents.sh

# Check if we can compile the sandcat extensions, which will download golang dependencies for agent extensions
RUN mkdir /tmp/gocatextensionstest

RUN cp -R ./gocat /tmp/gocatextensionstest/gocat
RUN cp -R ./gocat-extensions/* /tmp/gocatextensionstest/gocat/
RUN cd /usr/src/app/plugins/sandcat; tr -d '\15\32' < ./update-agents.sh > ./update-agents.sh

RUN cp ./update-agents.sh /tmp/gocatextensionstest/update-agents.sh

WORKDIR /tmp/gocatextensionstest

RUN mkdir /tmp/gocatextensionstest/payloads
# Set timezone (default to UTC)
ARG TZ="UTC"
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone

RUN ./update-agents.sh
# Install pip requirements
RUN pip3 install --break-system-packages --no-cache-dir -r requirements.txt

# Set up config file
RUN python3 -c "import app; import app.utility.config_generator; app.utility.config_generator.ensure_local_config();"

# For offline atomic (disable it by default in slim image)
# Disable atomic if this is not downloaded
RUN if [ ! -d "/usr/src/app/plugins/atomic/data/atomic-red-team" ] && [ "$VARIANT" = "full" ]; then \
git clone --depth 1 https://github.com/redcanaryco/atomic-red-team.git \
/usr/src/app/plugins/atomic/data/atomic-red-team; \
else \
sed -i '/\- atomic/d' conf/local.yml; \
fi

# Clone atomic red team repo for the atomic plugin
RUN if [ ! -d "/usr/src/app/plugins/atomic/data/atomic-red-team" ]; then \
git clone --depth 1 https://github.com/redcanaryco/atomic-red-team.git \
/usr/src/app/plugins/atomic/data/atomic-red-team; \
# For offline emu
# (Emu is disabled by default, no need to disable it if slim variant is being built)
RUN if [ ! -d "/usr/src/app/plugins/emu/data/adversary-emulation-plans" ] && [ "$VARIANT" = "full" ]; then \
git clone --depth 1 https://github.com/center-for-threat-informed-defense/adversary_emulation_library \
/usr/src/app/plugins/emu/data/adversary-emulation-plans; \
fi

WORKDIR /usr/src/app/plugins/emu
# Download emu payloads
# emu doesn't seem capable of running this itself - always download
RUN cd /usr/src/app/plugins/emu; ./download_payloads.sh

# If emu is enabled, complete necessary installation steps
RUN if [ $(grep -c "\- emu" ../../conf/local.yml) ]; then \
apt-get -y install zlib1g unzip; \
pip3 install -r requirements.txt; \
./download_payloads.sh; \
fi
# The commands above (git clone) will generate *huge* .git folders - remove them
RUN (find . -type d -name ".git") | xargs rm -rf

WORKDIR /usr/src/app
# Install Go dependencies
RUN cd /usr/src/app/plugins/sandcat/gocat; go mod tidy && go mod download

# Install Node.js, npm, and other build VueJS front-end
RUN apt-get update && \
apt-get install -y nodejs npm && \
# Directly use npm to install dependencies and build the application
(cd plugins/magma && npm install) && \
(cd plugins/magma && npm run build) && \
# Remove Node.js, npm, and other unnecessary packages
apt-get remove -y nodejs npm && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Update sandcat agents
RUN cd /usr/src/app/plugins/sandcat; ./update-agents.sh

WORKDIR /usr/src/app
# Make sure emu can always be used in container (even if not enabled right now)
RUN cd /usr/src/app/plugins/emu; \
pip3 install --break-system-packages -r requirements.txt

STOPSIGNAL SIGINT

Expand Down
58 changes: 33 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,39 @@ These requirements are for the computer running the core framework:
* Recommended: GoLang 1.17+ to dynamically compile GoLang-based agents.
* NodeJS (v16+ recommended for v5 VueJS UI)

## Docker Installation (Recommended)
**Note 1: The image on DockerHub is outdated, please do not use it for the time being!**

**Note 2: The builder plugin will not work within Docker**

Local build:
```sh
git clone https://github.com/mitre/caldera.git --recursive
cd caldera
docker build --build-arg VARIANT=full -t caldera .
docker run -p 8888:8888 caldera
```

Adjust the port forwarding (`-p`) and build args (`--build-arg`) as desired to make ports accessible or change the caldera variant.

Pre-Built Image (from GitHub Container Registry):
```sh
docker run -p 8888:8888 ghcr.io/mitre/caldera:latest
```

To gracefully terminate your docker container, do the following:
```Bash
# Find the container ID for your docker container running Caldera
docker ps

# Stop the container
docker stop [container ID]
```

There are two variants available, *full* and *slim*.
The *slim* variant doesn't include files necessary for the *emu* and *atomic* plugins, which will be downloaded on-demand if the plugins are ever enabled. The *full* variant is suitable for operation in environments without an internet connection. Slim images on GHCR are prefixed with "slim".


## Installation

Concise installation steps:
Expand Down Expand Up @@ -110,31 +143,6 @@ If you'll be developing the UI, there are a few more additional installation ste

Your Caldera server is available at http://localhost:8888 as usual, but there will now be a hot-reloading development server for the VueJS front-end available at http://localhost:3000. Both logs from the server and the front-end will display in the terminal you launched the server from.

## Docker Deployment
To build a Caldera docker image, ensure you have docker installed and perform the following actions:
```Bash
# Recursively clone the Caldera repository if you have not done so
git clone https://github.com/mitre/caldera.git --recursive

# Build the docker image. Change image tagging as desired.
# WIN_BUILD is set to true to allow Caldera installation to compile windows-based agents.
# Alternatively, you can use the docker compose YML file via "docker-compose build"
cd caldera
docker build . --build-arg WIN_BUILD=true -t caldera:latest

# Run the image. Change port forwarding configuration as desired.
docker run -p 8888:8888 caldera:latest
```

To gracefully terminate your docker container, do the following:
```Bash
# Find the container ID for your docker container running Caldera
docker ps

# Stop the container
docker stop [container ID]
```

## Contributing

Refer to our [contributor documentation](CONTRIBUTING.md).
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ services:
context: .
dockerfile: Dockerfile
args:
TZ: "UTC" #TZ sets timezone for ubuntu setup
WIN_BUILD: "true" #WIN_BUILD is used to enable windows build in sandcat plugin
TZ: "UTC" # Timezone to use in container
VARIANT: "full"
image: caldera:latest
ports:
- "8888:8888"
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ asyncssh==2.14.1
aioftp~=0.20.0
packaging==23.2
croniter~=3.0.3
setuptools==75.6.0

0 comments on commit ce513fb

Please sign in to comment.