├── .github └── workflows │ ├── docker-build.yml │ └── docker-description.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Readme.md ├── docker-compose.example.yml ├── docker-entrypoint.sh ├── docs └── build.md ├── etc ├── networks.cfg ├── node.example.cfg └── zeekctl.cfg ├── logs └── .gitkeep ├── share └── zeek │ └── site │ └── autoload │ ├── 001-unload-scripts.zeek │ ├── 100-default.zeek │ ├── 200-inactivity_timeout.zeek │ └── 900-zkg.zeek └── zeek /.github/workflows/docker-build.yml: -------------------------------------------------------------------------------- 1 | name: Publish Docker Images 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | paths: 7 | # Paths that trigger a docker image build 8 | - '.github/workflows/docker-build.yml' 9 | - 'etc/**' 10 | - 'share/**' 11 | - 'docker-entrypoint.sh' 12 | - 'Dockerfile' 13 | env: 14 | REGISTRY_IMAGE: activecm/zeek 15 | 16 | jobs: 17 | build: 18 | runs-on: "${{ matrix.runner }}" 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | platform: 23 | - linux/amd64 24 | - linux/arm/v7 25 | - linux/arm64 26 | version: 27 | - "6.2.1" 28 | include: 29 | - platform: linux/amd64 30 | arch: amd64 31 | runner: ubuntu-large-1 32 | - platform: linux/arm64 33 | arch: arm64 34 | runner: ubuntu-arm-l 35 | - platform: linux/arm/v7 36 | arch: armv7 37 | runner: ubuntu-large-2 38 | - version: "6.2.1" 39 | zkg: "3.0.1" 40 | release-tag: latest 41 | 42 | steps: 43 | - name: Checkout 44 | uses: actions/checkout@v4 45 | with: 46 | fetch-depth: 0 47 | - name: Prepare 48 | run: | 49 | platform=${{ matrix.platform }} 50 | echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV 51 | 52 | - name: Docker meta 53 | id: meta 54 | uses: docker/metadata-action@v5 55 | with: 56 | images: ${{ env.REGISTRY_IMAGE }} 57 | tags: | 58 | type=semver,pattern={{version}},value=${{ matrix.version }} 59 | type=raw,value=latest,enable=${{ matrix.release-tag == 'latest' }} 60 | 61 | 62 | - name: Set up QEMU 63 | uses: docker/setup-qemu-action@v3 64 | 65 | - name: Set up Docker Buildx 66 | uses: docker/setup-buildx-action@v3 67 | 68 | - name: Login to Docker Hub 69 | uses: docker/login-action@v3 70 | with: 71 | username: ${{ secrets.DOCKER_USERNAME }} 72 | password: ${{ secrets.DOCKER_TOKEN }} 73 | 74 | - name: Build and push by digest 75 | id: build 76 | uses: docker/build-push-action@v6 77 | with: 78 | context: . 79 | platforms: ${{ matrix.platform }} 80 | labels: ${{ steps.meta.outputs.labels }} 81 | outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true 82 | build-args: | 83 | ZEEK_VERSION=${{ matrix.version }} 84 | ZKG_VERSION=${{ matrix.zkg }} 85 | push: true 86 | cache-from: type=registry,ref=${{ env.REGISTRY_IMAGE }}:buildcache-${{ matrix.version }}-${{ matrix.arch }} 87 | cache-to: type=registry,ref=${{ env.REGISTRY_IMAGE }}:buildcache-${{ matrix.version }}-${{ matrix.arch }},mode=max 88 | no-cache-filters: final 89 | 90 | 91 | - name: Export digest 92 | run: | 93 | mkdir -p /tmp/digests 94 | digest="${{ steps.build.outputs.digest }}" 95 | touch "/tmp/digests/${digest#sha256:}" 96 | 97 | - name: Upload digest 98 | uses: actions/upload-artifact@v4 99 | with: 100 | name: digests-${{ matrix.version }}-${{ env.PLATFORM_PAIR }} 101 | path: /tmp/digests/* 102 | if-no-files-found: error 103 | retention-days: 1 104 | 105 | merge: 106 | runs-on: 107 | group: "ubuntu-runners-l" 108 | needs: 109 | - build 110 | strategy: 111 | matrix: 112 | include: 113 | - version: "6.2.1" 114 | release-tag: latest 115 | steps: 116 | - name: Download digests 117 | uses: actions/download-artifact@v4 118 | with: 119 | path: /tmp/digests 120 | pattern: digests-${{ matrix.version }}-* 121 | merge-multiple: true 122 | 123 | - name: Set up Docker Buildx 124 | uses: docker/setup-buildx-action@v3 125 | 126 | - name: Docker meta 127 | id: meta 128 | uses: docker/metadata-action@v5 129 | with: 130 | images: ${{ env.REGISTRY_IMAGE }} 131 | tags: | 132 | type=semver,pattern={{version}},value=${{ matrix.version }} 133 | type=raw,value=latest,enable=${{ matrix.release-tag == 'latest' }} 134 | 135 | - name: Login to Docker Hub 136 | uses: docker/login-action@v3 137 | with: 138 | username: ${{ secrets.DOCKER_USERNAME }} 139 | password: ${{ secrets.DOCKER_TOKEN }} 140 | 141 | - name: Create manifest list and push 142 | working-directory: /tmp/digests 143 | run: | 144 | docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ 145 | $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) 146 | 147 | - name: Inspect image 148 | run: | 149 | docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} -------------------------------------------------------------------------------- /.github/workflows/docker-description.yml: -------------------------------------------------------------------------------- 1 | name: Update Docker Description 2 | 3 | on: 4 | push: 5 | # https://github.com/peter-evans/dockerhub-description/issues/10 6 | branches: [disabled] # purposely disabled as this doesn't work with Docker access tokens 7 | paths: 8 | - '.github/workflows/docker-description.yml' 9 | - 'Readme.md' 10 | 11 | jobs: 12 | description: 13 | name: Update Docker Zeek description 14 | runs-on: ubuntu-latest 15 | steps: 16 | - 17 | name: Checkout code 18 | uses: actions/checkout@v2 19 | - 20 | name: Update repo description 21 | uses: peter-evans/dockerhub-description@v2 22 | with: 23 | username: ${{ secrets.DOCKER_USERNAME }} 24 | password: ${{ secrets.DOCKER_TOKEN }} 25 | repository: activecm/zeek 26 | readme-filepath: ./Readme.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/* 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine AS builder 2 | 3 | ARG ZEEK_VERSION=6.2.1 4 | #ARG AF_PACKET_VERSION=3.0.2 5 | 6 | ARG BUILD_PROCS=4 7 | 8 | RUN apk add --no-cache zlib openssl libstdc++ libpcap libgcc 9 | RUN apk add --no-cache -t .build-deps \ 10 | bsd-compat-headers \ 11 | libmaxminddb-dev \ 12 | linux-headers \ 13 | openssl-dev \ 14 | libpcap-dev \ 15 | python3-dev \ 16 | zlib-dev \ 17 | flex-dev \ 18 | binutils \ 19 | fts-dev \ 20 | cmake \ 21 | bison \ 22 | bash \ 23 | swig \ 24 | perl \ 25 | make \ 26 | flex \ 27 | git \ 28 | gcc \ 29 | g++ \ 30 | fts \ 31 | krb5-dev 32 | 33 | #Removed clang, nodejs-dev, nodejs (the nodejs ones since we now disable javascript in configure) 34 | 35 | RUN echo "===> Cloning zeek..." \ 36 | && cd /tmp \ 37 | && git clone --recursive --branch v$ZEEK_VERSION https://github.com/zeek/zeek.git 38 | 39 | RUN echo "===> Compiling zeek..." \ 40 | && cd /tmp/zeek \ 41 | && CC=gcc ./configure --prefix=/usr/local/zeek \ 42 | --build-type=Release \ 43 | --disable-broker-tests \ 44 | --disable-auxtools \ 45 | --disable-javascript \ 46 | && make -j $BUILD_PROCS \ 47 | && make install 48 | 49 | #As of Zeek 5.2.0 af_packet is included with zeek. 50 | #RUN echo "===> Compiling af_packet plugin..." \ 51 | # && git clone https://github.com/J-Gras/zeek-af_packet-plugin.git --branch ${AF_PACKET_VERSION} /tmp/zeek-af_packet-plugin \ 52 | # && cd /tmp/zeek-af_packet-plugin \ 53 | # && CC=gcc ./configure --with-kernel=/usr --zeek-dist=/tmp/zeek \ 54 | # && make -j $BUILD_PROCS \ 55 | # && make install \ 56 | # && /usr/local/zeek/bin/zeek -NN Zeek::AF_Packet 57 | 58 | RUN echo "===> Shrinking image..." \ 59 | && strip -s /usr/local/zeek/bin/zeek 60 | 61 | RUN echo "===> Size of the Zeek install..." \ 62 | && du -sh /usr/local/zeek 63 | 64 | #################################################################################################### 65 | FROM alpine AS final 66 | 67 | # python3 & bash are needed for zeekctl scripts 68 | # ethtool is needed to manage interface features 69 | # util-linux provides taskset command needed to pin CPUs 70 | # py3-pip and git are needed for zeek's package manager 71 | RUN apk --no-cache add \ 72 | ca-certificates zlib openssl libstdc++ libpcap libmaxminddb libgcc fts krb5-libs \ 73 | python3 bash \ 74 | ethtool \ 75 | util-linux \ 76 | py3-pip git 77 | 78 | RUN ln -s $(which ethtool) /sbin/ethtool 79 | 80 | COPY --from=builder /usr/local/zeek /usr/local/zeek 81 | 82 | ENV ZEEKPATH=.:/usr/local/zeek/share/zeek:/usr/local/zeek/share/zeek/policy:/usr/local/zeek/share/zeek/site 83 | ENV PATH=$PATH:/usr/local/zeek/bin 84 | 85 | # Install Zeek package manager 86 | # In Zeek v4, zkg is bundled with Zeek. However, the configuration of zkg when bundled with Zeek 87 | # differs from the configuration when installed via pip. The state directory is 88 | # /usr/local/zeek/var/lib/zkg when using v4's bundled zkg. When zkg is installed via pip 89 | # or the --user flag is supplied to the bundled zkg, .root/zkg is used as the state directory. 90 | # In order to re-use the same configuration across v3 and v4, we manually install zkg from pip. 91 | ARG ZKG_VERSION=3.0.1 92 | 93 | ARG ZEEK_DEFAULT_PACKAGES="bro-interface-setup bro-doctor ja3 zeek-open-connections" 94 | 95 | RUN pip install --break-system-packages zkg==$ZKG_VERSION \ 96 | && zkg autoconfig \ 97 | && zkg refresh \ 98 | && zkg install --force $ZEEK_DEFAULT_PACKAGES 99 | 100 | ARG ZEEKCFG_VERSION=0.0.5 101 | 102 | # Set TARGET_ARCH to Docker build host arch unless TARGETARCH is specified via BuildKit 103 | RUN case `uname -m` in \ 104 | x86_64) \ 105 | TARGET_ARCH="amd64" \ 106 | ;; \ 107 | aarch64) \ 108 | TARGET_ARCH="arm64" \ 109 | ;; \ 110 | arm|armv7l) \ 111 | TARGET_ARCH="arm" \ 112 | ;; \ 113 | esac; \ 114 | TARGET_ARCH=${TARGETARCH:-$TARGET_ARCH}; \ 115 | echo https://github.com/activecm/zeekcfg/releases/download/v${ZEEKCFG_VERSION}/zeekcfg_${ZEEKCFG_VERSION}_linux_${TARGET_ARCH}; \ 116 | wget -qO /usr/local/zeek/bin/zeekcfg https://github.com/activecm/zeekcfg/releases/download/v${ZEEKCFG_VERSION}/zeekcfg_${ZEEKCFG_VERSION}_linux_${TARGET_ARCH} \ 117 | && chmod +x /usr/local/zeek/bin/zeekcfg 118 | 119 | # Run zeekctl cron to heal processes every 5 minutes 120 | RUN echo "*/5 * * * * /usr/local/zeek/bin/zeekctl cron" >> /etc/crontabs/root 121 | COPY docker-entrypoint.sh /docker-entrypoint.sh 122 | 123 | # Users must supply their own node.cfg 124 | RUN rm -f /usr/local/zeek/etc/node.cfg 125 | COPY etc/networks.cfg /usr/local/zeek/etc/networks.cfg 126 | COPY etc/zeekctl.cfg /usr/local/zeek/etc/zeekctl.cfg 127 | COPY share/zeek/site/ /usr/local/zeek/share/zeek/site/ 128 | 129 | CMD ["/docker-entrypoint.sh"] 130 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | [activecm/zeek](https://hub.docker.com/r/activecm/zeek) is meant to run a single-system Zeek cluster inside of a docker container. It is based on, but differs from [blacktop/zeek:zeekctl](https://hub.docker.com/r/blacktop/zeek) in that it focuses on running multiple Zeek processes with `zeekctl`. To that end, there are several helpful features included: 3 | 4 | - A [configuration wizard](https://github.com/activecm/zeekcfg) for generating a `node.cfg` cluster configuration 5 | - Will automatically run `zeekctl` on start and print a diagnostic report if it fails 6 | - Cron will periodically ensure that all Zeek processes are running and restart any that have crashed 7 | - Zeek's package manager is included, allowing you to easily install zeek plugins 8 | - Performance improvement by using `ethtool` to disable certain interface features by default 9 | - Performance improvement with AF_Packet plugin installed and enabled by default in the configuration wizard 10 | - Comes with the following other plugins pre-installed 11 | - bro-interface-setup 12 | - bro-doctor 13 | - ja3 14 | 15 | ## Supported Docker Tags 16 | 17 | The docker tags correspond with the version of [Zeek](https://zeek.org/get-zeek/) installed in the image. Zeek currently has two release tracks: feature and lts. 18 | 19 | * `v3-latest`, `3.2`, `3.2.3` 20 | * `v3-lts`, `3`, `3.0`, `3.0.12` 21 | * `v4-latest`, `4.2`, `4.2.0` 22 | * `v4-lts`, `4.0`, `4.0.5` 23 | * `latest`, `6.2`, `6.2.1` 24 | * `lts`, `6.2`, `6.2.1` 25 | 26 | ## Quickstart 27 | 28 | You'll first need Docker. If you don't already have it here is a quick and dirty way to install it on Linux: 29 | 30 | ```bash 31 | curl -fsSL https://get.docker.com | sh - 32 | ``` 33 | 34 | Otherwise, follow the [install instructions](https://docs.docker.com/get-docker/) for your operating system. 35 | 36 | You can then use the `zeek` script in this repo to quickly get Zeek running. We recommend putting this `zeek` script in your system `PATH`. The rest of this readme will assume this repo's `zeek` script is in the system `PATH`. 37 | 38 | ```bash 39 | sudo wget -O /usr/local/bin/zeek https://raw.githubusercontent.com/activecm/docker-zeek/master/zeek 40 | sudo chmod +x /usr/local/bin/zeek 41 | ``` 42 | 43 | Then use the script to start Zeek. 44 | 45 | ```bash 46 | zeek start 47 | ``` 48 | 49 | ## Customizing 50 | 51 | If the Quickstart section above doesn't fit your needs, you can use the following documentation to customize your install. 52 | 53 | ### Zeek Files Location 54 | 55 | The default location our `zeek` script puts its files on your host is `/opt/zeek/`. You can change this directory by setting the `zeek_top_dir` environment variable. We recommend making this change permanent by creating the file `/etc/profile.d/zeek`. For example, to change the directory to `/usr/local/zeek/`: 56 | 57 | ```bash 58 | echo "export zeek_top_dir=/usr/local/zeek/" | sudo tee -a /etc/profile.d/zeek.sh 59 | source /etc/profile.d/zeek.sh 60 | ``` 61 | 62 | ### Zeek Version 63 | 64 | The default version tag is `6.2.1` which will correspond to the latest release in the 6.2.1 Zeek release channel. You can customize this with the `zeek_release` environment variable. Set this variable to your desired Docker image tag. For example, to use the latest feature release: 65 | 66 | ```bash 67 | echo "export zeek_release=latest" | sudo tee -a /etc/profile.d/zeek.sh 68 | source /etc/profile.d/zeek.sh 69 | ``` 70 | 71 | ### Install a Plugin 72 | 73 | You can install Zeek packages from https://packages.zeek.org/ using the Zeek Package Manager, `zkg`. For example, to install the `hassh` plugin: 74 | 75 | ``` 76 | # Run `zeek start` if you haven't already 77 | docker exec -it zeek zkg install hassh 78 | # Restart Zeek to activate plugin 79 | zeek restart 80 | ``` 81 | 82 | Note: Currently only plugins that don't require compiling can be installed. 83 | 84 | ### Zeek Scripts and local.zeek 85 | 86 | This project will auto-generate a `local.zeek` file. This means that you should _not_ attempt to create or modify this file yourself. Instead, anything that would normally go inside the `local.zeek` file can be put inside one or more `.zeek` files in the `share/zeek/site/autoload` directory. The files there are included in alphabetical order to create the `local.zeek` file. The default `local.zeek` provided by the Zeek project is included for your convenience at `autoload/100-default.zeek` and this file can be safely modified. 87 | 88 | ```bash 89 | sudo mkdir -p /opt/zeek/share/zeek/site/autoload 90 | sudo mv custom.zeek /opt/zeek/share/zeek/site/autoload/210-custom.zeek 91 | zeek restart 92 | ``` 93 | 94 | ### Zeekctl Config 95 | 96 | Zeekctl has several config files you may want to modify such as `zeekctl.cfg` or `networks.cfg`. The default files used are [here](https://github.com/activecm/docker-zeek/tree/master/etc). If you want to provide your own, place your custom file in the appropriate place on your host and then restart Zeek. By default this would be in `/opt/zeek/etc/`. 97 | 98 | The `zeek` script will automatically prompt and create a `node.cfg` file for you. If you would like to re-run this prompt you can delete the existing `node.cfg` file and restart Zeek. For instance, if your files are in the default location: 99 | 100 | ```bash 101 | zeek stop 102 | sudo rm /opt/zeek/etc/node.cfg 103 | zeek start 104 | ``` 105 | 106 | ### Updating 107 | 108 | You can obtain the newest version of the `zeek` script from this repo. 109 | 110 | ```bash 111 | sudo wget -O /usr/local/bin/zeek https://raw.githubusercontent.com/activecm/docker-zeek/master/zeek 112 | ``` 113 | 114 | You can use the included `zeek` script to pull the most recent Docker image. This will also restart your Zeek instance. 115 | 116 | ```bash 117 | zeek update 118 | ``` 119 | 120 | ### Diagnosing Issues 121 | 122 | If Zeek crashes right after starting you can check the log output. 123 | 124 | ``` 125 | docker logs zeek 126 | ``` 127 | 128 | If Zeek is successfully capturing and you want to see if there are any issues: 129 | 130 | ``` 131 | # Container must be running already 132 | docker exec zeek zeekctl doctor 133 | ``` 134 | 135 | ## Development 136 | 137 | Developer documentation can be found in the [docs](docs/) folder. 138 | 139 | ## Credits 140 | 141 | Dockerfile based on [blacktop/docker-zeek](https://github.com/blacktop/docker-zeek/tree/master/zeekctl). 142 | -------------------------------------------------------------------------------- /docker-compose.example.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | 3 | services: 4 | zeek: 5 | image: activecm/zeek 6 | build: . 7 | 8 | cap_add: 9 | - net_raw 10 | - net_admin 11 | network_mode: host 12 | 13 | volumes: 14 | - type: bind 15 | source: /etc/localtime 16 | target: /etc/localtime 17 | read_only: true 18 | 19 | - type: bind 20 | source: ${LOGS:-./logs} # Edit this to the path you want zeek logs to be written 21 | target: /usr/local/zeek/logs 22 | 23 | - type: bind 24 | source: ${NODCFG:-./etc/node.sample.cfg} 25 | target: /usr/local/zeek/etc/node.cfg 26 | 27 | # Uncomment this block if you want to customize the zeek scripts loaded 28 | #- type: bind 29 | # source: ./share/zeek/site/local.zeek 30 | # target: /usr/local/zeek/share/zeek/site/local.zeek 31 | 32 | # Uncomment this block if you want to customize your internal network ranges 33 | #- type: bind 34 | # source: ./etc/networks.cfg # Edit this file with your custom networks 35 | # target: /usr/local/zeek/etc/networks.cfg 36 | 37 | # Uncomment this block if you want to customize zeekctl settings (unlikely) 38 | #- type: bind 39 | # source: ./etc/zeekctl.cfg 40 | # target: /usr/local/zeek/etc/zeekctl.cfg 41 | 42 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit script if an error is encountered 4 | set -e 5 | 6 | if [ ! -f /usr/local/zeek/etc/node.cfg ] || [ ! -s /usr/local/zeek/etc/node.cfg ]; then 7 | # node.cfg doesn't exist or is empty 8 | if [ -t 0 ]; then 9 | # at a tty, so start the config wizard 10 | zeekcfg -o /usr/local/zeek/etc/node.cfg --type afpacket --processes 0 --no-pin 11 | fi 12 | if [ ! -f /usr/local/zeek/etc/node.cfg ] || [ ! -s /usr/local/zeek/etc/node.cfg ]; then 13 | # if still doesn't exist 14 | echo 15 | echo "You must first create a node.cfg file and mount it into the container." 16 | exit 1 17 | fi 18 | fi 19 | 20 | # do final log rotation 21 | stop() { 22 | echo "Stopping zeek..." 23 | zeekctl stop 24 | trap - SIGINT SIGTERM 25 | exit 26 | } 27 | 28 | # run zeekctl diag on error 29 | diag() { 30 | echo "Running zeekctl diag for debugging" 31 | zeekctl diag 32 | trap - ERR 33 | } 34 | trap 'diag' ERR 35 | 36 | # ensure Zeek has a valid, updated config, and then start Zeek 37 | echo "Checking your Zeek configuration..." 38 | # generate a single local.zeek from a bunch of partials 39 | #We specifically strip out the line for misc/scan as it's no longer part of zeek and it's darn near impossible to find. 40 | cat /usr/local/zeek/share/zeek/site/autoload/* | grep -v '^#' | grep -v 'misc/scan' >/usr/local/zeek/share/zeek/site/local.zeek 41 | zeekctl check >/dev/null 42 | zeekctl install 43 | zeekctl start 44 | 45 | # ensure spool logs are rotated when container is stopped 46 | trap 'stop' SIGINT SIGTERM 47 | 48 | # periodically run the Zeek cron monitor to restart any terminated processes 49 | zeekctl cron enable 50 | # disable the zeekctl ERR trap as there are no more zeek commands to fail 51 | trap - ERR 52 | 53 | # daemonize cron but log output to stdout 54 | crond -b -L /dev/fd/1 55 | 56 | # infinite loop to prevent container from exiting and allow this script to process signals 57 | while :; do sleep 1s; done 58 | -------------------------------------------------------------------------------- /docs/build.md: -------------------------------------------------------------------------------- 1 | # Automatic Build (Dockerhub) 2 | 3 | The steps to take vary based on what has changed in the new version. 4 | 5 | If the Zeek version changes it needs to be updated in the following places: 6 | - Default value for the `ZEEK_VERSION` build arg in the `Dockerfile` 7 | - List of available tags in `Readme.md` 8 | - Version specified in the Github workflow (`.github/workflows/docker-build.yml`) 9 | 10 | If the `Readme.md` changes the contents need to be copied to the Dockerhub project manually. This is due to using Github Actions to push up multiple images (vs. using Dockerhub to pull the code and build a single image). Dockerhub does not automatically update the project with the readme when using the push model. An API is not currently available to do this programmatically. 11 | 12 | To trigger a new image build on Dockerhub, push changes to master (or merge a pull request into master) on Github. 13 | 14 | # Manual Build 15 | 16 | Using default values defined in the dockerfile: 17 | 18 | ```bash 19 | docker build -t activecm/zeek . 20 | ``` 21 | 22 | Using a specific Zeek version: 23 | 24 | ```bash 25 | # Note: tag the image with the Zeek version used 26 | docker build --build-arg ZEEK_VERSION=3.0.6 -t activecm/zeek:3.0.6 . 27 | ``` 28 | 29 | Using a specific Zeekcfg version: 30 | 31 | ```bash 32 | docker build --build-arg ZEEKCFG_VERSION=0.0.4 -t activecm/zeek . 33 | ``` 34 | 35 | Bundling custom Zeek packages in the image: 36 | 37 | ```bash 38 | docker build --build-arg ZEEK_DEFAULT_PACKAGES="bro-interface-setup ja3 hassh" -t activecm/zeek . 39 | ``` 40 | 41 | Increasing the number of build processes (recommend to set to number of CPU cores): 42 | ```bash 43 | docker build --build-arg BUILD_PROCS=8 -t activecm/zeek . 44 | ``` 45 | 46 | # Checking Versions 47 | 48 | Verifying the Zeek version installed: 49 | 50 | ```bash 51 | docker run --rm activecm/zeek zeek --version 52 | ``` 53 | 54 | Verifying the Zeek packages installed: 55 | 56 | ```bash 57 | docker run --rm activecm/zeek zkg list 58 | ``` -------------------------------------------------------------------------------- /etc/networks.cfg: -------------------------------------------------------------------------------- 1 | # List of local networks in CIDR notation, optionally followed by a 2 | # descriptive tag. 3 | # For example, "10.0.0.0/8" or "fe80::/64" are valid prefixes. 4 | 5 | 10.0.0.0/8 Private IP space 6 | 172.16.0.0/12 Private IP space 7 | 192.168.0.0/16 Private IP space 8 | -------------------------------------------------------------------------------- /etc/node.example.cfg: -------------------------------------------------------------------------------- 1 | # Example ZeekControl node configuration. 2 | # 3 | # This example has a standalone node ready to go except for possibly changing 4 | # the sniffing interface. 5 | 6 | # This is a complete standalone configuration. Most likely you will 7 | # only need to change the interface. 8 | #[zeek] 9 | #type=standalone 10 | #host=localhost 11 | #interface=eth0 12 | 13 | ## Below is an example clustered configuration. If you use this, 14 | ## remove the [zeek] node above. 15 | 16 | [manager] 17 | type=manager 18 | host=localhost 19 | 20 | [proxy-1] 21 | type=proxy 22 | host=localhost 23 | 24 | [worker-1] 25 | type=worker 26 | host=localhost 27 | # Change eth0 to match your capture interface 28 | interface=af_packet::eth0 29 | lb_method=custom 30 | # Change based on the number of cores you want to dedicate to worker processes 31 | lb_procs=4 32 | # Uncomment and modify if you need to squeeze out even more performance. 33 | #pin_cpus=0,1,2,3,4 34 | # Optional parameters for per node configuration: 35 | af_packet_fanout_id=23 36 | af_packet_fanout_mode=AF_Packet::FANOUT_HASH 37 | af_packet_buffer_size=128*1024*1024 38 | -------------------------------------------------------------------------------- /etc/zeekctl.cfg: -------------------------------------------------------------------------------- 1 | ## Global ZeekControl configuration file. 2 | 3 | ############################################### 4 | # Mail Options 5 | 6 | # Recipient address for all emails sent out by Zeek and ZeekControl. 7 | MailTo = root@localhost 8 | 9 | # Mail connection summary reports each log rotation interval. A value of 1 10 | # means mail connection summaries, and a value of 0 means do not mail 11 | # connection summaries. This option has no effect if the trace-summary 12 | # script is not available. 13 | # We're disabling this because sendmail is not commonly set up and it provides an error very hour. 14 | MailConnectionSummary = 0 15 | 16 | # Lower threshold (in percentage of disk space) for space available on the 17 | # disk that holds SpoolDir. If less space is available, "zeekctl cron" starts 18 | # sending out warning emails. A value of 0 disables this feature. 19 | MinDiskSpace = 0 20 | 21 | # Send mail when "zeekctl cron" notices the availability of a host in the 22 | # cluster to have changed. A value of 1 means send mail when a host status 23 | # changes, and a value of 0 means do not send mail. 24 | MailHostUpDown = 0 25 | 26 | ############################################### 27 | # Logging Options 28 | 29 | # Rotation interval in seconds for log files on manager (or standalone) node. 30 | # A value of 0 disables log rotation. 31 | LogRotationInterval = 3600 32 | 33 | # Expiration interval for archived log files in LogDir. Files older than this 34 | # will be deleted by "zeekctl cron". The interval is an integer followed by 35 | # one of these time units: day, hr, min. A value of 0 means that logs 36 | # never expire. 37 | LogExpireInterval = 0 38 | 39 | # Enable ZeekControl to write statistics to the stats.log file. A value of 1 40 | # means write to stats.log, and a value of 0 means do not write to stats.log. 41 | StatsLogEnable = 1 42 | 43 | # Number of days that entries in the stats.log file are kept. Entries older 44 | # than this many days will be removed by "zeekctl cron". A value of 0 means 45 | # that entries never expire. 46 | StatsLogExpireInterval = 0 47 | 48 | ############################################### 49 | # Other Options 50 | 51 | # Show all output of the zeekctl status command. If set to 1, then all output 52 | # is shown. If set to 0, then zeekctl status will not collect or show the peer 53 | # information (and the command will run faster). 54 | StatusCmdShowAll = 0 55 | 56 | # Number of days that crash directories are kept. Crash directories older 57 | # than this many days will be removed by "zeekctl cron". A value of 0 means 58 | # that crash directories never expire. 59 | CrashExpireInterval = 0 60 | 61 | # Site-specific policy script to load. Zeek will look for this in 62 | # $PREFIX/share/zeek/site. A default local.zeek comes preinstalled 63 | # and can be customized as desired. 64 | SitePolicyScripts = local.zeek 65 | 66 | # Location of the log directory where log files will be archived each rotation 67 | # interval. 68 | # NOTE: This is the path inside a docker container. If you want to change the location 69 | # on your host system, this is not the place to do it. See https://github.com/activecm/docker-zeek#zeek-files-location 70 | LogDir = /usr/local/zeek/logs 71 | 72 | # Location of the spool directory where files and data that are currently being 73 | # written are stored. 74 | # NOTE: This is the path inside a docker container. If you want to change the location 75 | # on your host system, this is not the place to do it. See https://github.com/activecm/docker-zeek#zeek-files-location 76 | SpoolDir = /usr/local/zeek/spool 77 | 78 | # Location of other configuration files that can be used to customize 79 | # ZeekControl operation (e.g. local networks, nodes). 80 | # NOTE: This is the path inside a docker container. If you want to change the location 81 | # on your host system, this is not the place to do it. See https://github.com/activecm/docker-zeek#zeek-files-location 82 | CfgDir = /usr/local/zeek/etc 83 | 84 | # https://github.com/ncsa/bro-interface-setup 85 | interfacesetup.enabled=1 86 | # https://github.com/Security-Onion-Solutions/securityonion-setup/blob/ec219e2cbf72ffa52c4612e642e543c022f9c5ca/bin/sosetup-network#L446 87 | interfacesetup.flags_command=/sbin/ethtool -K {interface} rx off tx off sg off tso off ufo off gso off gro off lro off 88 | -------------------------------------------------------------------------------- /logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/activecm/docker-zeek/9edadec34a8858555851c1c6490718d70ae60757/logs/.gitkeep -------------------------------------------------------------------------------- /share/zeek/site/autoload/001-unload-scripts.zeek: -------------------------------------------------------------------------------- 1 | ##! Do NOT customize this file. Use autoload/100-default.zeek or a custom 2 | ##! script in autoload/ instead. 3 | ##! 4 | ##! This file WILL be overwritten when upgrading or reinstalling! 5 | 6 | 7 | # @unload specifies a Zeek script that we don't want to load (so subsequent attempts to load will be skipped). 8 | # However, if the specified script has already been loaded, then this directive has no affect. 9 | # https://docs.zeek.org/en/master/script-reference/directives.html#unload 10 | 11 | # Disable MD5 and SHA1 hashing for all files. 12 | @unload frameworks/files/hash-all-files 13 | 14 | # Disable detecting SHA1 sums in Team Cymru's Malware Hash Registry. 15 | @unload frameworks/files/detect-MHR 16 | -------------------------------------------------------------------------------- /share/zeek/site/autoload/100-default.zeek: -------------------------------------------------------------------------------- 1 | ##! Local site policy. Customize as appropriate. 2 | ##! 3 | ##! This file will not be overwritten when upgrading or reinstalling! 4 | 5 | # This script logs which scripts were loaded during each run. 6 | @load misc/loaded-scripts 7 | 8 | # Apply the default tuning scripts for common tuning settings. 9 | @load tuning/defaults 10 | 11 | # Estimate and log capture loss. 12 | @load misc/capture-loss 13 | 14 | # Enable logging of memory, packet and lag statistics. 15 | @load misc/stats 16 | 17 | # DO NOT Load the scan detection script, no longer included. 18 | # @load misc/scan 19 | 20 | # Detect traceroute being run on the network. This could possibly cause 21 | # performance trouble when there are a lot of traceroutes on your network. 22 | # Enable cautiously. 23 | #@load misc/detect-traceroute 24 | 25 | # Generate notices when vulnerable versions of software are discovered. 26 | # The default is to only monitor software found in the address space defined 27 | # as "local". Refer to the software framework's documentation for more 28 | # information. 29 | @load frameworks/software/vulnerable 30 | 31 | # Detect software changing (e.g. attacker installing hacked SSHD). 32 | @load frameworks/software/version-changes 33 | 34 | # This adds signatures to detect cleartext forward and reverse windows shells. 35 | @load-sigs frameworks/signatures/detect-windows-shells 36 | 37 | # Load all of the scripts that detect software in various protocols. 38 | @load protocols/ftp/software 39 | @load protocols/smtp/software 40 | @load protocols/ssh/software 41 | @load protocols/http/software 42 | # The detect-webapps script could possibly cause performance trouble when 43 | # running on live traffic. Enable it cautiously. 44 | #@load protocols/http/detect-webapps 45 | 46 | # This script detects DNS results pointing toward your Site::local_nets 47 | # where the name is not part of your local DNS zone and is being hosted 48 | # externally. Requires that the Site::local_zones variable is defined. 49 | @load protocols/dns/detect-external-names 50 | 51 | # Script to detect various activity in FTP sessions. 52 | @load protocols/ftp/detect 53 | 54 | # Scripts that do asset tracking. 55 | @load protocols/conn/known-hosts 56 | @load protocols/conn/known-services 57 | @load protocols/ssl/known-certs 58 | 59 | # This script enables SSL/TLS certificate validation. 60 | @load protocols/ssl/validate-certs 61 | 62 | # This script prevents the logging of SSL CA certificates in x509.log 63 | @load protocols/ssl/log-hostcerts-only 64 | 65 | # Uncomment the following line to check each SSL certificate hash against the ICSI 66 | # certificate notary service; see http://notary.icsi.berkeley.edu . 67 | # @load protocols/ssl/notary 68 | 69 | # If you have GeoIP support built in, do some geographic detections and 70 | # logging for SSH traffic. 71 | @load protocols/ssh/geo-data 72 | # Detect hosts doing SSH bruteforce attacks. 73 | @load protocols/ssh/detect-bruteforcing 74 | # Detect logins using "interesting" hostnames. 75 | @load protocols/ssh/interesting-hostnames 76 | 77 | # Detect SQL injection attacks. 78 | @load protocols/http/detect-sqli 79 | 80 | #### Network File Handling #### 81 | 82 | # Enable MD5 and SHA1 hashing for all files. 83 | @load frameworks/files/hash-all-files 84 | 85 | # Detect SHA1 sums in Team Cymru's Malware Hash Registry. 86 | @load frameworks/files/detect-MHR 87 | 88 | # DO NOT Extend email alerting to include hostnames 89 | # This module causes errors in docker-zeek: 90 | # timestamp expression error in /usr/local/zeek/share/zeek/policy/frameworks/notice/extend-email/hostnames.zeek, line 39: no such index (Notice::tmp_notice_storage[Notice::uid]) 91 | # @load policy/frameworks/notice/extend-email/hostnames 92 | 93 | # Uncomment the following line to enable detection of the heartbleed attack. Enabling 94 | # this might impact performance a bit. 95 | # @load policy/protocols/ssl/heartbleed 96 | 97 | # Uncomment the following line to enable logging of connection VLANs. Enabling 98 | # this adds two VLAN fields to the conn.log file. 99 | # @load policy/protocols/conn/vlan-logging 100 | 101 | # Uncomment the following line to enable logging of link-layer addresses. Enabling 102 | # this adds the link-layer address for each connection endpoint to the conn.log file. 103 | # @load policy/protocols/conn/mac-logging 104 | -------------------------------------------------------------------------------- /share/zeek/site/autoload/200-inactivity_timeout.zeek: -------------------------------------------------------------------------------- 1 | ##! Do NOT customize this file. Use autoload/100-default.zeek or a custom 2 | ##! script in autoload/ instead. 3 | ##! 4 | ##! This file WILL be overwritten when upgrading or reinstalling! 5 | 6 | # This is important for accurate connection info. More info here: 7 | # https://www.activecountermeasures.com/fixing-bro-zeeks-long-connection-detection-problem/ 8 | redef tcp_inactivity_timeout = 60 min; 9 | -------------------------------------------------------------------------------- /share/zeek/site/autoload/900-zkg.zeek: -------------------------------------------------------------------------------- 1 | ##! Do NOT customize this file. Use autoload/100-default.zeek or a custom 2 | ##! script in autoload/ instead. 3 | ##! 4 | ##! This file WILL be overwritten when upgrading or reinstalling! 5 | 6 | # Auto load installed packages from the Zeek package manager 7 | @load packages 8 | -------------------------------------------------------------------------------- /zeek: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #Sample start/stop script for Zeek running inside docker 3 | #based on service_script_template v0.2 4 | #Many thanks to Logan for his Active-Flow init script, from which some of the following was copied. 5 | #Many thanks to Ethan for his help with the design and implementation, and for the help in troubleshooting readpcap 6 | #V0.5.2 7 | 8 | #The --ulimit settings in this file address an issue in an upstream library 9 | #used by zeek where the library allocates two arrays of ints, one entry for 10 | #every possible file descriptor (which is massive in RHEL9 and derivatives 11 | #and allocates 4gb physical, 16gb virtual. See 12 | # https://github.com/zeek/zeek/issues/2951 13 | #for more details. 14 | 15 | #==== USER CUSTOMIZATION ==== 16 | #The default Zeek top level directory (/opt/zeek) can be overridden with 17 | #the "zeek_top_dir" environment variable. Edit /etc/profile.d/zeek and 18 | #add the line (without leading "#"): 19 | #export zeek_top_dir='/my/data/zeek/' 20 | # 21 | #Similarly, the preferred release of zeek ("3.0", which covers any 3.0.x 22 | #version) can be overridden with the "zeek_release" variable. Edit the 23 | #/etc/profile.d/zeek file and add the line (without leading "#"): 24 | #export zeek_release='lts' 25 | # 26 | #You'll need to log out and log back in again for these lines to take effect. 27 | 28 | # If the current user doesn't have docker permissions run with sudo 29 | SUDO='' 30 | if [ ! -w "/var/run/docker.sock" ]; then 31 | SUDO="sudo --preserve-env " 32 | fi 33 | 34 | #The user can set the top level directory that holds all zeek content by setting it in "zeek_top_dir" (default "/opt/zeek") 35 | HOST_ZEEK=${zeek_top_dir:-/opt/zeek} 36 | IMAGE_NAME="activecm/zeek:${zeek_release:-latest}" 37 | 38 | # initilizes Zeek directories and config files on the host 39 | init_zeek_cfg() { 40 | # create a temporary container to run commands 41 | local container="zeek-init-$RANDOM" 42 | $SUDO docker run \ 43 | --ulimit nofile=1048576:1048576 \ 44 | --detach \ 45 | --name $container \ 46 | -v "$HOST_ZEEK":"/zeek" \ 47 | --network host \ 48 | "$IMAGE_NAME" \ 49 | sh -c 'while sleep 1; do :; done' >/dev/null 2>&1 50 | # ensure the temporary container is removed 51 | trap "$SUDO docker rm --force $container >/dev/null 2>&1" EXIT 52 | 53 | # run commands using $SUDO docker to avoid unnecessary sudo calls 54 | # create directories required for running Zeek 55 | $SUDO docker exec $container mkdir -p \ 56 | "/zeek/manual-logs" \ 57 | "/zeek/logs" \ 58 | "/zeek/spool" \ 59 | "/zeek/etc" \ 60 | "/zeek/share/zeek/site/autoload" 2>/dev/null \ 61 | || true # suppress error code if symlink exists 62 | 63 | # make logs readable to all users 64 | $SUDO docker exec $container chmod -f 0755 \ 65 | "/zeek/manual-logs" \ 66 | "/zeek/logs" \ 67 | "/zeek/spool" 2>/dev/null \ 68 | || true # suppress error code if chmod fails 69 | 70 | # initialize config files that are commonly customized 71 | if [ ! -f "$HOST_ZEEK/etc/networks.cfg" ]; then 72 | $SUDO docker exec $container cp -f /usr/local/zeek/etc/networks.cfg /zeek/etc/networks.cfg 73 | fi 74 | if [ ! -f "$HOST_ZEEK/etc/zeekctl.cfg" ]; then 75 | $SUDO docker exec $container cp -f /usr/local/zeek/etc/zeekctl.cfg /zeek/etc/zeekctl.cfg 76 | fi 77 | if [ ! -f "$HOST_ZEEK/share/zeek/site/autoload/100-default.zeek" ]; then 78 | $SUDO docker exec $container cp -f /usr/local/zeek/share/zeek/site/autoload/100-default.zeek /zeek/share/zeek/site/autoload/100-default.zeek 79 | fi 80 | 81 | # Copy all default autoload partials to the host, overwriting existing files 82 | $SUDO docker exec $container bash -c 'find /usr/local/zeek/share/zeek/site/autoload/ -type f -iname \*.zeek ! -name 100-default.zeek -exec cp -f "{}" /zeek/share/zeek/site/autoload/ \;' 83 | 84 | # archive the existing local.zeek if it exists 85 | if [ -f "$HOST_ZEEK/share/zeek/site/local.zeek" ]; then 86 | echo "Renaming existing local.zeek file to local.zeek.bak. Please use the autoload directory or zkg to load Zeek scripts." >&2 87 | local local_zeek_bak="$HOST_ZEEK/share/zeek/site/local.zeek.bak" 88 | echo "# THIS FILE HAS BEEN ARCHIVED." | $SUDO tee "$local_zeek_bak" > /dev/null 89 | echo "# Please $HOST_ZEEK/share/zeek/site/autoload instead. Any files ending with .zeek" | $SUDO tee -a "$local_zeek_bak" > /dev/null 90 | echo "# in the autoload directory will be automatically added to Zeek's running configuration." | $SUDO tee -a "$local_zeek_bak" > /dev/null 91 | echo "# after running \"zeek reload\"." | $SUDO tee -a "$local_zeek_bak" > /dev/null 92 | cat "$HOST_ZEEK/share/zeek/site/local.zeek" | $SUDO tee -a "$local_zeek_bak" > /dev/null 93 | $SUDO rm "$HOST_ZEEK/share/zeek/site/local.zeek" 94 | fi 95 | 96 | # create the node.cfg file required for running Zeek (but not if we're in readpcap mode, and not if it exists already) 97 | if [ "$1" != "readpcap" -a ! -s "$HOST_ZEEK/etc/node.cfg" ]; then 98 | echo "Could not find $HOST_ZEEK/etc/node.cfg. Generating one now." >&2 99 | $SUDO docker exec -it $container zeekcfg -o "/zeek/etc/node.cfg" --type afpacket --processes 0 --no-pin 100 | fi 101 | } 102 | 103 | main() { 104 | if [ -n "$1" ]; then 105 | case "$1" in 106 | start|stop|readpcap|restart|force-restart|status|reload|enable|disable|pull|update) 107 | action="$1" 108 | if [ "$action" = "readpcap" ]; then 109 | if [ -n "$2" -a -e "$2" ]; then 110 | pcap_filename="$2" 111 | MANUAL_LOG_DIR=$(realpath "${3:-$HOST_ZEEK/manual-logs}") 112 | if [ ! -e "$MANUAL_LOG_DIR" ]; then 113 | $SUDO mkdir -p "$MANUAL_LOG_DIR" 114 | fi 115 | if [ ! -d "$MANUAL_LOG_DIR" ]; then 116 | echo "Unable to create directory $MANUAL_LOG_DIR , exiting." >&2 117 | exit 1 118 | fi 119 | else 120 | echo "readpcap requires an existing pcap filename as a second parameter and accepts" >&2 121 | echo "an (optional) third parameter for the directory in which to place the" >&2 122 | echo "output logs (default: /opt/zeek/manual-logs/). Please fix and re-run. Exiting." >&2 123 | exit 1 124 | fi 125 | fi 126 | ;; 127 | *) 128 | echo "Unrecognized action $1 , exiting" >&2 129 | exit 1 130 | ;; 131 | esac 132 | else 133 | echo 'This script expects a command line option (start, stop, readpcap, restart, status, reload, enable or disable).' >&2 134 | echo 'In the case of readpcap, please supply the pcap filename as the second command line parameter.' >&2 135 | echo 'readpcap also accepts an (optional) directory in which to save the logs as the third command line parameter.' >&2 136 | echo 'Please run again. Exiting' >&2 137 | exit 1 138 | fi 139 | 140 | local container="zeek" 141 | 142 | local running="false" 143 | local restart="always" #Not used in readpcap, where this is forced to "no" 144 | if $SUDO docker inspect "$container" &>/dev/null; then 145 | running=`$SUDO docker inspect -f "{{ .State.Running }}" $container 2>/dev/null` 146 | restart=`$SUDO docker inspect -f "{{ .HostConfig.RestartPolicy.Name }}" $container 2>/dev/null` 147 | fi 148 | 149 | case "$action" in 150 | start) 151 | #Command(s) needed to start the service right now 152 | 153 | if [ "$running" = "true" ]; then 154 | echo "Zeek is already running." >&2 155 | exit 0 156 | fi 157 | 158 | init_zeek_cfg 159 | 160 | # create the volumes required for peristing user-installed zkg packages 161 | $SUDO docker volume create zeek-zkg-script >/dev/null 162 | $SUDO docker volume create zeek-zkg-plugin >/dev/null 163 | $SUDO docker volume create zeek-zkg-state >/dev/null 164 | 165 | docker_cmd=("docker" "run" "--detach") # start container in the background 166 | docker_cmd+=("--ulimit" "nofile=1048576:1048576") 167 | docker_cmd+=("--name" "$container") # provide a predictable name 168 | docker_cmd+=("--restart" "$restart") 169 | docker_cmd+=("--cap-add" "net_raw") # allow Zeek to listen to raw packets 170 | docker_cmd+=("--cap-add" "net_admin") # allow Zeek to modify interface settings 171 | docker_cmd+=("--network" "host") # allow Zeek to monitor host network interfaces 172 | 173 | # allow packages installed via zkg to persist across restarts 174 | docker_cmd+=("--mount" "source=zeek-zkg-script,destination=/usr/local/zeek/share/zeek/site/packages/,type=volume") 175 | docker_cmd+=("--mount" "source=zeek-zkg-plugin,destination=/usr/local/zeek/lib/zeek/plugins/packages/,type=volume") 176 | docker_cmd+=("--mount" "source=zeek-zkg-state,destination=/root/.zkg,type=volume") 177 | 178 | # mirror the host timezone settings to the container 179 | docker_cmd+=("--mount" "source=/etc/localtime,destination=/etc/localtime,type=bind,readonly") 180 | 181 | # persist and allow accessing the logs from the host 182 | docker_cmd+=("--mount" "source=$HOST_ZEEK/logs,destination=/usr/local/zeek/logs/,type=bind") 183 | docker_cmd+=("--mount" "source=$HOST_ZEEK/spool,destination=/usr/local/zeek/spool/,type=bind") 184 | 185 | # allow users to provide arbitrary custom config files and scripts 186 | # mount all zeekctl config files 187 | while IFS= read -r -d $'\0' CONFIG; do 188 | docker_cmd+=("--mount" "source=$CONFIG,destination=/usr/local/zeek/${CONFIG#"$HOST_ZEEK"},type=bind") 189 | done < <(find "$HOST_ZEEK/etc/" -type f -print0 2>/dev/null) 190 | # mount all zeek scripts, except local.zeek which will be auto-generated instead 191 | while IFS= read -r -d $'\0' SCRIPT; do 192 | docker_cmd+=("--mount" "source=$SCRIPT,destination=/usr/local/zeek/${SCRIPT#"$HOST_ZEEK"},type=bind") 193 | done < <(find "$HOST_ZEEK/share/" -type f -iname \*.zeek ! -name local.zeek -print0 2>/dev/null) 194 | # loop reference: https://stackoverflow.com/a/23357277 195 | # ${CONFIG#"$HOST_ZEEK"} and ${SCRIPT#"$HOST_ZEEK"} strip $HOST_ZEEK prefix 196 | 197 | docker_cmd+=("$IMAGE_NAME") 198 | 199 | echo "Starting the Zeek docker container" >&2 200 | $SUDO "${docker_cmd[@]}" 201 | 202 | # Fix current symlink for the host (sleep to give Zeek time to finish starting) 203 | (sleep 30s; $SUDO docker exec "$container" ln -sfn "../spool/manager" /usr/local/zeek/logs/current) & 204 | 205 | ;; 206 | 207 | stop) 208 | #Command(s) needed to stop the service right now 209 | 210 | if [ "$running" != "false" ]; then 211 | echo "Stopping the Zeek docker container" >&2 212 | $SUDO docker stop -t 90 "$container" >&2 213 | else 214 | echo "Zeek is already stopped." >&2 215 | fi 216 | 217 | $SUDO docker rm --force "$container" >/dev/null 2>&1 218 | ;; 219 | 220 | readpcap) 221 | #Command(s) needed to process a pcap file 222 | 223 | init_zeek_cfg readpcap #Parameter is used to tell init_zeek_cfg to skip creating node.cfg (as it's not needed for readpcap) 224 | 225 | # create the volumes required for peristing user-installed zkg packages 226 | $SUDO docker volume create zeek-zkg-script >/dev/null 227 | $SUDO docker volume create zeek-zkg-plugin >/dev/null 228 | $SUDO docker volume create zeek-zkg-state >/dev/null 229 | 230 | docker_cmd=("docker" "run" "--rm") # start container in the foreground 231 | docker_cmd+=("--ulimit" "nofile=1048576:1048576") 232 | docker_cmd+=("--workdir" "/usr/local/zeek/logs/") 233 | 234 | # allow packages installed via zkg to persist across restarts 235 | docker_cmd+=("--mount" "source=zeek-zkg-script,destination=/usr/local/zeek/share/zeek/site/packages/,type=volume") 236 | docker_cmd+=("--mount" "source=zeek-zkg-plugin,destination=/usr/local/zeek/lib/zeek/plugins/packages/,type=volume") 237 | docker_cmd+=("--mount" "source=zeek-zkg-state,destination=/root/.zkg,type=volume") 238 | 239 | # mirror the host timezone settings to the container 240 | docker_cmd+=("--mount" "source=/etc/localtime,destination=/etc/localtime,type=bind,readonly") 241 | 242 | # persist and allow accessing the logs from the host 243 | docker_cmd+=("--mount" "source=$MANUAL_LOG_DIR,destination=/usr/local/zeek/logs/,type=bind") 244 | 245 | # mount the incoming pcap file 246 | abs_path=$(realpath "$pcap_filename") 247 | docker_cmd+=("--mount" "source=$abs_path,destination=/incoming.pcap,type=bind,readonly") 248 | 249 | # allow users to provide arbitrary custom config files and scripts 250 | # mount all zeekctl config files 251 | while IFS= read -r -d $'\0' CONFIG; do 252 | docker_cmd+=("--mount" "source=$CONFIG,destination=/usr/local/zeek/${CONFIG#"$HOST_ZEEK"},type=bind") 253 | done < <(find "$HOST_ZEEK/etc/" -type f -print0 2>/dev/null) 254 | # mount all zeek scripts, except local.zeek which will be auto-generated instead 255 | while IFS= read -r -d $'\0' SCRIPT; do 256 | docker_cmd+=("--mount" "source=$SCRIPT,destination=/usr/local/zeek/${SCRIPT#"$HOST_ZEEK"},type=bind") 257 | done < <(find "$HOST_ZEEK/share/" -type f -iname \*.zeek ! -name local.zeek -print0 2>/dev/null) 258 | # loop reference: https://stackoverflow.com/a/23357277 259 | # ${CONFIG#"$HOST_ZEEK"} and ${SCRIPT#"$HOST_ZEEK"} strip $HOST_ZEEK prefix 260 | 261 | docker_cmd+=("--entrypoint" "/bin/bash") #Running /bin/bash -c "series ; of ; shell ; commands" lets use effectively run a shell script inside the container. 262 | docker_cmd+=("$IMAGE_NAME") 263 | #If you want to output diags before running, add " ; /usr/local/zeek/bin/zeekctl diag just before running zeek in the following. 264 | docker_cmd+=("-c" "/bin/cat /usr/local/zeek/share/zeek/site/autoload/* | /bin/grep -v '^#' | /bin/grep -v 'misc/scan' >/usr/local/zeek/share/zeek/site/local.zeek ; /bin/mv -f /usr/local/zeek/share/zeek/builtin-plugins/Zeek_AF_Packet/{__load__.zeek,init.zeek} /usr/local/zeek/share/zeek/builtin-plugins/ || /bin/true ; /usr/local/zeek/bin/zeek -C -r /incoming.pcap local 'Site::local_nets += { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }' 'Notice::sendmail = ' 2>&1 | grep -v 'Node names are not added to logs (not in cluster mode'") 265 | echo "Starting the Zeek docker container" >&2 266 | echo "Zeek logs will be saved to $MANUAL_LOG_DIR" >&2 267 | #Show the command, useful for debugging 268 | #echo $SUDO "${docker_cmd[@]}" 269 | $SUDO "${docker_cmd[@]}" 270 | ;; 271 | 272 | restart|force-restart) 273 | #Command(s) needed to stop and start the service right now 274 | #You can test the value of "$action" in case there's a different set of steps needed to "force-restart" 275 | echo "Restarting the Zeek docker container" >&2 276 | $0 stop 277 | $0 start 278 | ;; 279 | 280 | status) 281 | #Command(s) needed to tell the user the state of the service 282 | echo "Zeek docker container status" >&2 283 | $SUDO docker ps --filter name=zeek >&2 284 | 285 | echo "Zeek processes status" >&2 286 | $SUDO docker exec "$container" zeekctl status >&2 287 | ;; 288 | 289 | reload) 290 | #Command(s) needed to tell the service to reload any configuration files 291 | echo "Reloading Zeek docker container configuration files" >&2 292 | #Note; I'm not aware of a way to do a config file reload, so forcing a full restart at the moment. 293 | $0 stop 294 | $0 start 295 | ;; 296 | 297 | enable) 298 | #Command(s) needed to start the service on future boots 299 | echo "Enabling Zeek docker container on future boots" >&2 300 | if [ "$running" = "false" ]; then 301 | echo "Zeek is stopped - please start first to set restart policy." >&2 302 | exit 0 303 | fi 304 | 305 | $SUDO docker update --restart always "$container" >&2 306 | ;; 307 | 308 | disable) 309 | #Command(s) needed to stop the service on future boots 310 | echo "Blocking Zeek docker container from starting on future boots" >&2 311 | if [ "$running" = "false" ]; then 312 | echo "Zeek is stopped - please start first to set restart policy." >&2 313 | exit 0 314 | fi 315 | 316 | $SUDO docker update --restart no "$container" >&2 317 | ;; 318 | 319 | pull|update) 320 | #Command needed to pull down a new version of Zeek if there's a new docker image 321 | $SUDO docker pull "$IMAGE_NAME" 322 | 323 | $0 stop 324 | $0 start 325 | ;; 326 | 327 | *) 328 | echo "Unrecognized action $action , exiting" >&2 329 | exit 1 330 | ;; 331 | esac 332 | 333 | exit 0 334 | } 335 | 336 | if [ "$0" = "$BASH_SOURCE" ]; then 337 | # script was executed, not sourced 338 | main "$@" 339 | fi 340 | --------------------------------------------------------------------------------