2015-05-11 06:08:28 +02:00
|
|
|
#!/bin/sh
|
|
|
|
# ------------------------------------------------------------------------------
|
2018-05-10 15:19:10 +02:00
|
|
|
# Docker Bench for Security
|
2015-05-11 06:08:28 +02:00
|
|
|
#
|
2016-04-30 22:31:08 +02:00
|
|
|
# Docker, Inc. (c) 2015-
|
2015-05-11 06:08:28 +02:00
|
|
|
#
|
2015-06-28 20:04:53 +02:00
|
|
|
# Checks for dozens of common best-practices around deploying Docker containers in production.
|
2015-05-11 06:08:28 +02:00
|
|
|
# ------------------------------------------------------------------------------
|
|
|
|
|
2018-05-10 15:19:10 +02:00
|
|
|
version='1.3.4'
|
|
|
|
|
2015-05-11 06:08:28 +02:00
|
|
|
# Setup the paths
|
2018-05-10 15:41:27 +02:00
|
|
|
this_path=$(abspath "$0") ## Path of this file including filename
|
2015-05-29 13:42:34 +02:00
|
|
|
myname=$(basename "${this_path}") ## file name of this script.
|
2015-05-11 06:08:28 +02:00
|
|
|
|
2018-05-10 15:41:27 +02:00
|
|
|
readonly version
|
|
|
|
readonly this_path
|
|
|
|
readonly myname
|
|
|
|
|
2018-06-26 21:45:43 +02:00
|
|
|
export PATH=$PATH:/bin:/sbin:/usr/bin:/usr/local/bin:/usr/sbin/
|
2015-05-11 06:08:28 +02:00
|
|
|
|
|
|
|
# Check for required program(s)
|
2018-01-11 16:43:53 +01:00
|
|
|
req_progs='awk docker grep ss stat'
|
2015-05-11 06:08:28 +02:00
|
|
|
for p in $req_progs; do
|
2015-05-29 13:42:34 +02:00
|
|
|
command -v "$p" >/dev/null 2>&1 || { printf "%s command not found.\n" "$p"; exit 1; }
|
2015-05-11 06:08:28 +02:00
|
|
|
done
|
|
|
|
|
|
|
|
# Ensure we can connect to docker daemon
|
2017-02-17 15:03:29 +01:00
|
|
|
if ! docker ps -q >/dev/null 2>&1; then
|
2015-05-11 06:08:28 +02:00
|
|
|
printf "Error connecting to docker daemon (does docker ps work?)\n"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
usage () {
|
2015-09-05 01:25:13 +02:00
|
|
|
cat <<EOF
|
|
|
|
usage: ${myname} [options]
|
2015-05-11 06:08:28 +02:00
|
|
|
|
2018-10-25 11:34:14 +02:00
|
|
|
-b optional Do not print colors
|
2015-09-05 01:25:13 +02:00
|
|
|
-h optional Print this help message
|
2018-01-16 13:44:43 +01:00
|
|
|
-l FILE optional Log output in FILE
|
2018-02-27 15:43:51 +01:00
|
|
|
-c CHECK optional Comma delimited list of specific check(s)
|
2018-05-10 14:45:59 +02:00
|
|
|
-e CHECK optional Comma delimited list of specific check(s) to exclude
|
2018-10-15 16:21:00 +02:00
|
|
|
-i INCLUDE optional Comma delimited list of patterns within a container name to check
|
2018-02-27 15:43:51 +01:00
|
|
|
-x EXCLUDE optional Comma delimited list of patterns within a container name to exclude from check
|
2015-09-05 01:25:13 +02:00
|
|
|
EOF
|
2015-05-11 06:08:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# Get the flags
|
2015-09-05 01:25:13 +02:00
|
|
|
# If you add an option here, please
|
|
|
|
# remember to update usage() above.
|
2018-10-25 11:34:14 +02:00
|
|
|
while getopts bhl:c:e:i:x: args
|
2015-05-11 06:08:28 +02:00
|
|
|
do
|
|
|
|
case $args in
|
2018-10-25 11:34:14 +02:00
|
|
|
b) nocolor="nocolor";;
|
2015-09-05 01:34:00 +02:00
|
|
|
h) usage; exit 0 ;;
|
2015-05-11 06:08:28 +02:00
|
|
|
l) logger="$OPTARG" ;;
|
2018-01-16 13:44:43 +01:00
|
|
|
c) check="$OPTARG" ;;
|
2018-05-10 14:45:59 +02:00
|
|
|
e) checkexclude="$OPTARG" ;;
|
2018-10-15 16:21:00 +02:00
|
|
|
i) include="$OPTARG" ;;
|
2018-02-27 15:43:51 +01:00
|
|
|
x) exclude="$OPTARG" ;;
|
2015-09-05 01:34:00 +02:00
|
|
|
*) usage; exit 1 ;;
|
2015-05-11 06:08:28 +02:00
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
2015-09-05 16:23:34 +02:00
|
|
|
if [ -z "$logger" ]; then
|
|
|
|
logger="${myname}.log"
|
|
|
|
fi
|
|
|
|
|
2018-10-25 11:34:14 +02:00
|
|
|
# Load dependencies
|
|
|
|
. ./functions_lib.sh
|
|
|
|
. ./helper_lib.sh
|
|
|
|
. ./output_lib.sh
|
|
|
|
|
2018-05-10 15:19:10 +02:00
|
|
|
yell_info
|
2015-09-05 16:23:34 +02:00
|
|
|
|
2015-09-05 15:51:51 +02:00
|
|
|
# Warn if not root
|
|
|
|
ID=$(id -u)
|
|
|
|
if [ "x$ID" != "x0" ]; then
|
2018-05-10 15:41:27 +02:00
|
|
|
warn "Some tests might require root to run"
|
|
|
|
sleep 3
|
2015-09-05 15:51:51 +02:00
|
|
|
fi
|
|
|
|
|
2017-10-23 15:38:08 +02:00
|
|
|
# Total Score
|
|
|
|
# Warn Scored -1, Pass Scored +1, Not Score -0
|
|
|
|
|
|
|
|
totalChecks=0
|
|
|
|
currentScore=0
|
|
|
|
|
2015-09-05 15:44:44 +02:00
|
|
|
logit "Initializing $(date)\n"
|
2018-05-10 15:19:10 +02:00
|
|
|
beginjson "$version" "$(date +%s)"
|
2015-09-05 15:44:44 +02:00
|
|
|
|
2015-05-11 06:08:28 +02:00
|
|
|
# Load all the tests from tests/ and run them
|
|
|
|
main () {
|
2015-07-25 07:08:14 +02:00
|
|
|
# If there is a container with label docker_bench_security, memorize it:
|
2015-05-14 02:08:12 +02:00
|
|
|
benchcont="nil"
|
|
|
|
for c in $containers; do
|
2017-02-17 15:03:29 +01:00
|
|
|
if docker inspect --format '{{ .Config.Labels }}' "$c" | \
|
|
|
|
grep -e 'docker.bench.security' >/dev/null 2>&1; then
|
|
|
|
benchcont="$c"
|
|
|
|
fi
|
2015-05-14 02:08:12 +02:00
|
|
|
done
|
2018-10-15 16:21:00 +02:00
|
|
|
|
|
|
|
if [ -n "$include" ]; then
|
|
|
|
pattern=$(echo "$include" | sed 's/,/|/g')
|
|
|
|
containers=$(docker ps | sed '1d' | awk '{print $NF}' | grep -v "$benchcont" | grep -E "$pattern")
|
|
|
|
elif [ -n "$exclude" ]; then
|
2018-02-27 15:43:51 +01:00
|
|
|
pattern=$(echo "$exclude" | sed 's/,/|/g')
|
2018-10-15 16:21:00 +02:00
|
|
|
containers=$(docker ps | sed '1d' | awk '{print $NF}' | grep -v "$benchcont" | grep -Ev "$pattern")
|
|
|
|
else
|
|
|
|
containers=$(docker ps | sed '1d' | awk '{print $NF}' | grep -v "$benchcont")
|
2018-02-27 15:43:51 +01:00
|
|
|
fi
|
2015-05-14 04:22:39 +02:00
|
|
|
|
2018-01-16 13:44:43 +01:00
|
|
|
if [ -z "$containers" ]; then
|
|
|
|
running_containers=0
|
|
|
|
else
|
|
|
|
running_containers=1
|
|
|
|
fi
|
|
|
|
|
2018-05-10 15:41:27 +02:00
|
|
|
for test in tests/*.sh; do
|
|
|
|
. ./"$test"
|
2015-05-11 06:08:28 +02:00
|
|
|
done
|
2017-10-10 13:54:59 +02:00
|
|
|
|
2018-05-10 15:41:27 +02:00
|
|
|
if [ -z "$check" ] && [ ! "$checkexclude" ]; then
|
2018-01-16 13:44:43 +01:00
|
|
|
cis
|
2018-05-10 14:45:59 +02:00
|
|
|
elif [ -z "$check" ] && [ "$checkexclude" ]; then
|
2018-10-24 10:01:27 +02:00
|
|
|
checkexcluded="$(echo ",$checkexclude" | sed -e 's/^/\^/g' -e 's/,/\$|/g' -e 's/$/\$/g')"
|
|
|
|
for c in $(grep 'check_[0-9]_' functions_lib.sh | grep -vE "\'$checkexcluded\'"); do
|
2018-05-10 14:45:59 +02:00
|
|
|
"$c"
|
|
|
|
done
|
2018-01-16 13:44:43 +01:00
|
|
|
else
|
2018-05-10 14:45:59 +02:00
|
|
|
for i in $(echo "$check" | sed "s/,/ /g"); do
|
2018-02-27 15:43:51 +01:00
|
|
|
if command -v "$i" 2>/dev/null 1>&2; then
|
|
|
|
"$i"
|
|
|
|
else
|
|
|
|
echo "Check \"$i\" doesn't seem to exist."
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
done
|
2018-01-16 13:44:43 +01:00
|
|
|
fi
|
|
|
|
|
2017-10-23 15:38:08 +02:00
|
|
|
printf "\n"
|
|
|
|
info "Checks: $totalChecks"
|
|
|
|
info "Score: $currentScore"
|
|
|
|
|
Improve docker-bench-security json output
Add a test object for each test performed by the script. Each object has
an id N.M, a desc property describing the test, and the result. Some
tests include additional information about the test e.g. "No TLS
Certificate Found". That can be found in an optional details property of
the test object.
Also, some tests might also return a list of containers, images, users,
etc. This is included in an optional items property of the test object.
Instead of having all test results as top-level objects, break the test
results into sections. Each section has an id + description e.g. "1" and
"Host Configuration". The tests for that section are an array below that
object.
All of the additional json output is implemented by adding new functions
startsectionjson(), endsectionjson(), starttestjson(), and
resulttestjson() that take the id/desc/etc as arguments and print the
proper json properties. It also required adding an "end" test to each
script that calls endsectionjson().
Signed-off-by: Mark Stemm <mark.stemm@gmail.com>
2018-07-12 03:02:12 +02:00
|
|
|
endjson "$totalChecks" "$currentScore" "$(date +%s)"
|
2015-05-11 06:08:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
main "$@"
|