Skip to content

Sinker is a Python tool to automate the execution of dockerized container scanning security tools merging their findings into one report.

License

Notifications You must be signed in to change notification settings

mmartins000/sinker

Repository files navigation

Sinker 🐙

Sinker is a Python tool to automate:

  • execution of dockerized container scanning tools;
  • merge of multiple reports;
  • post-execution tasks.

Why?

  • Running these tools manually can be boring and time-consuming when there are multiple images and deployments
  • Parsing their reports manually to get a unified view of the findings is challenging
  • Which container scanning tool (if only one) should you select for a given project?

Target audience

  • Users looking to automate container scanning tools and post-execution tasks
  • Users looking to benchmark container scanning tools

Pre-requisites

  • Linux or mac OS (tested with mac OS 10.15.7)
  • Python 3 (tested with version 3.10.4)
  • Docker Engine (tested with version 20.10.12)
  • Docker module for Python (tested with version 5.0.3)

To install Python pre-requisites:

$ pip install -r requirements.txt

Container Security Tools

The tools automated here don't have the same features. To learn more, check their websites.

Tested Versions

  • Syft v0.40.1
  • Grype v0.34.7
  • Trivy v0.25.3
  • Snyk v1.883.0 (standalone)

Execution

  1. Clone this repo (git clone https://github.com/mmartins000/sinker.git)
  2. Run python3 core/sinker.py -h to learn the options
  3. Compare the results of the tools.

To build and run a Docker image, check the last section of this document.

Under the Hood

Sinker will:

  1. Download Docker images for the scanners and the targets
  2. Run scanners against targets
  3. Parse the reports generated by the scanners
  4. Write a JSON file with the execution summary and findings
  5. Run enabled integrations (if any)
  6. Clean up (depending on selected options)

Configuration

Check and edit the default config file sinker.json or create your own.

Your own targets

You can replace file targets.json for a file that contains a list images to assess.

Example of file targets.json (to change to another filename, change the configuration in sinker.json):

{
  "images": [
    "alpine:3.12.1"
  ]
}

Another example, with a list of images:

{
  "images": [
    "alpine:3.12.1",
    "alpine:3.15",
    "postgres:14.2",
    "python"
  ]
}

The flag --targets can also be used. Options are:

  • A JSON file, like targets.json
  • A directory, with YAML files (to assess images in Kubernetes or docker-compose files)
  • A single YAML file

Integrations

Sinker can create Jira issues for the findings. If it finds a vulnerability in a public image, it will only create on issue for the whole image, because it assumes you don't own it and won't fix the vulnerabilities yourself. If it finds vulnerabilities for a private image, it will create one issue for each vulnerability. Filters will determine the findings in the report and sent to integrated tools. Check the last section for details.

Credentials

If you plan to use Snyk or Jira, don't forget to configure the credentials.

  • For Snyk, SNYK_TOKEN value in your account.
  • For Jira, username/password, token or cookie.

Output

Help menu:

$ python3 sinker/core.py -h
usage: core.py [-h] [--version] [--config CONFIG] [-v] [-i] [--skip-syft] [-g] [-t] [-s] [--force-docker-pull FORCEDOCKERPULL] [-o OUTPUT] [--targets TARGETS]
               [--no-update] [--only-updates] [--fresh-start] [--only-cleanup] [--only-process-json PROCESSJSON]
               [--fail-on-critical | --fail-on-high | --fail-on-medium | --fail-on-low]

options:
  -h, --help            show this help message and exit
  --version             Print current version and exit
  --config <filename>   Config file
  -v, --verbose         Verbose mode
  -i, --ignore-root     Ignore being executed as root
  --skip-syft           Skip Syft execution
  -g, --skip-grype      Skip Grype execution
  -t, --skip-trivy      Skip Trivy execution
  -s, --skip-snyk       Skip Snyk execution
  --force-docker-pull [ always | missing | never ]
                        Configure when Docker should pull the image. Default: missing
  -o <OUTPUT_FOLDER>, --output <OUTPUT_FOLDER>
                        Override output_folder parameter in config file
  --targets TARGETS     Override targets file parameter in config file
  --no-update           Do not update vulnerability DBs
  --only-updates        Update vulnerability DBs and exit
  --fresh-start         Erase images and vulnerability DBs
  --only-cleanup        Execute a clean up and exit
  --only-process-json <Sinker JSON filename>
                        Skip scanners and process a previously generated JSON
  --fail-on-critical    Exit with failed signal if critical severity vulnerabilities are found
  --fail-on-high        Exit with failed signal if high severity vulnerabilities are found
  --fail-on-medium      Exit with failed signal if medium severity vulnerabilities are found
  --fail-on-low         Exit with failed signal if low severity vulnerabilities are found

Sample execution with image 'alpine:3.12.1' and Grype, Trivy and Snyk:

$ python3 ./sinker/core.py -v --config /tmp/sinker/sinker.json --targets alpine:3.12.1
Sinker v0.1.1

Summary: Run Grype, Trivy, Snyk in alpine:3.12.1
Docker image alpine:3.12.1 found and will not be downloaded.
Docker image anchore/syft:latest found and will not be downloaded.
Docker image anchore/grype:latest found and will not be downloaded.
Docker image snyk/snyk:docker found and will not be downloaded.
Docker image aquasec/trivy:latest found and will not be downloaded.
Updating vulnerability database for Trivy...
Grype vulnerability database is already up-to-date.
Starting container image scans.
Scanning target alpine:3.12.1.
Running Syft on alpine:3.12.1...
Docker ran Syft container in alpine:3.12.1, it took 1.6 seconds and the report was saved in /tmp/sinker/alpine_3.12.1-sbom_syft_spdx.json.
Running Snyk on alpine:3.12.1...
Docker ran Snyk container in alpine:3.12.1, it took 6.48 seconds and the report was saved in /tmp/sinker/alpine_3.12.1-results_snyk.json.
Running Grype on alpine:3.12.1...
Docker ran Grype container in alpine:3.12.1, it took 3.56 seconds and the report was saved in /tmp/sinker/alpine_3.12.1-results_grype.json.
Running Trivy on alpine:3.12.1...
Docker ran Trivy container in alpine:3.12.1, it took 1.21 seconds and the report was saved in /tmp/sinker/alpine_3.12.1-results_trivy.json.
Finished scanning container image alpine:3.12.1.
Finished scanning all targets.
Sinker JSON saved to /tmp/sinker/sinker_results.json
Done.

Sample JSON output of command $ python3 ./sinker/core.py -v --config /tmp/sinker/sinker.json --targets alpine:3.12.1:

{
    "sinker": {
        "script_version": "0.1.1",
        "json_schema_version": "1",
        "url": "https://github.com/mmartins000/sinker",
        "command_line_args": null,
        "docker_version": null,
        "start_time": "2022-04-08 03:22:49",
        "end_time": "2022-04-08 03:23:27",
        "scanners_count": 3,
        "targets_count": 1,
        "duration_seconds": 38,
        "extended_duration": "38 seconds"
    },
    "reporting": {
        "alpine:3.12.1": {
            "summary": {
                "findings": 49,
                "findings_by_scanner": {
                    "grype": 49,
                    "trivy": 47,
                    "snyk": 47
                },
                "findings_by_severity": {
                    "critical": 3,
                    "high": 30,
                    "medium": 12,
                    "low": 4,
                    "negligible": 0,
                    "unknown": 0
                },
                "unanimous_findings": 47,
                "disputed_findings": 2
            },
            (...)

Sample table output of command $ python3 ./sinker/core.py -v --config /tmp/sinker/sinker.json --targets alpine:3.12.1:

+---------------+--------------+-----------+----------------+----------+------------+---------------+
|  Target Image |   Artifact   |  Upstream |       ID       | Severity |  Version   | Fixed Version |
+---------------+--------------+-----------+----------------+----------+------------+---------------+
| alpine:3.12.1 |  apk-tools   | apk-tools | CVE-2021-36159 | critical | 2.10.5-r1  |   2.10.7-r0   |
| alpine:3.12.1 | libcrypto1.1 |  openssl  | CVE-2021-3711  | critical | 1.1.1g-r0  |   1.1.1l-r0   |
| alpine:3.12.1 |  libssl1.1   |  openssl  | CVE-2021-3711  | critical | 1.1.1g-r0  |   1.1.1l-r0   |
| alpine:3.12.1 |  apk-tools   | apk-tools | CVE-2021-30139 |   high   | 2.10.5-r1  |   2.10.6-r0   |
(...)

Filtering the results

The results can be filtered using a JSON filter file, specified in the JSON config file. This filter file is a list of dict objects. The following filter will remove from the results all findings that match severity == "high" and below:

[
  {
    "severity": "high"
  }
]

The following filter contains two entries: one just like the above, and the next will remove all findings that match severity == "medium" and below AND "artifact" == "apk-tools"

[
  {
    "severity": "high"
  },
  {
    "severity": "medium",
    "artifact": "apk-tools",
  },
]

In the example above, if a finding matches one of the filter entries (OR condition) it will be removed from the report (JSON and text table, and later on, from the integrations).

The available fields are:

"id"
"description"
"artifact"
"upstream"
"severity"
"installed_version"
"fixed_version"
"cvss_v2score"
"cvss_v2vector"
"cvss_v3score"
"cvss_v3vector"
"datasource"
"datasource_nvd"
"datasource_mitre"
"found_by"

Building the container image

Sinker can be executed from a Docker container.

To build the image on your computer:

$ docker image build --rm --tag 'sinker:latest' .

To run it using the same example as shown in previous sections:

$ docker run --rm -v '/var/run/docker.sock:/var/run/docker.sock' -v '/tmp:/tmp' sinker:latest --ignore-root -v --config /tmp/sinker/sinker.json --targets alpine:3.12.1

About

Sinker is a Python tool to automate the execution of dockerized container scanning security tools merging their findings into one report.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published