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>
This commit is contained in:
Mark Stemm 2018-07-11 18:02:12 -07:00
parent bbf43c88e1
commit ec7d8ce690
11 changed files with 1006 additions and 427 deletions

View file

@ -2,262 +2,314 @@
check_2() {
logit "\n"
info "2 - Docker daemon configuration"
id_2="2"
desc_2="Docker daemon configuration"
check_2="id_2 - $desc_2"
info "$check_2"
startsectionjson "$id_2" "$desc_2"
}
# 2.1
check_2_1() {
check_2_1="2.1 - Ensure network traffic is restricted between containers on the default bridge"
id_2_1="2.1"
desc_2_1="Ensure network traffic is restricted between containers on the default bridge"
check_2_1="$id_2_1 - $desc_2_1"
starttestjson "$id_2_1" "$desc_2_1"
totalChecks=$((totalChecks + 1))
if get_docker_effective_command_line_args '--icc' | grep false >/dev/null 2>&1; then
pass "$check_2_1"
logjson "2.1" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
elif get_docker_configuration_file_args 'icc' | grep "false" >/dev/null 2>&1; then
pass "$check_2_1"
logjson "2.1" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_1"
logjson "2.1" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
}
# 2.2
check_2_2() {
check_2_2="2.2 - Ensure the logging level is set to 'info'"
id_2_2="2.2"
desc_2_2="Ensure the logging level is set to 'info'"
check_2_2="$id_2_2 - $desc_2_2"
starttestjson "$id_2_2" "$desc_2_2"
totalChecks=$((totalChecks + 1))
if get_docker_configuration_file_args 'log-level' >/dev/null 2>&1; then
if get_docker_configuration_file_args 'log-level' | grep info >/dev/null 2>&1; then
pass "$check_2_2"
logjson "2.2" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
elif [ -z "$(get_docker_configuration_file_args 'log-level')" ]; then
pass "$check_2_2"
logjson "2.2" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_2"
logjson "2.2" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
elif get_docker_effective_command_line_args '-l'; then
if get_docker_effective_command_line_args '-l' | grep "info" >/dev/null 2>&1; then
pass "$check_2_2"
logjson "2.2" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_2"
logjson "2.2" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
else
pass "$check_2_2"
logjson "2.2" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
fi
}
# 2.3
check_2_3() {
check_2_3="2.3 - Ensure Docker is allowed to make changes to iptables"
id_2_3="2.3"
desc_2_3="Ensure Docker is allowed to make changes to iptables"
check_2_3="$id_2_3 - $desc_2_3"
starttestjson "$id_2_3" "$desc_2_3"
totalChecks=$((totalChecks + 1))
if get_docker_effective_command_line_args '--iptables' | grep "false" >/dev/null 2>&1; then
warn "$check_2_3"
logjson "2.3" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
elif get_docker_configuration_file_args 'iptables' | grep "false" >/dev/null 2>&1; then
warn "$check_2_3"
logjson "2.3" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
else
pass "$check_2_3"
logjson "2.3" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
fi
}
# 2.4
check_2_4() {
check_2_4="2.4 - Ensure insecure registries are not used"
id_2_4="2.4"
desc_2_4="Ensure insecure registries are not used"
check_2_4="$id_2_4 - $desc_2_4"
starttestjson "$id_2_4" "$desc_2_4"
totalChecks=$((totalChecks + 1))
if get_docker_effective_command_line_args '--insecure-registry' | grep "insecure-registry" >/dev/null 2>&1; then
warn "$check_2_4"
logjson "2.4" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
elif ! [ -z "$(get_docker_configuration_file_args 'insecure-registries')" ]; then
if get_docker_configuration_file_args 'insecure-registries' | grep '\[]' >/dev/null 2>&1; then
pass "$check_2_4"
logjson "2.4" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_4"
logjson "2.4" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
else
pass "$check_2_4"
logjson "2.4" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
fi
}
# 2.5
check_2_5() {
check_2_5="2.5 - Ensure aufs storage driver is not used"
id_2_5="2.5"
desc_2_5="Ensure aufs storage driver is not used"
check_2_5="$id_2_5 - $desc_2_5"
starttestjson "$id_2_5" "$desc_2_5"
totalChecks=$((totalChecks + 1))
if docker info 2>/dev/null | grep -e "^Storage Driver:\s*aufs\s*$" >/dev/null 2>&1; then
warn "$check_2_5"
logjson "2.5" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
else
pass "$check_2_5"
logjson "2.5" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
fi
}
# 2.6
check_2_6() {
check_2_6="2.6 - Ensure TLS authentication for Docker daemon is configured"
id_2_6="2.6"
desc_2_6="Ensure TLS authentication for Docker daemon is configured"
check_2_6="$id_2_6 - $desc_2_6"
starttestjson "$id_2_6" "$desc_2_6"
totalChecks=$((totalChecks + 1))
if [ grep -i 'tcp://' "$CONFIG_FILE" 2>/dev/null 1>&2 ] || \
[ $(get_docker_cumulative_command_line_args '-H' | grep -vE '(unix|fd)://') >/dev/null 2>&1 ]; then
if [ $(get_docker_configuration_file_args '"tlsverify":' | grep 'true') ] || \
[ $(get_docker_cumulative_command_line_args '--tlsverify' | grep 'tlsverify') >/dev/null 2>&1 ]; then
pass "$check_2_6"
logjson "2.6" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
elif [ $(get_docker_configuration_file_args '"tls":' | grep 'true') ] || \
[ $(get_docker_cumulative_command_line_args '--tls' | grep 'tls$') >/dev/null 2>&1 ]; then
warn "$check_2_6"
warn " * Docker daemon currently listening on TCP with TLS, but no verification"
logjson "2.6" "WARN"
resulttestjson "WARN" "Docker daemon currently listening on TCP with TLS, but no verification"
currentScore=$((currentScore - 1))
else
warn "$check_2_6"
warn " * Docker daemon currently listening on TCP without TLS"
logjson "2.6" "WARN"
resulttestjson "WARN" "Docker daemon currently listening on TCP without TLS"
currentScore=$((currentScore - 1))
fi
else
info "$check_2_6"
info " * Docker daemon not listening on TCP"
logjson "2.6" "INFO"
resulttestjson "INFO" "Docker daemon not listening on TCP"
currentScore=$((currentScore + 0))
fi
}
# 2.7
check_2_7() {
check_2_7="2.7 - Ensure the default ulimit is configured appropriately"
id_2_7="2.7"
desc_2_7="Ensure the default ulimit is configured appropriately"
check_2_7="$id_2_7 - $desc_2_7"
starttestjson "$id_2_7" "$desc_2_7"
totalChecks=$((totalChecks + 1))
if get_docker_configuration_file_args 'default-ulimit' | grep -v '{}' >/dev/null 2>&1; then
pass "$check_2_7"
logjson "2.7" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
elif get_docker_effective_command_line_args '--default-ulimit' | grep "default-ulimit" >/dev/null 2>&1; then
pass "$check_2_7"
logjson "2.7" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
info "$check_2_7"
info " * Default ulimit doesn't appear to be set"
logjson "2.7" "INFO"
resulttestjson "INFO" "Default ulimit doesn't appear to be set"
currentScore=$((currentScore + 0))
fi
}
# 2.8
check_2_8() {
check_2_8="2.8 - Enable user namespace support"
id_2_8="2.8"
desc_2_8="Enable user namespace support"
check_2_8="$id_2_8 - $desc_2_8"
starttestjson "$id_2_8" "$desc_2_8"
totalChecks=$((totalChecks + 1))
if get_docker_configuration_file_args 'userns-remap' | grep -v '""'; then
pass "$check_2_8"
logjson "2.8" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
elif get_docker_effective_command_line_args '--userns-remap' | grep "userns-remap" >/dev/null 2>&1; then
pass "$check_2_8"
logjson "2.8" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_8"
logjson "2.8" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
}
# 2.9
check_2_9() {
check_2_9="2.9 - Ensure the default cgroup usage has been confirmed"
id_2_9="2.9"
desc_2_9="Ensure the default cgroup usage has been confirmed"
check_2_9="$id_2_9 - $desc_2_9"
starttestjson "$id_2_9" "$desc_2_9"
totalChecks=$((totalChecks + 1))
if get_docker_configuration_file_args 'cgroup-parent' | grep -v '""'; then
warn "$check_2_9"
info " * Confirm cgroup usage"
logjson "2.9" "INFO"
resulttestjson "WARN" "Confirm cgroup usage"
currentScore=$((currentScore + 0))
elif get_docker_effective_command_line_args '--cgroup-parent' | grep "cgroup-parent" >/dev/null 2>&1; then
warn "$check_2_9"
info " * Confirm cgroup usage"
logjson "2.9" "INFO"
resulttestjson "WARN" "Confirm cgroup usage"
currentScore=$((currentScore + 0))
else
pass "$check_2_9"
logjson "2.9" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
fi
}
# 2.10
check_2_10() {
check_2_10="2.10 - Ensure base device size is not changed until needed"
id_2_10="2.10"
desc_2_10="Ensure base device size is not changed until needed"
check_2_10="$id_2_10 - $desc_2_10"
starttestjson "$id_2_10" "$desc_2_10"
totalChecks=$((totalChecks + 1))
if get_docker_configuration_file_args 'storage-opts' | grep "dm.basesize" >/dev/null 2>&1; then
warn "$check_2_10"
logjson "2.10" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
elif get_docker_effective_command_line_args '--storage-opt' | grep "dm.basesize" >/dev/null 2>&1; then
warn "$check_2_10"
logjson "2.10" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
else
pass "$check_2_10"
logjson "2.10" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
fi
}
# 2.11
check_2_11() {
check_2_11="2.11 - Ensure that authorization for Docker client commands is enabled"
id_2_11="2.11"
desc_2_11="Ensure that authorization for Docker client commands is enabled"
check_2_11="$id_2_11 - $desc_2_11"
starttestjson "$id_2_11" "$desc_2_11"
totalChecks=$((totalChecks + 1))
if get_docker_configuration_file_args 'authorization-plugins' | grep -v '\[]'; then
pass "$check_2_11"
logjson "2.11" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
elif get_docker_effective_command_line_args '--authorization-plugin' | grep "authorization-plugin" >/dev/null 2>&1; then
pass "$check_2_11"
logjson "2.11" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_11"
logjson "2.11" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
}
# 2.12
check_2_12() {
check_2_12="2.12 - Ensure centralized and remote logging is configured"
id_2_12="2.12"
desc_2_12="Ensure centralized and remote logging is configured"
check_2_12="$id_2_12 - $desc_2_12"
starttestjson "$id_2_12" "$desc_2_12"
totalChecks=$((totalChecks + 1))
if docker info --format '{{ .LoggingDriver }}' | grep 'json-file' >/dev/null 2>&1; then
warn "$check_2_12"
logjson "2.12" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
else
pass "$check_2_12"
logjson "2.12" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
fi
}
@ -267,48 +319,58 @@ check_2_13() {
docker_version=$(docker version | grep -i -A2 '^server' | grep ' Version:' \
| awk '{print $NF; exit}' | tr -d '[:alpha:]-,.')
totalChecks=$((totalChecks + 1))
id_2_13="2.13"
desc_2_13="Ensure operations on legacy registry (v1) are Disabled"
check_2_13="$id_2_13 - $desc_2_13"
starttestjson "$id_2_13" "$desc_2_13"
if [ "$docker_version" -lt 1712 ]; then
check_2_13="2.13 - Ensure operations on legacy registry (v1) are Disabled"
if get_docker_configuration_file_args 'disable-legacy-registry' | grep 'true' >/dev/null 2>&1; then
pass "$check_2_13"
logjson "2.13" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
elif get_docker_effective_command_line_args '--disable-legacy-registry' | grep "disable-legacy-registry" >/dev/null 2>&1; then
pass "$check_2_13"
logjson "2.13" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_13"
logjson "2.13" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
else
check_2_13="2.13 - Ensure operations on legacy registry (v1) are Disabled (Deprecated)"
desc_2_13="$desc_2_13 (Deprecated)"
check_2_13="$id_2_13 - $desc_2_13"
info "$check_2_13"
logjson "2.13" "info"
resulttestjson "INFO"
fi
}
# 2.14
check_2_14() {
check_2_14="2.14 - Ensure live restore is Enabled"
id_2_14="2.14"
desc_2_14="Ensure live restore is Enabled"
check_2_14="$id_2_14 - $desc_2_14"
starttestjson "$id_2_14" "$desc_2_14"
totalChecks=$((totalChecks + 1))
if docker info 2>/dev/null | grep -e "Live Restore Enabled:\s*true\s*" >/dev/null 2>&1; then
pass "$check_2_14"
logjson "2.14" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
if docker info 2>/dev/null | grep -e "Swarm:*\sactive\s*" >/dev/null 2>&1; then
pass "$check_2_14 (Incompatible with swarm mode)"
logjson "2.14" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
elif get_docker_effective_command_line_args '--live-restore' | grep "live-restore" >/dev/null 2>&1; then
pass "$check_2_14"
logjson "2.14" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_14"
logjson "2.14" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
fi
@ -316,68 +378,88 @@ check_2_14() {
# 2.15
check_2_15() {
check_2_15="2.15 - Ensure Userland Proxy is Disabled"
id_2_15="2.15"
desc_2_15="Ensure Userland Proxy is Disabled"
check_2_15="$id_2_15 - $desc_2_15"
starttestjson "$id_2_15" "$desc_2_15"
totalChecks=$((totalChecks + 1))
if get_docker_configuration_file_args 'userland-proxy' | grep false >/dev/null 2>&1; then
pass "$check_2_15"
logjson "2.15" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
elif get_docker_effective_command_line_args '--userland-proxy=false' 2>/dev/null | grep "userland-proxy=false" >/dev/null 2>&1; then
pass "$check_2_15"
logjson "2.15" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_15"
logjson "2.15" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
}
# 2.16
check_2_16() {
check_2_16="2.16 - Ensure daemon-wide custom seccomp profile is applied, if needed"
id_2_16="2.16"
desc_2_16="Ensure daemon-wide custom seccomp profile is applied, if needed"
check_2_16="$id_2_16 - $desc_2_16"
starttestjson "$id_2_16" "$desc_2_16"
totalChecks=$((totalChecks + 1))
if docker info --format '{{ .SecurityOptions }}' | grep 'name=seccomp,profile=default' 2>/dev/null 1>&2; then
pass "$check_2_16"
logjson "2.16" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
info "$check_2_16"
logjson "2.16" "INFO"
resulttestjson "INFO"
currentScore=$((currentScore + 0))
fi
}
# 2.17
check_2_17() {
check_2_17="2.17 - Ensure experimental features are avoided in production"
id_2_17="2.17"
desc_2_17="Ensure experimental features are avoided in production"
check_2_17="$id_2_17 - $desc_2_17"
starttestjson "$id_2_17" "$desc_2_17"
totalChecks=$((totalChecks + 1))
if docker version -f '{{.Server.Experimental}}' | grep false 2>/dev/null 1>&2; then
pass "$check_2_17"
logjson "2.17" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_17"
logjson "2.17" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
}
# 2.18
check_2_18() {
check_2_18="2.18 - Ensure containers are restricted from acquiring new privileges"
id_2_18="2.18"
desc_2_18="Ensure containers are restricted from acquiring new privileges"
check_2_18="$id_2_18 - $desc_2_18"
starttestjson "$id_2_18" "$desc_2_18"
totalChecks=$((totalChecks + 1))
if get_docker_effective_command_line_args '--no-new-privileges' | grep "no-new-privileges" >/dev/null 2>&1; then
pass "$check_2_18"
logjson "2.18" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
elif get_docker_configuration_file_args 'no-new-privileges' | grep true >/dev/null 2>&1; then
pass "$check_2_18"
logjson "2.18" "PASS"
resulttestjson "PASS"
currentScore=$((currentScore + 1))
else
warn "$check_2_18"
logjson "2.18" "WARN"
resulttestjson "WARN"
currentScore=$((currentScore - 1))
fi
}
check_2_end() {
endsectionjson
}