diff --git a/.docker/s6/prepare b/.docker/s6/prepare new file mode 100755 index 0000000..ef626ad --- /dev/null +++ b/.docker/s6/prepare @@ -0,0 +1,41 @@ +#!/usr/bin/with-contenv bash +CONFIG_FILE=${CONFIG_FILE:-"$myWORKDIR/conf/synapse.conf"} +LOG_FILE="$myWORKDIR/logs/synapse.log" + +echo "${0##*/} || Write config file..." +cat << EOF > $CONFIG_FILE +[api] +debug:${DEBUG:-False} +host:${HOST:-"0.0.0.0"} +port:${PORT:-5000} +threaded:${API_THREADED:-True} + +[TheHive] +url:${TH_URL:-http://thehive:9000} +user:${TH_USER:-synapse} +api_key:${TH_API_KEY} + +[EWS] +#ip or domain to EWS server +server:${EWS_HOST} +#According to exchangelib doc: +#"username is usually in WINDOMAIN\username format +#some servers also accept usernames in PrimarySMTPAddress +#('myusername@example.com') format (Office365 requires it) +username:${EWS_USERNAME} +password:${EWS_PASSWORD} +auth_type:${EWS_AUTH_TYPE:-"NTLM"} +smtp_address:${EWS_SMTP_ADDRESS} +folder_name:${EWS_FOLDER_NAME:-"TheHive"} + +[QRadar] +#ip or domain to QRadar +server:${QRADAR_SERVER} +auth_token:${QRADAR_AUTH_TOKEN} +cert_filepath:${QRADAR_CERT_FILEPATH:-"/opt/synapse/qradar.crt"} +api_version:${QRADAR_API_VERSION:"0.8"} + +EOF + +echo "${0##*/} || Change permission for configuration file..." && chmod 644 "$CONFIG_FILE" +echo "${0##*/} || Fix permissions in ${myWORKDIR}..." && chown -r abc. ${myWORKDIR} diff --git a/.docker/s6/run b/.docker/s6/run new file mode 100755 index 0000000..95f0153 --- /dev/null +++ b/.docker/s6/run @@ -0,0 +1,4 @@ +#!/usr/bin/with-contenv bash + +exec s6-setuidgid abc \ + ${myWORKDIR}/venv/bin/python ${myWORKDIR}/app.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..14211aa --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +LICENSE +README.md +.gitignore +.github +.git +make.sh +Makefile +docs +example* +Dockerfile +.dockerignore \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..583decf --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + # Maintain dependencies for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" \ No newline at end of file diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..66d80bd --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,10 @@ +`````release_notes +## Whats new +- ... + +## Which Bugfixes +- ... + +## Whats removed +- ... +```` \ No newline at end of file diff --git a/.github/workflows/dockerfile_lint.yml b/.github/workflows/dockerfile_lint.yml new file mode 100644 index 0000000..0f059aa --- /dev/null +++ b/.github/workflows/dockerfile_lint.yml @@ -0,0 +1,15 @@ +# https://github.com/marketplace/actions/docker-lint +name: Dockerfile Lint +on: [push] +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@master + - name: lint + uses: luke142367/Docker-Lint-Action@v1.1.1 + with: + target: ./Dockerfile + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/git_help.yml b/.github/workflows/git_help.yml new file mode 100644 index 0000000..1e10161 --- /dev/null +++ b/.github/workflows/git_help.yml @@ -0,0 +1,27 @@ +name: Git - Mark Issue with Help Wanted - actions-ecosystem + +on: + issues: + types: + - opened + - edited + - reopened + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - uses: actions-ecosystem/action-regex-match@v2 + id: regex-match + with: + text: ${{ github.event.issue.title }} + regex: "help|not work" + flags: 'gi' + + - uses: actions-ecosystem/action-add-labels@v1 + if: ${{ steps.regex-match.outputs.match != '' }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + labels: 'help wanted' \ No newline at end of file diff --git a/.github/workflows/git_lint_pull_request.yml b/.github/workflows/git_lint_pull_request.yml new file mode 100644 index 0000000..6cc362a --- /dev/null +++ b/.github/workflows/git_lint_pull_request.yml @@ -0,0 +1,40 @@ +name: Git - Lint Pull Request Title - actions-ecosystem + +on: + pull_request: + types: + - opened + - edited + - reopened + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - uses: actions-ecosystem/action-regex-match@v2 + id: regex-match + with: + text: ${{ github.event.pull_request.title }} + regex: '(?:add|update|fix)\([a-z]+\):\s.+' + + - uses: actions-ecosystem/action-create-comment@v1 + if: ${{ steps.regex-match.outputs.match == '' }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + body: | + :warning: The title of this PR is invalid. + + Please make the title match the regex `(?:add|update|fix)\([a-z]+\):\s.+`. + + e.g.) `add(cli): enable --verbose flag`, `fix(api): avoid unexpected error in handler` + + - uses: actions-ecosystem/action-add-labels@v1 + if: ${{ steps.regex-match.outputs.match == '' }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + labels: 'invalid/title' + + - run: exit 1 + if: ${{ steps.regex-match.outputs.match == '' }} \ No newline at end of file diff --git a/.github/workflows/git_release.yml b/.github/workflows/git_release.yml new file mode 100644 index 0000000..00c30a4 --- /dev/null +++ b/.github/workflows/git_release.yml @@ -0,0 +1,78 @@ +name: Git Create Release - actions-ecosystem + +on: + push: + branches: + - master + pull_request: + types: + - labeled + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - uses: actions-ecosystem/action-get-merged-pull-request@v1 + id: get-merged-pull-request + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions-ecosystem/action-release-label@v1 + id: release-label + if: ${{ steps.get-merged-pull-request.outputs.title != null }} + with: + labels: ${{ steps.get-merged-pull-request.outputs.labels }} + + - uses: actions-ecosystem/action-get-latest-tag@v1 + id: get-latest-tag + if: ${{ steps.release-label.outputs.level != null }} + with: + semver_only: true + + - uses: actions-ecosystem/action-bump-semver@v1 + id: bump-semver + if: ${{ steps.release-label.outputs.level != null }} + with: + current_version: ${{ steps.get-latest-tag.outputs.tag }} + level: ${{ steps.release-label.outputs.level }} + + - uses: actions-ecosystem/action-regex-match@v2 + id: regex-match + if: ${{ steps.bump-semver.outputs.new_version != null }} + with: + text: ${{ steps.get-merged-pull-request.outputs.body }} + regex: '```release_note([\s\S]*)```' + + - uses: actions-ecosystem/action-push-tag@v1 + if: ${{ steps.bump-semver.outputs.new_version != null }} + with: + tag: ${{ steps.bump-semver.outputs.new_version }} + message: "${{ steps.bump-semver.outputs.new_version }}: PR #${{ steps.get-merged-pull-request.outputs.number }} ${{ steps.get-merged-pull-request.outputs.title }}" + + - uses: actions/create-release@v1 + if: ${{ steps.release-label.outputs.level == 'major' || steps.release-label.outputs.level == 'minor' }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.bump-semver.outputs.new_version }} + release_name: ${{ steps.bump-semver.outputs.new_version }} + body: ${{ steps.regex-match.outputs.group1 }} + + - uses: actions-ecosystem/action-create-comment@v1 + if: ${{ steps.bump-semver.outputs.new_version != null }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + number: ${{ steps.get-merged-pull-request.outputs.number }} + body: | + The new version [${{ steps.bump-semver.outputs.new_version }}](https://github.com/${{ github.repository }}/releases/tag/${{ steps.bump-semver.outputs.new_version }}) has been released :tada: + + - uses: actions-ecosystem/action-create-comment@v1 + if: ${{ steps.bump-semver.outputs.new_version != null }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + body: | + This PR will update [${{ github.repository }}](https://github.com/${{ github.repository }}) from [${{ steps.get-latest-tag.outputs.tag }}](https://github.com/${{ github.repository }}/releases/tag/${{ steps.get-latest-tag.outputs.tag }}) to ${{ steps.bump-semver.outputs.new_version }} :rocket: + + If this update isn't as you expected, you may want to change or remove the *release label*. \ No newline at end of file diff --git a/.github/workflows/git_release_check.yml b/.github/workflows/git_release_check.yml new file mode 100644 index 0000000..251d800 --- /dev/null +++ b/.github/workflows/git_release_check.yml @@ -0,0 +1,37 @@ +name: Check Release + +on: + pull_request: + types: + - labeled + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - uses: actions-ecosystem/action-release-label@v1 + id: release-label + if: ${{ startsWith(github.event.label.name, 'release/') }} + + - uses: actions-ecosystem/action-get-latest-tag@v1 + id: get-latest-tag + if: ${{ steps.release-label.outputs.level != null }} + with: + semver_only: true + + - uses: actions-ecosystem/action-bump-semver@v1 + id: bump-semver + if: ${{ steps.release-label.outputs.level != null }} + with: + current_version: ${{ steps.get-latest-tag.outputs.tag }} + level: ${{ steps.release-label.outputs.level }} + + - uses: actions-ecosystem/action-create-comment@v1 + if: ${{ steps.bump-semver.outputs.new_version != null }} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + body: | + This PR will update [${{ github.repository }}](https://github.com/${{ github.repository }}) from [${{ steps.get-latest-tag.outputs.tag }}](https://github.com/${{ github.repository }}/releases/tag/${{ steps.get-latest-tag.outputs.tag }}) to ${{ steps.bump-semver.outputs.new_version }} :rocket: + If this update isn't as you expected, you may want to change or remove the *release label*. \ No newline at end of file diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml new file mode 100644 index 0000000..285d726 --- /dev/null +++ b/.github/workflows/reviewdog.yml @@ -0,0 +1,28 @@ +name: shellcheck / hadolint - reviewdog +# https://github.com/reviewdog/action-shellcheck +on: [pull_request] +jobs: + shellcheck: + #name: runner / shellcheck + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: shellcheck + uses: reviewdog/action-shellcheck@v1 + with: + github_token: ${{ secrets.github_token }} + reporter: github-pr-review # Change reporter. + path: "." # Optional. + pattern: "*.sh" # Optional. + exclude: "./.git/*" # Optional. + hadolint: + #name: runner / hadolint + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v2 + - name: hadolint + uses: reviewdog/action-hadolint@v1 + with: + github_token: ${{ secrets.github_token }} + reporter: github-pr-review # Default is github-pr-check \ No newline at end of file diff --git a/.github/workflows/sysdig_cis_benchmark.yml b/.github/workflows/sysdig_cis_benchmark.yml new file mode 100644 index 0000000..bace2a6 --- /dev/null +++ b/.github/workflows/sysdig_cis_benchmark.yml @@ -0,0 +1,15 @@ +name: Sysdig CIS Benchmarks +on: + pull_request: + # paths: + # - '.docker/**' +jobs: + run: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Sysdig CIS Dockerfile Benchmark + uses: sysdiglabs/benchmark-dockerfile@v1.0.0 + with: + directory: . \ No newline at end of file diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 0000000..4c4529e --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,24 @@ +name: package pip +on: + push: + branches: + - master + schedule: + - cron: '0 0 * * *' +jobs: + run: + name: Run + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - package-ecosystem: "pip" + # Look for `build.gradle` in the `root` directory + directory: "/" + # Check for updates once weekly + schedule: + interval: "weekly" + ignore: + # Ignore updates to packages that start 'aws' + # Wildcards match zero or more arbitrary characters + - dependency-name: "flask*" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..6532c29 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,49 @@ +FROM python:3.8 +ARG UID=40000 +ENV myWORKDIR /opt/synapse +# Add a work directory +WORKDIR ${myWORKDIR} +# Add user +RUN set -eu \ + ;adduser --home ${myWORKDIR} --no-create-home --uid ${UID} --disabled-password --disabled-login --shell /bin/sh abc -quiet \ + ;chown abc. ${myWORKDIR} \ + ; + +# Switch to non privileged user +USER abc + +# Copy the files from outside directory into the container image +COPY requirements.txt requirements.txt + +# Install python virtual environment +# VIRUTAL_ENV is required see https://pythonspeed.com/articles/activate-virtualenv-dockerfile/ +ENV VIRTUAL_ENV=${myWORKDIR}/venv +RUN set -eu \ + ;python3 -m venv ${VIRTUAL_ENV} \ + ; +# Set required environment variables +ENV PATH ${VIRTUAL_ENV}/bin:$PATH +# Install python dependencies into virtual environment +RUN set -eu \ + ;pip3 install --no-cache-dir -r requirements.txt \ + ; + +# Add S6 Overlay +USER root +ADD https://github.com/just-containers/s6-overlay/releases/latest/download/s6-overlay-amd64.tar.gz /tmp/ +RUN set -eu \ + ;tar xzf /tmp/s6-overlay-amd64.tar.gz -C / \ + ; + +#COPY s6/permissions /etc/fix-attrs.d/00-synapse-set-permissions +COPY .docker/s6/prepare /etc/cont-init.d/00-synapse-prepare +COPY .docker/s6/run /etc/services.d/synapse/run + +ENTRYPOINT ["/init"] +HEALTHCHECK --interval=60s --timeout=30s --start-period=60s --retries=3 CMD curl --fail http://127.0.0.1:5000/version || exit 1 + +# Expose the default port 5000 +EXPOSE 5000 + +# Copy the files from outside directory into the container image +COPY --chown=abc:abc . . diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0c41d7c --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ + + +# Add remote url for mainstream +add-remote-url: + git remote add base https://github.com/arnydo/Synapse +# Update from mainstream +update-from-origin: + git fetch base + git merge base/master +# Build the docker container +docker-build: + docker build -t synapse -f Dockerfile . +# DEV only +update-toc: + docker run -v $(shell pwd)":/app" -w /app --rm -it sebdah/markdown-toc README.md --skip-headers 1 --replace --inline diff --git a/README.md b/README.md index a401ff2..d66d51b 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,22 @@ Currently, Synapse supports the following alert sources: - Microsoft O365 - IBM QRadar + +# Table of Contents + +1. [Overview](#overview) +1. [Using Synapse](#using-synapse) +1. [Running in Docker](#running-in-docker) +1. [License](#license) +1. [Updates](#updates) +1. [Contributing](#contributing) +1. [Support](#support) +1. [Community Discussions](#community-discussions) +1. [Website](#website) +1. [Roadmap](#roadmap) +1. [Special Thanks](#special-thanks) + + # Overview Most of the time, transforming a security event or a notification about a suspicious email requires several actions and conditions. Synapse gathers those into workflows. @@ -31,6 +47,14 @@ The [user guide](docs/user_guide.md) should contain all the information you need While all operating systems running Python 3 can be used for Synapse, we recommend the use of Ubuntu. +# Running in Docker + + 1. Build Image: ```docker build -t synapse .``` + 2. Run Container: ```docker run -d --name synapse -p 5000:5000 synapse``` + + You can also mount the config file for easier adjustments + ```docker run -d --name synapse -v ${pwd}/conf/synapse.conf:/opt/synapse/conf/synapse.conf -p 5000:5000 synapse``` + # License Synapse is an open source and free software released under the [AGPL](https://github.com/TheHive-Project/TheHive/blob/master/LICENSE) (Affero General Public License). @@ -59,7 +83,7 @@ We have set up a Google forum at =3.2 defusedxml==0.5.0 dnspython==1.15.0 exchangelib==1.12.0 @@ -14,9 +14,9 @@ future==0.16.0 idna==2.7 isodate==0.6.0 itsdangerous==0.24 -jinja2==2.10 -lxml==4.2.5 -markupsafe==1.0 +Jinja2>=2.10.1 +lxml>=4.6.2 +markupsafe==1.1.1 ntlm-auth==1.2.0 pycparser==2.19 pygments==2.2.0 @@ -29,5 +29,5 @@ six==1.11.0 python-slugify==1.2.6 thehive4py==1.5.1 tzlocal==1.5.1 -urllib3==1.23 -werkzeug==0.14.1 +urllib3<1.25,>=1.21.1 #is required for request 2.20 +werkzeug>=0.15.3