From fe88be9282a51b009ffd0e89e39d3ebac9c4a196 Mon Sep 17 00:00:00 2001 From: Marcelo Primo Date: Fri, 11 Aug 2023 14:09:59 -0300 Subject: [PATCH] feat: terragrunt trivy hook --- .pre-commit-hooks.yaml | 6 ++ hooks/trivy_terraform.sh | 38 ++++++++---- hooks/trivy_terragrunt.sh | 126 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+), 13 deletions(-) create mode 100755 hooks/trivy_terragrunt.sh diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml index 7bacdf1..7dac87c 100644 --- a/.pre-commit-hooks.yaml +++ b/.pre-commit-hooks.yaml @@ -4,3 +4,9 @@ require_serial: true entry: hooks/trivy_terraform.sh language: script +- id: terragrunt_trivy + name: Terraform validate with trivy + description: Static analysis of Terraform templates to spot potential security issues. + require_serial: true + entry: hooks/trivy_terragrunt.sh + language: script diff --git a/hooks/trivy_terraform.sh b/hooks/trivy_terraform.sh index 670eb95..f9311f5 100755 --- a/hooks/trivy_terraform.sh +++ b/hooks/trivy_terraform.sh @@ -11,22 +11,30 @@ BLUE='\033[0;34m' ENDCOLOR='\033[0m' # Validate Dependencies -if ! command -v trivy &> /dev/null && ! command -v docker &> /dev/null; then - echo -e "${RED}Error: Neither 'trivy' binary or 'docker' found!${ENDCOLOR}" - exit 1 -fi +function validate_dependencies() { + if ! command -v trivy &> /dev/null && ! command -v docker &> /dev/null; then + echo -e "${RED}Error: Neither 'trivy' binary or 'docker' found!${ENDCOLOR}" + exit 1 + fi +} # Parsing arguments function parse_args() { local -r args=("$@") + for arg in "${args[@]}"; do - if [[ -f $arg ]] || [[ -d $arg ]]; then - DIR="$DIR $(dirname "$arg")" + if [[ -f $arg || -d $arg ]]; then + DIR+=" $(realpath "$(dirname "$arg")")" else - ARGS="$ARGS $arg" + ARGS+=" $arg" fi done + + # Remove spaces in beginning of string + DIR=${DIR# } + ARGS=${ARGS# } + } # Scanning directories @@ -46,7 +54,8 @@ function trivy_scan() { fi - for dir in $DIR; do + for dir in $1; do + echo -e "\n---------------------------------------" echo "SCANNING -> $dir" echo -e "---------------------------------------\n" @@ -61,13 +70,16 @@ function trivy_scan() { fi - echo -e "\n${GREEN}NO PROBLEMS FOUND!!!${ENDCOLOR}" + echo -e "\n${GREEN}No Problems Found!!!${ENDCOLOR}" done } -parse_args "$@" +function main() { + validate_dependencies + parse_args "$@" + DIR=$(echo "$DIR" | tr ' ' '\n' | sort -u | tr '\n' ' ') -# Removing repeated elements -DIR=$(echo "$DIR" | tr ' ' '\n' | sort -u | tr '\n' ' ') + trivy_scan "$DIR" +} -trivy_scan +main "$@" diff --git a/hooks/trivy_terragrunt.sh b/hooks/trivy_terragrunt.sh new file mode 100755 index 0000000..23d264e --- /dev/null +++ b/hooks/trivy_terragrunt.sh @@ -0,0 +1,126 @@ +#!/bin/env bash +# +# shellcheck disable=SC2086 # allow to pass arguments as a string + +set -eo pipefail + +# color +RED='\033[0;31m' +GREEN='\033[0;32m' +BLUE='\033[0;34m' +ENDCOLOR='\033[0m' + +# files to control scanning +flag_filename=".verify-this" +trivy_ignorefile=".trivyignore" + +# Validate Dependencies +function validate_dependencies() { + if ! command -v trivy &> /dev/null && ! command -v docker &> /dev/null; then + echo -e "${RED}Error: Neither 'trivy' binary or 'docker' found!${ENDCOLOR}" + exit 1 + fi +} + +# Parsing arguments +function parse_args() { + local -r args=("$@") + + for arg in "${args[@]}"; do + + if [[ -f $arg || -d $arg ]]; then + DIR+=" $(realpath "$(dirname "$arg")")" + else + ARGS+=" $arg" + fi + done + + # Remove spaces in beginning of string + DIR=${DIR# } + ARGS=${ARGS# } +} + +function test_terragrunt_file() { + local dir="$1" + local flag_file="$dir/$flag_filename" + + if [[ -f "$flag_file" ]]; then + cd "$dir" + if terragrunt terragrunt-info &> /dev/null; then + return 0 + else + echo -e "${RED}Error: Check if you're logged in to the right account!${ENDCOLOR}" + exit 1 + fi + + else + return 1 + fi +} + +# Scanning directories +function trivy_scan() { + local trivy_bin + + # Trying running trivy binary first + # and downloading latest definitions + if command -v trivy &> /dev/null; then + trivy image --download-db-only + trivy_bin=1 + + else + echo -e "${RED}Trivy binary not found!${ENDCOLOR}" + echo -e "${BLUE}Trying to run trivy docker image...${ENDCOLOR}" + trivy_bin=0 + + fi + + for dir in $1; do + + # Testing terragrunt file + if test_terragrunt_file "$dir"; then + cd "$dir" + terragrunt plan -out=tfplan.binary --terragrunt-non-interactive > /dev/null + TG_CACHE_DIR=$(find "$dir" -type d -name '.terraform' -exec dirname {} \+) + cd "$TG_CACHE_DIR" + terraform show -json tfplan.binary > tfplan.json + + else + continue + fi + + echo -e "\n---------------------------------------" + echo "SCANNING -> $dir" + echo -e "---------------------------------------\n" + + # check if ignorefile exists + if [[ -f "$dir/$trivy_ignorefile" ]]; then + ARGS+=" --ignorefile $dir/$trivy_ignorefile" + fi + + if [[ $trivy_bin -eq 1 ]]; then + trivy config ${ARGS} "$TG_CACHE_DIR/tfplan.json" + + # remove plan files + rm -rf "$TG_CACHE_DIR/tfplan.binary" "$TG_CACHE_DIR/tfplan.json" + else + docker run --rm -v "$PWD:/src:rw,Z" -w "/src" aquasec/trivy:latest config \ + --cache-dir /src/.pre-commit-trivy-cache \ + ${ARGS} "$TG_CACHE_DIR/tfplan.json" + + fi + + echo -e "\n${GREEN}No Problems Found!!!${ENDCOLOR}" + done + +} + +function main() { + validate_dependencies + parse_args "$@" + DIR=$(echo "$DIR" | tr ' ' '\n' | sort -u | tr '\n' ' ') + + trivy_scan "$DIR" +} + +main "$@"