github.com/verrazzano/verrazzano@v1.7.0/release/scripts/scan_bom_images.sh (about) 1 #!/usr/bin/env bash 2 # 3 # Copyright (c) 2021, 2023, Oracle and/or its affiliates. 4 # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 5 # 6 # Scan images in a specified BOM 7 8 SCRIPT_DIR=$(cd $(dirname "$0"); pwd -P) 9 TOOL_SCRIPT_DIR=${SCRIPT_DIR}/../../tools/scripts 10 11 . $SCRIPT_DIR/common.sh 12 13 ALLOW_LIST= 14 BOM_FILE= 15 REGISTRY= 16 REPO_PATH= 17 OUTPUT_DIR= 18 OCIR_NAMESPACE= 19 20 # The COMBINED_PATH is formed based on whether there is an OCIR tenancy namespace or not: 21 # $REGISTRY/$REPO_PATH 22 # $REGISTRY/$OCIR_NAMESPACE/$REPO_PATH 23 COMBINED_PATH= 24 25 function usage() { 26 ec=${1:-0} 27 if [ ! -z "$2" ]; then 28 echo "$2" 29 fi 30 31 cat << EOM 32 Scan images in specified BOM 33 34 Usage: 35 $(basename $0) -b bom-file -r results-directory [-a allow-list] 36 37 Options: 38 -b <bom-file> BOM file to use for determining images to scan (required) 39 -o <output-directory> Directory to store scan result files (required) 40 -r <docker-registry> Docker registry to find images in (required) 41 -n <ocir-namespace> OCIR namespace. This is required if the registry is an OCIR registry, and is not needed otherwise (optional) 42 -p <repository-path> Repository name/prefix for each image, e.g \"path/to/my/image\"; not including an OCIR namespace if one is required, if not specified the default will be used according to the BOM 43 -x <ocir-repo-path> This is the OCIR namespace plus the repository path as well (basically -n and -p combined). 44 -a <allow-list> Allow-list to use for scanning (optional) 45 46 One of the path options must be specified: -x or -p 47 48 Pre-requisites: 49 This requires that trivy and grype scanners are installed 50 51 Example: 52 $(basename $0) -b verrazzano-bom.json -t ghcr.io -p my/repo/path -o scan-results 53 $(basename $0) -b verrazzano-bom.json -t phx.ocir.io -n tenancynamespace -p my/repo/path -o scan-results 54 EOM 55 exit ${ec} 56 } 57 58 # This will get the scan summaries and details for all of the repositories 59 # 60 # It will also verify that all repositories found have scan results as well 61 # 62 # $1 Scan BOM file 63 function scan_images_in_bom() { 64 # Get a list of the images in the BOM based on the specified registry and repo path, but trim the paths 65 # off in the file so we are left with them in the form image:tag 66 local bomimages=$(mktemp temp-bom-images-XXXXXX.out) 67 sh $TOOL_SCRIPT_DIR/vz-registry-image-helper.sh -m $bomimages -t $REGISTRY -r $COMBINED_PATH -b $BOM_FILE 68 cat $bomimages 69 echo "$REGISTRY/$COMBINED_PATH" 70 sed -i "s;$REGISTRY/$COMBINED_PATH/;;g" $bomimages 71 72 cat $bomimages 73 74 # Scan each image listed in the BOM 75 while read BOM_IMAGE; do 76 RESULT_REPOSITORY_IMAGE=$(echo "${BOM_IMAGE}" | sed 's;/;_;g') 77 RESULT_FILE_PREFIX=$(echo "${OUTPUT_DIR}/${RESULT_REPOSITORY_IMAGE}") 78 SCAN_IMAGE=$(echo "${REGISTRY}/${COMBINED_PATH}/${BOM_IMAGE}") 79 80 # FIXME: Add allowlist support 81 82 echo "performing trivy scan for $SCAN_IMAGE" 83 trivy image -f json -o ${RESULT_FILE_PREFIX}-trivy-details.json ${SCAN_IMAGE} 2> ${RESULT_FILE_PREFIX}-trivy.err || echo "trivy scan failed for $SCAN_IMAGE" 84 # Check if any Results section was included or not, only convert to CSV if there are Results there 85 results_size=$(cat ${RESULT_FILE_PREFIX}-trivy-details.json | jq '.Results' | wc -l) 86 if [[ results_size -gt 1 ]]; then 87 cat ${RESULT_FILE_PREFIX}-trivy-details.json | jq -r '.Results[]' | sed 's/null//g' | jq -r '.Vulnerabilities' | sed 's/null//g' | jq -r ' .[] | { sev: .Severity, cve: ."VulnerabilityID", description: .Description } ' | sed 's/\\[nt]/ /g' | jq -r '[.[]] | @csv' | sort -u > ${RESULT_FILE_PREFIX}-trivy-details.csv 88 else 89 echo "No Results section found in ${RESULT_FILE_PREFIX}-trivy-details.json, so no need to generate CSV for it" 90 fi 91 92 echo "performing grype scan for $BOM_IMAGE" 93 grype ${SCAN_IMAGE} -o json > ${RESULT_FILE_PREFIX}-grype-details.json 2> ${RESULT_FILE_PREFIX}-grype.err || echo "grype scan failed for $SCAN_IMAGE" 94 cat ${RESULT_FILE_PREFIX}-grype-details.json | jq -r '.matches[] | { sev: .vulnerability.severity, cve: .vulnerability.id, description: .vulnerability.description } ' | sed 's/\\[nt]/ /g' | jq -r '[.[]] | @csv' | sort -u > ${RESULT_FILE_PREFIX}-grype-details.csv 95 done <$bomimages 96 rm $bomimages 97 } 98 99 function validate_inputs() { 100 if [ -z "$BOM_FILE" ] || [ ! -f "$BOM_FILE" ]; then 101 usage 1 "A valid BOM file is required to be specified" 102 fi 103 104 if [ -z "$OUTPUT_DIR" ]; then 105 usage 1 "A valid scan results directory is required to be specified" 106 else 107 if [ ! -d "$OUTPUT_DIR" ]; then 108 mkdir -p $OUTPUT_DIR || usage 1 "Failed creating $OUTPUT_DIR. A valid scan results directory location is required to be specified" 109 fi 110 fi 111 112 if [ -z "$REGISTRY" ]; then 113 usage 1 "The registry must be specified" 114 fi 115 116 if [ -z "$REPO_PATH" ]; then 117 usage 1 "The repository path must be specified" 118 fi 119 120 # If we already have a combined path, we were give -x with a namespace and path already 121 # If not, then we check if they gave us -p or -n and -p 122 if [ -z "$COMBINED_PATH" ]; then 123 if [ -z "$OCIR_NAMESPACE" ]; then 124 COMBINED_PATH="$REPO_PATH" 125 else 126 COMBINED_PATH="$OCIR_NAMESPACE/$REPO_PATH" 127 fi 128 fi 129 } 130 131 function verify_prerequisites() { 132 command -v trivy >/dev/null 2>&1 || { 133 usage 1 "trivy scanner is not installed" 134 } 135 command -v grype >/dev/null 2>&1 || { 136 usage 1 "grype scanner is not installed" 137 } 138 echo "Grype installation directory: $(which grype)" 139 echo "Trivy installation directory: $(which trivy)" 140 } 141 142 while getopts 'hb:a:o:n:r:p:x:' opt; do 143 case $opt in 144 a) 145 ALLOW_LIST=$OPTARG 146 ;; 147 b) 148 BOM_FILE=$OPTARG 149 ;; 150 n) 151 OCIR_NAMESPACE=$OPTARG 152 ;; 153 o) 154 OUTPUT_DIR=$OPTARG 155 ;; 156 r) 157 REGISTRY=$OPTARG 158 ;; 159 p) 160 REPO_PATH=$OPTARG 161 ;; 162 x) 163 COMBINED_PATH=$OPTARG 164 REPO_PATH=$(echo $COMBINED_PATH | cut -d "/" -f2-) 165 ;; 166 h | ?) 167 usage 168 ;; 169 esac 170 done 171 172 validate_inputs 173 verify_prerequisites 174 scan_images_in_bom || exit 1