Skip to content

Commit a6962b8

Browse files
Merge pull request #1 from NextronSystems/ghcr-io
refactor: docker compose with base image
2 parents 9a7e276 + d064d37 commit a6962b8

9 files changed

Lines changed: 257 additions & 112 deletions

File tree

.github/workflows/build.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Build and Publish Base Image
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
workflow_dispatch:
8+
9+
env:
10+
REGISTRY: ghcr.io
11+
IMAGE_NAME: ${{ github.repository }}
12+
13+
jobs:
14+
build-and-push:
15+
runs-on: ubuntu-latest
16+
permissions:
17+
contents: read
18+
packages: write
19+
20+
steps:
21+
- name: Checkout repository
22+
uses: actions/checkout@v4
23+
24+
- name: Log in to GitHub Container Registry
25+
uses: docker/login-action@v3
26+
with:
27+
registry: ${{ env.REGISTRY }}
28+
username: ${{ github.actor }}
29+
password: ${{ secrets.GITHUB_TOKEN }}
30+
31+
- name: Extract metadata
32+
id: meta
33+
uses: docker/metadata-action@v5
34+
with:
35+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
36+
tags: |
37+
type=raw,value=latest,enable={{is_default_branch}}
38+
type=sha,prefix=sha-
39+
40+
- name: Build and push image
41+
uses: docker/build-push-action@v6
42+
with:
43+
context: .
44+
file: Containerfile
45+
push: true
46+
tags: ${{ steps.meta.outputs.tags }}
47+
labels: ${{ steps.meta.outputs.labels }}

Containerfile

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,30 @@ LABEL maintainer="Marius Benthin <marius.benthin@nextron-systems.com>"
44
# install dependencies
55
RUN apk add --no-cache wget unzip
66

7-
# pass contract token via --build-args
8-
ARG CONTRACT_TOKEN
9-
RUN test -n "$CONTRACT_TOKEN" || (echo "CONTRACT_TOKEN is required!" && false)
10-
117
# specify environment variables
128
ENV TEMP_DIR="/tmp/thunderstorm"
139
ENV TARGET_DIR="/opt/nextron/thunderstorm"
1410
ENV UPLOAD_DIR="$TEMP_DIR/uploads"
15-
ENV SIGNATURE_UPDATE_INTERVAL=24
1611

1712
# create directories and user
18-
RUN mkdir -p "$TEMP_DIR" "$TARGET_DIR" "$UPLOAD_DIR" && \
13+
RUN mkdir -p \
14+
"$TEMP_DIR" \
15+
"$TEMP_DIR/.persisted-uploads" \
16+
"$TEMP_DIR/logs" \
17+
"$TEMP_DIR/vfs" \
18+
"$TARGET_DIR" \
19+
"$TARGET_DIR/config" \
20+
"$TARGET_DIR/plugins" \
21+
"$TARGET_DIR/signatures" \
22+
"$TARGET_DIR/custom-signatures" \
23+
"$UPLOAD_DIR" && \
1924
adduser -S -H -D -g "Thunderstorm User" thunderstorm && \
2025
chown -R thunderstorm "$TEMP_DIR" "$TARGET_DIR"
2126

22-
# copy entrypoint script
27+
# copy unified entrypoint script
2328
COPY entrypoint.sh /entrypoint.sh
2429
RUN chmod +x /entrypoint.sh
2530

26-
# copy custom THOR config
27-
COPY custom-thor.yml /opt/nextron/thunderstorm/config/custom-thor.yml
28-
2931
USER thunderstorm
3032

31-
# download and extract Thor
32-
RUN wget -O "$TEMP_DIR/thor.zip" "https://portal.nextron-systems.com/api/voucher/download/$CONTRACT_TOKEN/thor/linux"
33-
RUN unzip -o -q "$TEMP_DIR/thor.zip" -d "$TARGET_DIR"
34-
35-
# cleanup
36-
RUN rm "$TEMP_DIR/thor.zip"
37-
38-
# copy custom THOR config
39-
COPY custom-thor.yml "$TARGET_DIR/config/custom-thor.yml"
40-
4133
ENTRYPOINT ["/entrypoint.sh"]

README.md

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,66 @@
1-
# Deploy Thunderstorm in a Container Environment
1+
# Deploy Thunderstorm as a Container
22

3-
Many companies rely on the containerization of services to increase economic and technical efficiency. Customers which use containerization need to create images that make the services available as containers. In this guide, we provide you with the necessary requirements and templates to run Thunderstorm as a container.
3+
[THOR Thunderstorm](https://www.nextron-systems.com/thor-thunderstorm/) is a web service that lets you scan files with our compromise assessment tool THOR through a Web-API. This guide provides a base [container image](https://github.com/NextronSystems/thunderstorm-deployment/pkgs/container/thunderstorm-deployment) and a [Docker Compose template](https://raw.githubusercontent.com/NextronSystems/thunderstorm-deployment/master/docker-compose.yml) so you can run Thunderstorm as a container with just providing your contract token.
44

5-
## Containerize Thunderstorm
65

7-
Thunderstorm is a web service which allows you to scan files with our compromise assessment tool THOR through a Web-API. By sane defaults, the web service listens to `127.0.0.1` on port `8000` only. However, if we want the Thunderstorm API to be accessible from anywhere, we need to adjust the binding address via command line parameter `--host`.
6+
## Quick-Start
87

9-
We created an `entrypoint.sh` which accepts optional environment variables from a Containerfile and deployment configuration. First, the shell script updates the THOR signatures to download all detection rules published after the image was created. Subsequently, the Thunderstorm executable is started which will run infinitely until the container is stopped.
10-
11-
### Build Container Image
12-
13-
The Thunderstorm binary is not publicly available and requires a non-host-based license from our portal. Therefore, we cannot provide a ready-to-use image. However, you can use the following Containerfile in combination with your contract token to build your personal Thunderstorm image.
14-
15-
1. Clone the repository
8+
1. Download the [Docker Compose](https://raw.githubusercontent.com/NextronSystems/thunderstorm-deployment/master/docker-compose.yml) file
169

1710
```
18-
git clone https://github.com/NextronSystems/thunderstorm-deployment.git
11+
curl -O https://raw.githubusercontent.com/NextronSystems/thunderstorm-deployment/master/docker-compose.yml
1912
```
2013

21-
2. Change to repository directory
14+
2. Get a contract token from the [Nextron Portal](https://portal.nextron-systems.com/ui/contracts/contracts) (see [Contract-Token](#contract-token))
15+
16+
3. Start the service with your contract token
2217

2318
```
24-
cd thunderstorm-deployment/
19+
CONTRACT_TOKEN=<CONTRACT_TOKEN> docker compose up -d
2520
```
2621

27-
3. Build image where `<TAG>` could be the Thunderstorm version and `<CONTRACT_TOKEN>` is the contract token of your non-host-based Thunderstorm license.
22+
Thunderstorm is exposed on port **8080** by default.
2823

29-
```
30-
docker build -f Containerfile -t thunderstorm:<TAG> --build-arg CONTRACT_TOKEN=<CONTRACT_TOKEN> .
31-
```
24+
## Contract-Token
3225

33-
4. Push image to your container registry
26+
Deploying Thunderstorm as a container requires a **non-host-based** Thunderstorm license.
3427

35-
```
36-
docker tag thunderstorm:<TAG> registry.internal/thunderstorm/thunderstorm:<TAG>
37-
docker push registry.internal/thunderstorm/thunderstorm:<TAG>
38-
```
28+
On first start, the container uses your contract token to download the THOR binaries and persists them in a Docker volume so subsequent restarts are instant. You can omit the contract token afterwards as long as the volume exists.
3929

40-
## Signature Updates
30+
A contract token can be retrieved from the [Nextron Portal](https://portal.nextron-systems.com/ui/contracts/contracts) under *Contracts & Licenses → Contracts → Actions → cloud icon → THOR Download Token*.
4131

42-
By default, Thunderstorm tries to download new THOR signatures every 24 hours while running. You should keep in mind that the THOR signature release cycle may differ, so there is not always a new package available. The signature update interval can be modified on an hourly basis by specifying the environment variable `SIGNATURE_UPDATE_INTERVAL` in the `Containerfile` or `docker-compose.yml`.
32+
<img src="images/contract_token.png" alt="Contract Token location in Nextron Portal" width="500">
4333

44-
### Rolling Deployment
34+
## Tech-Preview
4535

46-
If you are running a single Thunderstorm instance, you may want to use a Rolling Deployment to prevent a downtime of your Thunderstorm service. A Rolling Deployment spawns a new container and stops the old one after ensuring that the new one is healthy and ready to accept requests. The configuration differs between container management systems such as Kubernetes, Docker or Docker Swarm.
36+
If you want to use the techpreview channel (currently THOR 11) you need to set `TECHPREVIEW=1`. If it is omitted it will downgrade to the stable channel again.
4737

48-
For Docker we recommend `start-first` as value for `deploy.update_config.order`. A docker-compose template can be found under `ochestration/docker/docker-compose.yml`.
38+
The compose file contains commented environment variables for all available configuration options. Some options only apply to specific THOR major versions, for example, `QUEUE_WARN_SIZE` is only available for THOR 11.
4939

50-
### Multiple Replicas
40+
## Signature Updates
5141

52-
If you want to deploy multiple Thunderstorm instances, we recommend to distribute the requests equally using a load-balancer such as [Traefik](https://traefik.io/traefik) or [Nginx](https://nginx.org).
42+
THOR signatures are updated automatically on every container start. To keep them fresh without manually restart, set `SIGNATURE_UPDATE_INTERVAL` (in hours) to schedule recurring updates.
5343

54-
We created a docker-compose template for a Docker Swarm setup with Traefik under `ochestration/docker-swarm/docker-compose.yml`.
44+
The update mechanism depends on the THOR major version. On THOR 10, new signatures only take effect after a restart. Docker's health check therefore marks the container as unhealthy once `SIGNATURE_UPDATE_INTERVAL` has elapsed, prompting Docker to restart it. The new signatures are then fetched as part of the regular container start, at the cost of a brief API downtime. THOR 11 uses Thunderstorm's built-in signature-update feature to download and apply signatures in-place, leaving the API available throughout.
5545

56-
## Remote Logging
46+
## Additional Arguments
5747

58-
Thunderstorm is able to pass custom parameters to the THOR executable. By default, the respective Container Image disables the generation of JSON reports with `--no-json` because the reports will be deleted after the container stops (unless a persistence volume is used). However, you usually want to log the scan results to a remote SIEM system such as [Splunk](https://www.splunk.com) or [Elastic](https://www.elastic.co). Therefore, you may want to specify your remote logging systems inside the `custom-thor.yml` template file.
48+
If you need to customize the THOR scan behavior, you can pass additional arguments via `THOR_ARGS` environment variable. For example, to forward scan results to a remote SIEM:
5949

6050
```yaml
61-
# Send scan output to a remote server
62-
remote-log:
63-
- splunk.intern:514:DEFAULT:TCP
64-
- elastic.intern:1514:JSON:TCP
51+
environment:
52+
THOR_ARGS: "--remote-log splunk.intern:514:DEFAULT:TCP --remote-log elastic.intern:1514:JSON:TCP"
6553
```
6654
55+
A full list of all supported arguments can be derived from the THOR binary using `./thor-linux-64 --fullhelp`.
56+
6757
## Security
6858

6959
The communication between a client and the Thunderstorm service could involve sensitive files. Therefore, we highly recommend to encrypt the traffic using TLS by mounting the certificate and private key via the built-in secrets functionality of Docker or Kubernetes into the container. In addition, you need to specify the file path to the TLS certificate and private key in the environment variables `TLS_CERT` and `TLS_KEY`.
7060

71-
Out of the box, Thunderstorm API is unauthenticated and does not support authentication providers at the moment. If you require an authentication layer, we suggest to use a proxy middleware which delegates the authentication to an external provider such as [Microsoft Entra ID](https://www.microsoft.com/de-de/security/business/identity-access/microsoft-entra-id).
61+
Out of the box, Thunderstorm API is unauthenticated and does not support authentication providers at the moment. If you require an authentication layer, we suggest to use a proxy middleware which delegates the authentication to an external provider such as [Microsoft Entra ID](https://www.microsoft.com/de-de/security/business/identity-access/microsoft-entra-id).
62+
63+
## Limitations
64+
65+
### Load-Balancing
66+
Thunderstorm allows you to send **asynchronous requests** and poll the results using an ID. Currently, Thunderstorm instances do not share their results with each other. If you run multiple Thunderstorm containers behind a load-balancer and request the results of an async request, you may not get the result from the correct Thunderstorm instance. We recommend to use async requests in combination with remote logging only in a load-balancer setup.

custom-thor.yml

Lines changed: 0 additions & 5 deletions
This file was deleted.

docker-compose.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
services:
2+
thunderstorm:
3+
image: ghcr.io/nextronsystems/thunderstorm-deployment:latest
4+
ports:
5+
- "${PORT:-8080}:8080"
6+
environment:
7+
# Required on initial startup: your non-host-based Thunderstorm contract token
8+
CONTRACT_TOKEN: "${CONTRACT_TOKEN}"
9+
# Optional: upgrade to THOR techpreview channel
10+
# TECHPREVIEW: "true"
11+
# Optional: hours between signature updates (default: 0)
12+
# SIGNATURE_UPDATE_INTERVAL: "0"
13+
# Optional: result cache size (default: 250000)
14+
# RESULT_CACHE_SIZE: "250000"
15+
# Optional: enforce maximum file size for all file types including registry hives and log files
16+
# FORCE_MAX_FILE_SIZE: "true"
17+
# Optional: write log to the logs volume (uncomment volume below)
18+
# LOG_ENABLED: "true"
19+
# Optional: TLS certificate and private key paths (mounted via secrets)
20+
# TLS_CERT: "/run/secrets/tls_cert"
21+
# TLS_KEY: "/run/secrets/tls_key"
22+
# Optional: only scan using YARA signatures, disables programmatic checks, STIX, Sigma and IOCs
23+
# PURE_YARA: "true"
24+
# Optional: download YARA Forge community signatures on startup - ruleset: core, extended, full (not quality-assured by Nextron)
25+
# YARA_FORGE: "full"
26+
# Optional: additional Thunderstorm arguments
27+
# THUNDERSTORM_ARGS: ""
28+
# Optional: additional THOR arguments
29+
# THOR_ARGS: ""
30+
#
31+
# --- THOR 10 only ---
32+
# Optional: sample persistence - "all", "malicious", or "none" (default: none)
33+
# STORE_SAMPLES: "none"
34+
# Optional: reserve THOR threads for synchronous requests only
35+
# SYNC_ONLY_THREADS: ""
36+
#
37+
# --- THOR 11 only ---
38+
# Optional: minimum score for storing samples (default: 200)
39+
# STORE_SAMPLES_SCORE: "200"
40+
# Optional: upload queue size warning threshold (default: 50000)
41+
# QUEUE_WARN_SIZE: "50000"
42+
# Optional: enable VFS directory mirroring uploaded files per host (also uncomment volume below)
43+
# VFS_ENABLED: "true"
44+
volumes:
45+
# Persist Thor binaries and other artifacts across restarts
46+
- thunderstorm:/opt/nextron/thunderstorm
47+
# Optional: mount TLS certificate and private key (uncomment TLS_CERT/TLS_KEY above as well)
48+
# - ./tls_cert:/run/secrets/tls_cert:ro
49+
# - ./tls_key:/run/secrets/tls_key:ro
50+
restart: unless-stopped
51+
# THOR 10: periodically restart the container by signaling PID 1 once uptime exceeds
52+
# SIGNATURE_UPDATE_INTERVAL hours; restart policy brings it back up. Skipped when
53+
# SIGNATURE_UPDATE_INTERVAL is 0 (disabled, default) or TECHPREVIEW is set (THOR 11
54+
# updates signatures in-process).
55+
healthcheck:
56+
test: ["CMD-SHELL", "[ -n \"$$TECHPREVIEW\" ] || [ \"$${SIGNATURE_UPDATE_INTERVAL:-0}\" = \"0\" ] || [ $$(($$(date +%s) - $$(stat -c %Y /proc/1))) -lt $$(( $${SIGNATURE_UPDATE_INTERVAL} * 3600 )) ] || kill 1"]
57+
interval: 5m
58+
timeout: 10s
59+
start_period: 10m
60+
61+
volumes:
62+
thunderstorm:

0 commit comments

Comments
 (0)