Skip to content

Commit 34505ef

Browse files
authored
feat: add "assess_image" command (#47)
The command scans Docker image for vulnerabilities and secrets. Under the hood uses Grype for the vulnerability scan and Trivy for the secret scan. Sources image from the Docker daemon of the tarball file from disk.
1 parent e19d50e commit 34505ef

File tree

4 files changed

+187
-5
lines changed

4 files changed

+187
-5
lines changed

.circleci/test-deploy.yml

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,19 @@ jobs:
4848
- checkout
4949
- security/scan_dockerfile:
5050
dockerfile_dir: ./sample
51-
generate_sbom:
51+
generate_sbom_and_assess_image:
5252
machine:
5353
image: ubuntu-2204:current
5454
steps:
5555
- checkout
56+
- security/install_grype
57+
- security/install_syft
58+
- security/install_trivy
5659
- docker/build:
5760
image: security-sample
5861
tag: v1
5962
path: ./sample
6063
docker-context: ./sample
61-
- security/install_syft
6264
- security/generate_sbom:
6365
image: docker.io/security-sample:v1
6466
out_path: /tmp/sample-sbom.json
@@ -69,8 +71,22 @@ jobs:
6971
echo "SBOM output not found"
7072
exit 1
7173
fi
72-
74+
- security/assess_image:
75+
image: docker.io/security-sample:v1
76+
severity: critical
77+
report_path: /tmp/sample-vuln-report.json
78+
- run:
79+
name: Check vulnerability report
80+
command: |
81+
if [ ! -f "/tmp/sample-vuln-report.json" ]; then
82+
echo "Vulnerability report not found"
83+
exit 1
84+
fi
85+
- run:
86+
name: Cleanup
87+
command: |
7388
rm -f /tmp/sample-sbom.json
89+
rm -f /tmp/sample-vuln-report.json
7490
install_trivy:
7591
executor: core/node
7692
steps:
@@ -119,7 +135,7 @@ workflows:
119135
filters: *filters
120136
- scan_dockerfile:
121137
filters: *filters
122-
- generate_sbom:
138+
- generate_sbom_and_assess_image:
123139
filters: *filters
124140
- security/detect_secrets_dir:
125141
name: detect_secrets_dir
@@ -167,7 +183,7 @@ workflows:
167183
- scan_dependencies_prod_pnpm
168184
- scan_dependencies_command
169185
- scan_dockerfile
170-
- generate_sbom
186+
- generate_sbom_and_assess_image
171187
- detect_secrets_dir
172188
- detect_secrets_git_base_revision
173189
- analyze_code_diff

src/commands/assess_image.yml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
description: >
2+
Scan Docker images for vulnerabilities and secrets.
3+
Vulnerability scan is performed by Grype (https://github.com/anchore/grype)
4+
while scanning for secrets is executed by Trivy (https://github.com/aquasecurity/trivy).
5+
It is possible to provide additional configurable options by following the Grype
6+
(https://github.com/anchore/grype?tab=readme-ov-file#configuration) and Trivy
7+
(https://trivy.dev/latest/docs/configuration/) guides, respectively.
8+
However, some options cannot be overridden, such as source and format,
9+
since they are passed as command line arguments and thus have the highest precedence.
10+
11+
parameters:
12+
image:
13+
type: string
14+
description: >
15+
The Docker image to scan. Support following schemes
16+
(1) 'repo-name/image-name:tag' (2) '/path/to/image.tar'. Bases on provided scheme
17+
it will either use local Docker daemon or tarball archive from disk as a source.
18+
scanners:
19+
type: string
20+
default: vuln secret
21+
description: >
22+
Space delimited list of scans to run against the image. By default, runs all
23+
available scans. Following is available (1) 'vuln' - vulnerability scan
24+
(2) 'secret' - secrets scan of the image and its configuration.
25+
severity:
26+
type: enum
27+
enum:
28+
- low
29+
- medium
30+
- high
31+
- critical
32+
default: high
33+
description: >
34+
Choose a severity level to fail on with the error code. By default,
35+
when severity level of 'high' or greater is detected the command will
36+
fail with exit code 2.
37+
exclude:
38+
type: string
39+
default: ""
40+
description: >
41+
Space delimited list of GLOB expressions specifying files and paths to
42+
exclude from the vulnerability scan. The secrets scan is not affected by this.
43+
ignore_fix_status:
44+
type: string
45+
default: ""
46+
description: >
47+
Comma delimited list of matches to ignore based on the vulnerability fix status.
48+
Available options - 'fixed', 'not-fixed', 'wont-fix', 'unknown'.
49+
report_format:
50+
type: enum
51+
enum:
52+
- cyclonedx-json
53+
- json
54+
default: cyclonedx-json
55+
description: >
56+
Choose the format of the vulnerability report. By default, a JSON format
57+
conforming ot the CycloneDX specification.
58+
report_path:
59+
type: string
60+
default: /tmp/vuln-report.json
61+
description: Path to the file to write the vulnerability report to.
62+
63+
steps:
64+
- run:
65+
name: Assess image "<<parameters.image>>"
66+
environment:
67+
PARAM_STR_IMAGE: <<parameters.image>>
68+
PARAM_STR_SCANNERS: <<parameters.scanners>>
69+
PARAM_ENUM_SEVERITY: <<parameters.severity>>
70+
PARAM_STR_IGNORE_FIX_STATUS: <<parameters.ignore_fix_status>>
71+
PARAM_ENUM_REPORT_FORMAT: <<parameters.report_format>>
72+
PARAM_STR_REPORT_PATH: <<parameters.report_path>>
73+
command: <<include(scripts/assess-image.sh)>>

src/examples/image_scan.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
description: |
2+
By default, the "assess_image" command scans images for high and critical
3+
severity vulnerabilities and secrets. It uses the Docker daemon as the
4+
image source, or alternatively an image tarball file from disk if provided.
5+
There is an option to choose scanners, set severity levels, ignore findings
6+
based on fix status, exclude directories or files using the glob expressions,
7+
select different report format, and customize report path.
8+
9+
usage:
10+
version: 2.1
11+
orbs:
12+
security: studion/security@x.y.z
13+
jobs:
14+
vuln-and-secrets:
15+
machine:
16+
image: ubuntu-2204:current
17+
steps:
18+
- checkout
19+
- security/assess_image:
20+
image: studiondev/node-security:lts
21+
severity: medium
22+
ignore-fix-status: not-fixed,wont-fix
23+
exclude: /usr /var/**/*.log
24+
report-path: /tmp/reports/lts-vuln.json
25+
workflows:
26+
scan-image:
27+
jobs:
28+
- vuln-and-secrets

src/scripts/assess-image.sh

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/bin/bash
2+
3+
if [[ -z "${PARAM_STR_IMAGE}" ]]; then
4+
echo "Specify image and retry."
5+
6+
exit 1
7+
fi
8+
9+
10+
function scan_secrets () {
11+
local args=(image "--scanners=secret" "--image-config-scanners=secret")
12+
13+
if [[ "${PARAM_STR_IMAGE}" == *.tar ]]; then
14+
args+=(--input)
15+
fi
16+
17+
args+=("${PARAM_STR_IMAGE}")
18+
19+
set -x
20+
trivy "${args[@]}"
21+
set +x
22+
}
23+
24+
function scan_vuln () {
25+
local args=()
26+
27+
if [[ "${PARAM_STR_IMAGE}" == *.tar ]]; then
28+
args+=("docker-archive:${PARAM_STR_IMAGE}")
29+
else
30+
args+=("docker:${PARAM_STR_IMAGE}")
31+
fi
32+
33+
if [[ -n "${PARAM_STR_IGNORE_FIX_STATUS}" ]]; then
34+
args+=("--ignore-states=${PARAM_STR_IGNORE_FIX_STATUS}")
35+
fi
36+
37+
if [[ -n "${PARAM_STR_EXCLUDE}" ]]; then
38+
set -f # Disable glob expansion
39+
for exclude_glob in ${PARAM_STR_EXCLUDE}; do
40+
args+=("--exclude=$exclude_glob")
41+
done
42+
set +f
43+
fi
44+
45+
args+=(--by-cve "--fail-on=${PARAM_ENUM_SEVERITY}")
46+
args+=("--output=${PARAM_ENUM_REPORT_FORMAT}")
47+
args+=("--file=${PARAM_STR_REPORT_PATH}")
48+
49+
set -x
50+
grype "${args[@]}"
51+
set +x
52+
}
53+
54+
set -f # Disable glob expansion
55+
for scanner in ${PARAM_STR_SCANNERS}; do
56+
if [[ $scanner == "vuln" ]]; then
57+
scan_vuln
58+
elif [[ $scanner == "secret" ]]; then
59+
scan_secrets
60+
else
61+
echo "Unknow image scanner: $scanner"
62+
exit 1
63+
fi
64+
done
65+
set +f

0 commit comments

Comments
 (0)