Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
FROM nestybox/ubuntu-noble-systemd-docker@sha256:8b1c4409fe89bc110e1e468767074fe4403ba6bb2d1b34881fec5df8b6c2f9c3 AS fact_base

ARG FACT_DIR=/opt/fact
COPY src $FACT_DIR
WORKDIR $FACT_DIR

RUN --mount=type=cache,target=/var/cache/apt \
--mount=type=cache,target=/var/lib/apt \
apt-get update && \
apt-get install -y --no-install-recommends \
curl \
python3-venv \
postgresql-client \
redis-tools

RUN python3 -m venv venv
ARG VENV_DIR=$FACT_DIR/venv/bin
ENV PATH=$VENV_DIR:$PATH \
VIRTUAL_ENV=$VENV_DIR \
PYTHONPATH=$FACT_DIR \
FACT_INSTALLER_SKIP_DOCKER=1

RUN --mount=type=cache,target=/var/cache/apt \
--mount=type=cache,target=/var/lib/apt \
./install/pre_install.sh -D

FROM fact_base AS fact_frontend

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
python3 install.py -F -H

RUN chown -R admin:admin "$FACT_DIR"

COPY --chown=admin docker/entrypoint_frontend.sh .

ENTRYPOINT ["./entrypoint_frontend.sh"]

FROM fact_base AS fact_backend

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
python3 install.py -B

RUN chown -R admin:admin "$FACT_DIR"

COPY --chown=admin docker/entrypoint_backend.sh .

# This file serves as a flag to indicate that the backend installation of the docker containers is completed
RUN touch DOCKER_INSTALL_INCOMPLETE
# We must still install the docker images, so we need to overwrite the flag now:
ENV FACT_INSTALLER_SKIP_DOCKER=0

ENTRYPOINT ["./entrypoint_backend.sh"]
26 changes: 24 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,30 @@ our [tutorial](https://github.com/fkie-cad/FACT_core/blob/master/INSTALL.vagrant

### Docker

There is also a dockerized version, but it is currently unmaintained.
(see the [FACT_docker](https://github.com/fkie-cad/FACT_docker) repo for more information).
>[!IMPORTANT]
> The docker image requires Sysbox as Docker runtime.
> Sysbox installation is described [here](https://github.com/nestybox/sysbox/tree/master?tab=readme-ov-file#installation)
> Please make sure that it works before trying to run FACT with docker by running the hello-world image:
> `docker run --rm --runtime sysbox-runc hello-world`

If you have untracked files in the directory or also installed FACT locally, create a `.dockerignore`, so you don't
copy the files into the Docker image when building it:

```shell
# exclude untracked files:
git ls-files . --exclude-standard --others --directory > .dockerignore
# exclude ignored files:
git ls-files . --ignored --exclude-standard --others --directory >> .dockerignore
# also exclude the .git folder:
echo ".git/" >> .dockerignore
```

Running FACT with docker compose:

```shell
docker compose build
docker compose up
```

## Usage

Expand Down
77 changes: 77 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
services:
fact-frontend:
runtime: sysbox-runc
build:
context: .
target: fact_frontend
environment:
PGPASSWORD: password
ports:
- "5000:5000"
networks:
fact:
aliases:
- frontend
depends_on:
db:
condition: service_healthy
restart: true
redis:
condition: service_started
fact-backend:
runtime: sysbox-runc
build:
context: .
target: fact_backend
environment:
PGPASSWORD: password
networks:
fact:
aliases:
- backend
volumes:
- fact_files:/media/data
- fact_docker_images:/var/lib/docker
depends_on:
db:
condition: service_healthy
restart: true
redis:
condition: service_started
db:
container_name: postgres
image: postgres:17
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
PGDATA: /data/postgres
volumes:
- fact_db:/data/postgres
networks:
fact:
aliases:
- db
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d postgres"]
interval: 5s
retries: 5
start_period: 5s
timeout: 10s
redis:
container_name: redis
image: redis:alpine
restart: always
networks:
fact:
aliases:
- redis

networks:
fact:
driver: bridge

volumes:
fact_db:
fact_files:
fact_docker_images:
28 changes: 28 additions & 0 deletions docker/entrypoint_backend.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

set -eux

# start docker service
dockerd &

# redis runs in a different container => replace "localhost" with "redis"
sed -i 's/host = "localhost"/host = "redis"/g' /opt/fact/config/fact-core-config.toml
# postgres also runs in a different container => replace "localhost" with "db"
sed -i 's/server = "localhost"/server = "db"/g' /opt/fact/config/fact-core-config.toml

if [ -e DOCKER_INSTALL_INCOMPLETE ]; then
echo "Installing FACT docker images..."
python3 install.py --backend-docker-images
rm DOCKER_INSTALL_INCOMPLETE
echo "FACT docker image installation completed"
fi

# We can't use rest/status here, because it needs the list of available plugins (which is available after the backend
# was started).
until curl -s -X GET 'http://frontend:5000/rest/statistics/general'; do
echo "Waiting for FACT frontend to start..."
sleep 2
done
echo "FACT frontend is ready"

python3 start_fact_backend.py
18 changes: 18 additions & 0 deletions docker/entrypoint_frontend.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash

set -eux

# start docker service
dockerd &

# redis runs in a different container => replace "localhost" with "redis"
sed -i 's/host = "localhost"/host = "redis"/g' /opt/fact/config/fact-core-config.toml
# postgres also runs in a different container => replace "localhost" with "db"
sed -i 's/server = "localhost"/server = "db"/g' /opt/fact/config/fact-core-config.toml
# replace localhost with 0.0.0.0 in uWSGI config so that the frontend can be reached from outside
sed -i 's/127.0.0.1/0.0.0.0/g' /opt/fact/config/uwsgi_config.ini

# init the DB
python3 init_postgres.py

python3 start_fact_frontend.py --no-radare
4 changes: 1 addition & 3 deletions src/init_postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ def user_exists(user_name: str, host: str, port: str | int) -> bool:

def create_admin_user(user_name: str, password: str, host: str, port: int | str):
execute_psql_command(
# fmt: off
(f"CREATE USER {user_name} WITH PASSWORD '{password}' " 'LOGIN SUPERUSER INHERIT CREATEDB CREATEROLE;'),
# fmt: on
f"CREATE USER {user_name} WITH PASSWORD '{password}' LOGIN SUPERUSER INHERIT CREATEDB CREATEROLE;",
host=host,
port=port,
)
Expand Down
4 changes: 2 additions & 2 deletions src/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
PROGRAM_VERSION = '1.2'
PROGRAM_DESCRIPTION = 'Firmware Analysis and Comparison Tool (FACT) installation script'

FACT_INSTALLER_SKIP_DOCKER = os.getenv('FACT_INSTALLER_SKIP_DOCKER')
FACT_INSTALLER_SKIP_DOCKER = bool(int(os.getenv('FACT_INSTALLER_SKIP_DOCKER', '0')))


def _setup_argparser():
Expand Down Expand Up @@ -169,7 +169,7 @@ def install():
welcome()
none_chosen = not (args.frontend or args.db or args.backend or args.common)
# TODO maybe replace this with an cli argument
skip_docker = FACT_INSTALLER_SKIP_DOCKER is not None
skip_docker = FACT_INSTALLER_SKIP_DOCKER
# Note that the skip_docker environment variable overrides the cli argument
only_docker = not skip_docker and none_chosen and (args.backend_docker_images or args.frontend_docker_images)

Expand Down