-
Notifications
You must be signed in to change notification settings - Fork 0
/
scan.sh
executable file
·133 lines (99 loc) · 4.65 KB
/
scan.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/bin/bash -e
# Tool to generate an ACS scan of container images needed for any particular operator/version
# Requires a running ACS system.
OC_MIRROR="${OC_MIRROR:-oc-mirror}"
OCP_VERSION="${OCP_VERSION:-4.12}"
OPERATOR_CATALOG="${OPERATOR_CATALOG:-registry.redhat.io/redhat/redhat-operator-index}"
OPERATOR="${OPERATOR:-compliance-operator}"
# No default channel or version is set here because these are different for some operators
# Must be set by the user
#OPERATOR_CHANNEL=""
#OPERATOR_VERSION=""
# Example endpoint
#ROX_ENDPOINT="https://central-rhacs-operator.apps.cluster_name.basedomain.io:443"
#ROX_PASSWD=""
# Default CVSS min score. Set higher to limit findings
cvss="${cvss:-7}"
UNPACK="${UNPACK:-true}"
SCAN="${SCAN:-true}"
PARSE="${PARSE:-true}"
echo "Settings:"
echo "Operator: ${OPERATOR}"
echo "Operator Channel: ${OPERATOR_CHANNEL}"
echo "Operator Version: ${OPERATOR_VERSION}"
echo "ROX_ENDPOINT: ${ROX_ENDPOINT}"
echo "ROX_PASSWD: ${ROX_PASSWD}"
if [ -z ${OPERATOR} ];
then
echo "Operator name is required, set OPERATOR env variable"
exit 1
fi
if [ -z ${ROX_ENDPOINT} ];
then
echo "ROX_ENDPOINT is required, set ROX_ENDPOINT env variable"
exit 1
fi
if [ -z ${ROX_PASSWD} ];
then
echo "ROX_PASSWD is required, set ROX_PASSWD env variable"
exit 1
fi
if [[ $UNPACK == true ]]
then
# Lookup main operator channel if not specified by user
if [ -z ${OPERATOR_CHANNEL} ];
then
echo "Operator channel not specified, selecting primary channel"
${OC_MIRROR} list operators --catalog=${OPERATOR_CATALOG}:v${OCP_VERSION} --package=${OPERATOR}
OPERATOR_CHANNEL=$(${OC_MIRROR} list operators --catalog=${OPERATOR_CATALOG}:v${OCP_VERSION} \
--package=${OPERATOR} 2>/dev/null | grep -A 1 'DEFAULT CHANNEL' | tail -1 | awk -F\ '{print $NF}')
fi
# Lookup latest operator version in channel if not specified by user
if [ -z ${OPERATOR_VERSION} ];
then
echo "Operator version not specified, selecting head for channel: ${OPERATOR_CHANNEL}"
OPERATOR_VERSION=$(${OC_MIRROR} list operators --catalog=${OPERATOR_CATALOG}:v${OCP_VERSION} \
--package=${OPERATOR} --channel=${OPERATOR_CHANNEL} 2>/dev/null | grep -A 1 'VERSIONS' | tail -1)
fi
# Create oc mirror config file to get manifests for operator version
rm -f imageset-config.yaml
sed "s|TMP_DIR|${TMP_DIR}|g" imageset-config.yaml.template | sed "s|OCP_VERSION|${OCP_VERSION}|g" | \
sed "s|operator-name|${OPERATOR}|g" | sed "s|channel-name|${OPERATOR_CHANNEL}|g" | \
sed "s|operator-version|${OPERATOR_VERSION}|g" > imageset-config.yaml
# Get manifests for operator version
export DIR="${OPERATOR}-${OPERATOR_CHANNEL}-${OPERATOR_VERSION}"
rm -rf "${DIR}"
oc-mirror --config ./imageset-config.yaml --dry-run "file://${DIR}"
fi
export DIR="${OPERATOR}-${OPERATOR_CHANNEL}-${OPERATOR_VERSION}"
if [[ $SCAN == true ]]
then
# Request ACS to generate a scan of each image that is part of the operator bundle
for image in $(cat "${DIR}/oc-mirror-workspace/mapping.txt" | awk -F\= '{print $1}')
do
echo "Scanning image: ${image}"
FILENAME=$(echo "${image}" | sed 's|/|_|g')
FILENAME="${DIR}/${FILENAME}_scan.json"
roxctl image scan --insecure --insecure-skip-tls-verify \
--endpoint "${ROX_ENDPOINT}" --password "${ROX_PASSWD}" \
--force --include-snoozed \
--image "${image}" | tee "${FILENAME}"
done
fi
if [[ $PARSE == true ]]
then
# Extract CVE information from ACS scan results for each image and combine into CSV format
output_file="${DIR}/${OPERATOR}-${OPERATOR_VERSION}-scan.csv"
# Column Names
echo '"Image", "CVE", "CVSS Score", "Severity", "Component", "Version", "Fixed By"' > "${output_file}"
for f in ${DIR}/*@*.json
do
image_name="$(jq -rc '.name.fullName' ${f})"
export image_name
fname=$(jq -rc '.name.remote' ${f} | sed 's|/|_|g')
jq -r --argjson cvss "$cvss" 'try (.metadata.v1.layers as $layers | .scan.components | sort_by(.layerIndex, .name) | .[]? | . as $component | select(.vulns != null) | .vulns[] | select((.cvss >= $cvss) and .severity != "LOW_VULNERABILITY_SEVERITY") | select(.fixedBy != null) | [ env.image_name, .cve, .cvss, .severity, $component.name, $component.version, .fixedBy]) | @csv' ${f} >> "${output_file}"
# Uncomment to save individual image parsing metadata files
#jq -r --argjson cvss "$cvss" 'try (.metadata.v1.layers as $layers | .scan.components | sort_by(.layerIndex, .name) | .[]? | . as $component | select(.vulns != null) | .vulns[] | select(.cvss >= $cvss) | select(.fixedBy != null) | [ env.image_name, .cve, .cvss, .severity, $component.name, $component.version, .fixedBy]) | @csv' ${f} > "${DIR}/${fname}_scan.json"
done
fi
exit 0