First version of the CIS Docker Benchmark v1.0.0

This commit is contained in:
Diogo Monica 2015-05-10 21:08:28 -07:00
parent 487307834f
commit 18d5a13240
13 changed files with 1545 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.log

11
Dockerfile Normal file
View file

@ -0,0 +1,11 @@
FROM gliderlabs/alpine:3.1
RUN apk --update add docker
RUN mkdir /docker_security_benchmark
COPY . /docker_security_benchmark
WORKDIR /docker_security_benchmark
ENTRYPOINT ["/bin/sh", "docker_security_benchmark.sh"]

0
README
View file

36
README.md Normal file
View file

@ -0,0 +1,36 @@
# Docker Security Benchmark Checker
The Docker Security Benchmark Checker is a script that checks for all the automatable tests included in the [CIS Docker 1.6 Benchmark](https://benchmarks.cisecurity.org/tools2/docker/CIS_Docker_1.6_Benchmark_v1.0.0.pdf). We are releasing this as a follow-up to our [Understanding Docker Security and Best Practices](https://blog.docker.com/2015/05/understanding-docker-security-and-best-practices/) blog post.
We are making this available as an open-source utility so the Docker community can have an easy way to self-assess their hosts and docker containers against this benchmark.
## Running the benchmark
We packaged this benchmark as a small container for your convenience. Note that this container is being run with a *lot* of privilege -- sharing the host's filesystem, pid and network namespaces, due to portions of the benchmark applying to the running host.
The easiest way to run your hosts against the CIS Docker 1.6 benchmark is by running our pre-built container:
```
docker run -it --net host --pid host -v /var/run/docker.sock:/var/run/docker.sock \
-v /usr/lib/systemd:/usr/lib/systemd -v /etc:/etc diogomonica/docker-security-benchmark
```
## Building the benchmark
If you wish to build and run this container yourself, you can follow the following steps:
```
# git clone https://github.com/diogomonica/docker-security-benchmark.git
# cd docker-security-benchmark; docker build -t docker-security-benchmark .
# docker run run -it --net host --pid host -v /var/run/docker.sock:/var/run/docker.sock -v /usr/lib/systemd:/usr/lib/systemd -v /etc:/etc docker-security-benchmark
```
Also, this script can also be simply run from your base host by running:
```
# git clone https://github.com/diogomonica/docker-security-benchmark.git
# cd docker-security-benchmark; sh docker_security_benchmark.sh
```
This script was build to be POSIX 2004 compliant, so it should be portable across any Unix platform.

View file

@ -0,0 +1,80 @@
#!/bin/sh
# ------------------------------------------------------------------------------
# CIS Docker 1.6 Benchmark v1.0.0 checker
#
# Docker, Inc. (c) 2015
#
# Provides automated tests for the CIS Docker 1.6 Benchmark:
# https://benchmarks.cisecurity.org/tools2/docker/CIS_Docker_1.6_Benchmark_v1.0.0.pdf
#
# ------------------------------------------------------------------------------
# Load dependencies
. ./output_lib.sh
. ./helper_lib.sh
# Setup the paths
this_path=$(abspath $0) ## Path of this file including filenamel
dir_name=`dirname ${this_path}` ## Dir where this file is
myname=`basename ${this_path}` ## file name of this script.
logger="${myname}.log"
# Check for required program(s)
req_progs='docker netstat grep awk'
for p in $req_progs; do
command -v $p >/dev/null 2>&1 || { printf "$p command not found.\n"; exit 1; }
done
# Ensure we can connect to docker daemon
`docker ps -q >/dev/null 2>&1`
if [ $? -ne 0 ]; then
printf "Error connecting to docker daemon (does docker ps work?)\n"
exit 1
fi
usage () {
printf "
usage: $myname [options]
-h optional Print this help message\n"
exit 1
}
yell "# ------------------------------------------------------------------------------
# CIS Docker 1.6 Benchmark v1.0.0 checker
#
# Docker, Inc. (c) 2015
#
# Provides automated tests for the CIS Docker 1.6 Benchmark:
# https://benchmarks.cisecurity.org/tools2/docker/CIS_Docker_1.6_Benchmark_v1.0.0.pdf
# ------------------------------------------------------------------------------"
logit "Initializing `date`\n"
# Warn if not root
ID=`id -u`
if test "x$ID" != "x0"; then
warn "Some tests might require root to run"
sleep 3
fi
# Get the flags
while getopts :hlfi: args
do
case $args in
h) usage ;;
l) logger="$OPTARG" ;;
*) usage ;;
esac
done
# Load all the tests from tests/ and run them
main () {
for test in tests/*.sh
do
. ./$test
done
}
main "$@"

38
helper_lib.sh Normal file
View file

@ -0,0 +1,38 @@
#!/bin/sh
# Returns the absolute path of a given string
abspath () { case "$1" in /*)printf "%s\n" "$1";; *)printf "%s\n" "$PWD/$1";; esac; }
# Compares versions of software of the format X.Y.Z
do_version_check() {
[ "$1" = "$2" ] && return 10
ver1front=`printf $1 | cut -d "." -f -1`
ver1back=`printf $1 | cut -d "." -f 2-`
ver2front=`printf $2 | cut -d "." -f -1`
ver2back=`printf $2 | cut -d "." -f 2-`
if [ "$ver1front" != "$1" ] || [ "$ver2front" != "$2" ]; then
[ "$ver1front" -gt "$ver2front" ] && return 11
[ "$ver1front" -lt "$ver2front" ] && return 9
[ "$ver1front" = "$1" ] || [ -z "$ver1back" ] && ver1back=0
[ "$ver2front" = "$2" ] || [ -z "$ver2back" ] && ver2back=0
do_version_check "$ver1back" "$ver2back"
return $?
else
[ "$1" -gt "$2" ] && return 11 || return 9
fi
}
# Compares two strings and returns 0 if the second is a substring of the first
contains() {
string="$1"
substring="$2"
if test "${string#*$substring}" != "$string"
then
return 0 # $substring is in $string
else
return 1 # $substring is not in $string
fi
}

25
output_lib.sh Normal file
View file

@ -0,0 +1,25 @@
bldred='\033[1;31m'
bldgrn='\033[1;32m'
bldblu='\033[1;34m'
bldylw='\033[1;33m' # Yellow
txtrst='\033[0m'
logit () {
printf "$1\n" | tee -a $logger
}
info () {
printf '%b' "${bldblu}[INFO]${txtrst} $1\n" | tee -a $logger
}
pass () {
printf '%b' "${bldgrn}[PASS]${txtrst} $1\n" | tee -a $logger
}
warn () {
printf '%b' "${bldred}[WARN]${txtrst} $1\n" | tee -a $logger
}
yell () {
printf '%b' "${bldylw}$1${txtrst}\n"
}

View file

@ -0,0 +1,208 @@
#!/bin/sh
logit ""
info "1 - Host Configuration"
# 1.1
check_1_1="1.1 - Create a separate partition for containers"
grep /var/lib/docker /etc/fstab >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_1"
else
warn "$check_1_1"
fi
# 1.2
check_1_2="1.2 - Use an updated Linux Kernel"
kernel_version=`uname -r | cut -d "-" -f 1`
do_version_check 3.10 $kernel_version
if [ $? -eq 11 ]; then
warn "$check_1_2"
else
pass "$check_1_2"
fi
# 1.5
check_1_5="1.5 - Remove all non-essential services from the host - Network"
# Check for listening network services.
listening_services=`netstat -na | grep -v tcp6 | grep -v unix | grep LISTEN | wc -l`
if [ $listening_services -eq 0 ]; then
warn "1.5 - Failed to get listening services for check: $check_1_5"
else
if [ $listening_services -gt 5 ]; then
warn "$check_1_5"
else
pass "$check_1_5"
fi
fi
# 1.6
check_1_6="1.6 - Keep Docker up to date"
docker_version=`docker version | grep 'Server version' | awk '{print $3}'`
if [ $? -eq 11 ]; then
warn "$check_1_6"
else
pass "$check_1_6"
fi
# 1.7
check_1_7="1.7 - Only allow trusted users to control Docker daemon"
docker_users=`cat /etc/group | grep docker`
info "$check_1_7"
for u in $docker_users; do
info " * $u"
done
# 1.8
check_1_8="1.8 - Audit docker daemon"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /usr/bin/docker >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_8"
else
warn "$check_1_8"
fi
else
warn "1.8 - Failed to inspect: auditctl command not found."
fi
# 1.9
check_1_9="1.9 - Audit Docker files and directories - /var/lib/docker"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /var/lib/docker >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_9"
else
warn "$check_1_9"
fi
else
warn "1.9 - Failed to inspect: auditctl command not found."
fi
# 1.10
check_1_10="1.10 - Audit Docker files and directories - /etc/docker"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /etc/docker >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_10"
else
warn "$check_1_10"
fi
else
warn "1.10 - Failed to inspect: auditctl command not found."
fi
# 1.11
check_1_11="1.11 - Audit Docker files and directories - docker-registry.service"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /usr/lib/systemd/system/docker-registry.service >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_11"
else
warn "$check_1_11"
fi
else
warn "1.11 - Failed to inspect: auditctl command not found."
fi
# 1.12
check_1_12="1.12 - Audit Docker files and directories - docker.service"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /usr/lib/systemd/system/docker.service >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_12"
else
warn "$check_1_12"
fi
else
warn "1.12 - Failed to inspect: auditctl command not found."
fi
# 1.13
check_1_13="1.13 - Audit Docker files and directories - /var/run/docker.sock"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /var/run/docker.sock >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_13"
else
warn "$check_1_13"
fi
else
warn "1.13 - Failed to inspect: auditctl command not found."
fi
# 1.14
check_1_14="1.14 - Audit Docker files and directories - /etc/sysconfig/docker"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /etc/sysconfig/docker >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_14"
else
warn "$check_1_14"
fi
else
warn "1.14 - Failed to inspect: auditctl command not found."
fi
# 1.15
check_1_15="1.15 - Audit Docker files and directories - /etc/sysconfig/docker-network"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /etc/sysconfig/docker-network >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_15"
else
warn "$check_1_15"
fi
else
warn "1.15 - Failed to inspect: auditctl command not found."
fi
# 1.16
check_1_16="1.16 - Audit Docker files and directories - /etc/sysconfig/docker-registry"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /etc/sysconfig/docker-registry >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_16"
else
warn "$check_1_16"
fi
else
warn "1.16 - Failed to inspect: auditctl command not found."
fi
# 1.17
check_1_17="1.17 - Audit Docker files and directories - /etc/sysconfig/docker-storage"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /etc/sysconfig/docker-storage >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_17"
else
warn "$check_1_17"
fi
else
warn "1.17 - Failed to inspect: auditctl command not found."
fi
# 1.18
check_1_18="1.18 - Audit Docker files and directories - /etc/default/docker"
command -v auditctl >/dev/null 2>&1
if [ $? -eq 0 ]; then
auditctl -l | grep /etc/default/docker >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_1_18"
else
warn "$check_1_18"
fi
else
warn "1.18 - Failed to inspect: auditctl command not found."
fi

View file

@ -0,0 +1,105 @@
#!/bin/sh
logit "\n"
info "2 - Docker Daemon Configuration"
# 2.1
check_2_1="2.1 - Do not use lxc execution driver"
ps -ef | grep docker | grep lxc >/dev/null 2>&1
if [ $? -eq 0 ]; then
warn "$check_2_1"
else
pass "$check_2_1"
fi
# 2.2
check_2_2="2.2 - Restrict network traffic between containers"
ps -ef | grep docker | grep "icc=false" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_2_2"
else
warn "$check_2_2"
fi
# 2.3
check_2_3="2.3 - Set the logging level"
ps -ef | grep docker | grep "log-level=\"debug\"" >/dev/null 2>&1
if [ $? -eq 0 ]; then
warn "$check_2_3"
else
pass "$check_2_3"
fi
# 2.4
check_2_4="2.4 - Allow Docker to make changes to iptables"
ps -ef | grep docker | grep "iptables=false" >/dev/null 2>&1
if [ $? -eq 0 ]; then
warn "$check_2_4"
else
pass "$check_2_4"
fi
# 2.5
check_2_5="2.5 - Do not use insecure registries"
ps -ef | grep docker | grep "insecure-registry" >/dev/null 2>&1
if [ $? -eq 0 ]; then
warn "$check_2_5"
else
pass "$check_2_5"
fi
# 2.6
check_2_6="2.6 - Setup a local registry mirror"
ps -ef | grep docker | grep "registry-mirror" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_2_6"
else
info "$check_2_6"
info " * No local registry currently configured"
fi
# 2.7
check_2_7="2.7 - Do not use the aufs storage driver"
storage_driver=`docker info 2>/dev/null| grep -e "^Storage Driver:\s*aufs\s*$"`
if [ $? -eq 0 ]; then
warn "$check_2_7"
else
pass "$check_2_7"
fi
# 2.8
check_2_8="2.8 - Do not bind Docker to another IP/Port or a Unix socket"
ps -ef | grep docker | grep "\-H" >/dev/null 2>&1
if [ $? -eq 0 ]; then
info "$check_2_8"
info " * Docker daemon running with -H"
else
pass "$check_2_8"
fi
# 2.9
check_2_9="2.9 - Configure TLS authentication for Docker daemon"
ps -ef | grep docker | grep "tcp://" >/dev/null 2>&1
if [ $? -eq 0 ]; then
ps -ef | grep docker | grep "tlsverify" | grep "tlskey" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_2_9"
info " * Docker daemon currently listening on TCP"
else
warn "$check_2_9"
warn " * Docker daemon currently listening on TCP without --tlsverify"
fi
else
info "$check_2_9"
info " * Docker daemon not listening on TCP"
fi
# 2.10
check_2_10="2.10 - Set default ulimit as appropriate"
ps -ef | grep docker | grep "default-ulimit" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_2_10"
else
info "$check_2_10"
info " * Default ulimit doesn't appear to be set"
fi

View file

@ -0,0 +1,435 @@
#!/bin/sh
logit "\n"
info "3 - Docker Daemon Configuration Files"
# 3.1
check_3_1="3.1 - Verify that docker.service file ownership is set to root:root"
file="/usr/lib/systemd/system/docker.service"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_1"
else
warn "$check_3_1"
warn " * Wrong ownership for $file"
fi
else
info "$check_3_1"
info " * File not found"
fi
# 3.2
check_3_2="3.2 - Verify that docker.service file permissions are set to 644"
file="/usr/lib/systemd/system/docker.service"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $1}' | grep "rw-r--r--" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_2"
else
warn "$check_3_2"
warn " * Wrong permissions for $file"
fi
else
info "$check_3_2"
info " * File not found"
fi
# 3.3
check_3_3="3.3 - Verify that docker-registry.service file ownership is set to root:root"
file="/usr/lib/systemd/system/docker-registry.service"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_3"
else
warn "$check_3_3"
warn " * Wrong ownership for $file"
fi
else
info "$check_3_3"
info " * File not found"
fi
# 3.4
check_3_4="3.4 - Verify that docker-registry.service file permissions are set to 644"
file="/usr/lib/systemd/system/docker-registry.service"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $1}' | grep "rw-r--r--" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_4"
else
warn "$check_3_4"
warn " * Wrong permissions for $file"
fi
else
info "$check_3_4"
info " * File not found"
fi
# 3.5
check_3_5="3.5 - Verify that docker.socket file ownership is set to root:root"
file="/usr/lib/systemd/system/docker.socket"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_5"
else
warn "$check_3_5"
warn " * Wrong ownership for $file"
fi
else
info "$check_3_5"
info " * File not found"
fi
# 3.6
check_3_6="3.6 - Verify that docker.socket file permissions are set to 644"
file="/usr/lib/systemd/system/docker.socket"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $1}' | grep "rw-r--r--" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_6"
else
warn "$check_3_6"
warn " * Wrong permissions for $file"
fi
else
info "$check_3_6"
info " * File not found"
fi
# 3.7
check_3_7="3.7 - Verify that Docker environment file ownership is set to root:root "
file="/etc/sysconfig/docker"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_7"
else
warn "$check_3_7"
warn " * Wrong ownership for $file"
fi
else
info "$check_3_7"
info " * File not found"
fi
# 3.8
check_3_8="3.8 - Verify that Docker environment file permissions are set to 644"
file="/etc/sysconfig/docker"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $1}' | grep "rw-r--r--" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_8"
else
warn "$check_3_8"
warn " * Wrong permissions for $file"
fi
else
info "$check_3_8"
info " * File not found"
fi
# 3.9
check_3_9="3.9 - Verify that docker-network environment file ownership is set to root:root"
file="/etc/sysconfig/docker-network"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_9"
else
warn "$check_3_9"
warn " * Wrong ownership for $file"
fi
else
info "$check_3_9"
info " * File not found"
fi
# 3.10
check_3_10="3.10 - Verify that docker-network environment file permissions are set to 644"
file="/etc/sysconfig/docker-network"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $1}' | grep "rw-r--r--" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_10"
else
warn "$check_3_10"
warn " * Wrong permissions for $file"
fi
else
info "$check_3_10"
info " * File not found"
fi
# 3.11
check_3_11="3.11 - Verify that docker-registry environment file ownership is set to root:root"
file="/etc/sysconfig/docker-registry"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_11"
else
warn "$check_3_11"
warn " * Wrong ownership for $file"
fi
else
info "$check_3_11"
info " * File not found"
fi
# 3.12
check_3_12="3.12 - Verify that docker-registry environment file permissions are set to 644"
file="/etc/sysconfig/docker-registry"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $1}' | grep "rw-r--r--" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_12"
else
warn "$check_3_12"
warn " * Wrong permissions for $file"
fi
else
info "$check_3_12"
info " * File not found"
fi
# 3.13
check_3_13="3.13 - Verify that docker-storage environment file ownership is set to root:root"
file="/etc/sysconfig/docker-storage"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_13"
else
warn "$check_3_13"
warn " * Wrong ownership for $file"
fi
else
info "$check_3_13"
info " * File not found"
fi
# 3.14
check_3_14="3.14 - Verify that docker-storage environment file permissions are set to 644"
file="/etc/sysconfig/docker-storage"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $1}' | grep "rw-r--r--" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_14"
else
warn "$check_3_14"
warn " * Wrong permissions for $file"
fi
else
info "$check_3_14"
info " * File not found"
fi
# 3.15
check_3_15="3.15 - Verify that /etc/docker directory ownership is set to root:root"
directory="/etc/docker"
if [ -d "$directory" ]; then
ls -ld "$directory" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_15"
else
warn "$check_3_15"
warn " * Wrong ownership for $directory"
fi
else
info "$check_3_15"
info " * Directory not found"
fi
# 3.16
check_3_16="3.16 - Verify that /etc/docker directory permissions are set to 755"
directory="/etc/docker"
if [ -d "$directory" ]; then
perms=`ls -ld $directory | awk '{print $1}'`
if [ $perms = "drwxr-xr-x." ]; then
pass "$check_3_16"
elif [ $perms = "drwx------" ]; then
pass "$check_3_16"
else
warn "$check_3_16"
warn " * Wrong permissions for $directory"
fi
else
info "$check_3_16"
info " * Directory not found"
fi
# 3.17
check_3_17="3.17 - Verify that registry certificate file ownership is set to root:root"
directory="/etc/docker/certs.d/"
if [ -d "$directory" ]; then
fail=0
owners=`ls -lL $directory/* | grep .crt | awk '{print $3, $4}'`
for p in $owners; do
printf "$p" | grep "root" >/dev/null 2>&1
if [ $? -ne 0 ]; then
fail=1
fi
done
if [ $fail -eq 1 ]; then
warn "$check_3_17"
warn " * Wrong ownership for $directory"
else
pass "$check_3_17"
fi
else
info "$check_3_17"
info " * Directory not found"
fi
# 3.18
check_3_18="3.18 - Verify that registry certificate file permissions are set to 444"
directory="/etc/docker/certs.d/"
if [ -d "$directory" ]; then
fail=0
perms=`ls -lL $directory/* | grep .crt | awk '{print $1}'`
for p in $perms; do
if test "$p" != "-rw-r--r--." && test "$p" = "-rw-------."; then
fail=1
fi
done
if [ $fail -eq 1 ]; then
warn "$check_3_18"
warn " * Wrong permissions for $directory"
else
pass "$check_3_18"
fi
else
info "$check_3_18"
info " * Directory not found"
fi
# 3.19
check_3_19="3.19 - Verify that TLS CA certificate file ownership is set to root:root"
tlscacert=`ps -ef | grep docker | sed -n 's/.*tlscacert=\([^s]\)/\1/p' | cut -d " " -f 1`
if [ -f "$tlscacert" ]; then
ls -ld "$tlscacert" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_19"
else
warn "$check_3_19"
warn " * Wrong ownership for $tlscacert"
fi
else
info "$check_3_19"
info " * No TLS CA certificate found"
fi
# 3.20
check_3_20="3.20 - Verify that TLS CA certificate file permissions are set to 444"
tlscacert=`ps -ef | grep docker | sed -n 's/.*tlscacert=\([^s]\)/\1/p' | cut -d " " -f 1`
if [ -f "$tlscacert" ]; then
perms=`ls -ld "$tlscacert" | awk '{print $1}'`
if test "$perms" = "-rw-r--r--"; then
pass "$check_3_20"
else
warn "$check_3_20"
warn " * Wrong permissions for $tlscacert"
fi
else
info "$check_3_20"
info " * No TLS CA certificate found"
fi
# 3.21
check_3_21="3.21 - Verify that Docker server certificate file ownership is set to root:root"
tlscert=`ps -ef | grep docker | sed -n 's/.*tlscert=\([^s]\)/\1/p' | cut -d " " -f 1`
if [ -f "$tlscert" ]; then
ls -ld "$tlscert" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_21"
else
warn "$check_3_21"
warn " * Wrong ownership for $tlscert"
fi
else
info "$check_3_21"
info " * No TLS Server certificate found"
fi
# 3.22
check_3_22="3.22 - Verify that Docker server certificate file permissions are set to 444"
tlscacert=`ps -ef | grep docker | sed -n 's/.*tlscert=\([^s]\)/\1/p' | cut -d " " -f 1`
if [ -f "$tlscert" ]; then
perms=`ls -ld "$tlscert" | awk '{print $1}'`
if test "$perms" = "-rw-r--r--"; then
pass "$check_3_22"
else
warn "$check_3_22"
warn " * Wrong permissions for $tlscert"
fi
else
info "$check_3_22"
info " * No TLS Server certificate found"
fi
# 3.23
check_3_23="3.23 - Verify that Docker server key file ownership is set to root:root"
tlskey=`ps -ef | grep docker | sed -n 's/.*tlskey=\([^s]\)/\1/p' | cut -d " " -f 1`
if [ -f "$tlskey" ]; then
ls -ld "$tlskey" | awk '{print $3, $4}' | grep "root root" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_23"
else
warn "$check_3_23"
warn " * Wrong ownership for $tlskey"
fi
else
info "$check_3_23"
info " * No TLS Key found"
fi
# 3.24
check_3_24="3.24 - Verify that Docker server key file permissions are set to 400"
tlskey=`ps -ef | grep docker | sed -n 's/.*tlskey=\([^s]\)/\1/p' | cut -d " " -f 1`
if [ -f "$tlskey" ]; then
perms=`ls -ld "$tlskey" | awk '{print $1}'`
if test "$perms" = "-r--------"; then
pass "$check_3_24"
else
warn "$check_3_24"
warn " * Wrong permissions for $tlskey"
fi
else
info "$check_3_24"
info " * No TLS Key found"
fi
# 3.25
check_3_25="3.25 - Verify that Docker socket file ownership is set to root:docker"
file="/var/run/docker.sock"
if [ -f "$file" ]; then
ls -ld "$file" | awk '{print $3, $4}' | grep "root docker" >/dev/null 2>&1
if [ $? -eq 0 ]; then
pass "$check_3_25"
else
warn "$check_3_25"
warn " * Wrong ownership for $file"
fi
else
info "$check_3_25"
info " * File not found"
fi
# 3.26
check_3_26="3.26 - Verify that Docker socket file permissions are set to 660"
file="/var/run/docker.sock"
if [ -f "$file" ]; then
perms=`ls -ld "$file" | awk '{print $1}'`
if test "$perms" = "srw-rw----"; then
pass "$check_3_26"
else
warn "$check_3_26"
warn " * Wrong permissions for $file"
fi
else
info "$check_3_26"
info " * File not found"
fi

View file

@ -0,0 +1,43 @@
#!/bin/sh
logit "\n"
info "4 - Container Images and Build Files"
# 4.1
check_4_1="4.1 - Create a user for the container"
containers=`docker ps -q`
# If container_users is empty, there are no running containers
if test "$containers" = ""; then
info "$check_4_1"
info " * No containers running"
else
# List all the running containers, ouput their ID and USER
containers=`docker ps -q | xargs docker inspect --format '{{ .Id }}:User={{.Config.User}}' 2>/dev/null`
# We have some containers running, set failure flag to 0. Check for Users.
fail=0
# Make the loop separator be a new-line in POSIX compliant fashion
set -f; IFS=$'
'
for c in $containers; do
user=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $user = "User=" || test $user = "User=<no value>"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_4_1"
warn " * Running as root: $container_id"
fail=1
else
warn " * Running as root: $container_id"
fi
fi
done
# We went through all the containers and found none running as root
if [ $fail -eq 0 ]; then
pass "$check_4_1"
fi
fi
# Make the loop separator go back to space
set +f; unset IFS

View file

@ -0,0 +1,499 @@
#!/bin/sh
logit "\n"
info "5 - Container Runtime"
# If containers is empty, there are no running containers
if test "$containers" = ""; then
info " * No containers running, skipping Section 5"
else
# List all running containers
containers=`docker ps -q`
# Make the loop separator be a new-line in POSIX compliant fashion
set -f; IFS=$'
'
# 5.1
check_5_1="5.1 - Verify AppArmor Profile, if applicable"
# List all the running containers, ouput their ID and AppArmorProfile
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:AppArmorProfile={{.AppArmorProfile }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
policy=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $policy = "AppArmorProfile=" || test $policy = "AppArmorProfile=<no value>"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_1"
warn " * No AppArmorProfile Found: $container_id"
fail=1
else
warn " * No AppArmorProfile Found: $container_id"
fi
fi
done
# We went through all the containers and found none without AppArmor
if [ $fail -eq 0 ]; then
pass "$check_5_1"
fi
# 5.2
check_5_2="5.2 - Verify SELinux security options, if applicable"
# List all the running containers, ouput their ID and SecurityOptions
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:SecurityOpt={{.HostConfig.SecurityOpt }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
policy=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $policy = "SecurityOpt=" || test $policy = "SecurityOpt=<no value>"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_2"
warn " * No SecurityOptions Found: $container_id"
fail=1
else
warn " * No SecurityOptions Found: $container_id"
fi
fi
done
# We went through all the containers and found none without SELinux
if [ $fail -eq 0 ]; then
pass "$check_5_2"
fi
# 5.3
check_5_3="5.3 - Verify that containers are running only a single main process"
# List all the running containers, ouput their Id
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
processes=`docker exec $c ps -el 2>/dev/null | wc -l | awk '{print $1}'`
if [ $processes -gt 5 ]; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_3"
warn " * Too many proccesses running: $container_id"
fail=1
else
warn " * Too many proccesses running: $container_id"
fi
fi
done
# We went through all the containers and found none with toom any processes
if [ $fail -eq 0 ]; then
pass "$check_5_3"
fi
# 5.4
check_5_4="5.4 - Restrict Linux Kernel Capabilities within containers"
# List all the running containers, ouput their ID and CapAdd
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:CapAdd={{ .HostConfig.CapAdd}}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
caps=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $caps != "CapAdd=" && test $caps != "CapAdd=<no value>"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_4"
warn " * Capabilities added: $caps to $container_id"
fail=1
else
warn " * Capabilities added: $caps to $container_id"
fi
fi
done
# We went through all the containers and found none with extra capabilities
if [ $fail -eq 0 ]; then
pass "$check_5_4"
fi
# 5.5
check_5_5="5.5 - Do not use privileged containers"
# List all the running containers, ouput their ID and privileged status
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:{{.HostConfig.Privileged }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
privileged=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $privileged = "true"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_5"
warn " * Container running in Privileged mode: $container_id"
fail=1
else
warn " * Container running in Privileged mode: $container_id"
fi
fi
done
# We went through all the containers and found no privileged containers
if [ $fail -eq 0 ]; then
pass "$check_5_5"
fi
# 5.6
check_5_6="5.6 - Do not mount sensitive host system directories on containers"
containers=`docker ps -q`
# List of sensitive directories to test for. Script uses new-lines as a separator
sensitive_dirs='/boot
/dev
/etc
/lib
/proc
/sys
/usr'
# List all the running containers, ouput their ID and R/W Volumes
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:{{ .VolumesRW }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
volumes=`printf "$c" | cut -d ":" -f 2-`
container_id=`printf "$c" | cut -d ":" -f 1`
sensitive=0
# Go over each directory in sensitive dir and see if they exist in the volumes
for v in $sensitive_dirs; do
if [ $sensitive -eq 0 ]; then
contains "$volumes" "$v:" && sensitive=1
fi
done
if [ $sensitive -eq 1 ]; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_6"
warn " * Container mounted with sensitive directory: $container_id"
fail=1
else
warn " * Container mounted with sensitive directory: $container_id"
fi
fi
done
# We went through all the containers and found none with sensitive mounts
if [ $fail -eq 0 ]; then
pass "$check_5_6"
fi
# 5.7
check_5_7="5.7 - Do not run ssh within containers"
# List all the running containers, ouput their Id
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
processes=`docker exec $c ps -el 2>/dev/null | grep sshd | wc -l | awk '{print $1}'`
if [ $processes -gt 1 ]; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_7"
warn " * Container running sshd: $container_id"
fail=1
else
warn " * Container running sshd: $container_id"
fi
fi
done
# We went through all the containers and found none with sshd
if [ $fail -eq 0 ]; then
pass "$check_5_7"
fi
# 5.8
check_5_8="5.8 - Do not map privileged ports within containers"
# List all the running containers, ouput their listening ports
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $containers; do
port=`docker port $c | awk '{print $1}' | cut -d '/' -f1`
if test "$port" != "" && [ $port -lt 1025 ]; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_8"
warn " * Privileged Port in use: $port"
fail=1
else
warn " * Privileged Port in use: $port"
fi
fi
done
# We went through all the containers and found no privileged ports
if [ $fail -eq 0 ]; then
pass "$check_5_8"
fi
# 5.10
check_5_10="5.10 - Do not use host network mode on container"
# List all the running containers, ouput their ID and network mode
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:NetworkMode={{.HostConfig.NetworkMode }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
mode=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $mode = "NetworkMode=host"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_10"
warn " * Container running with networking mode 'host': $container_id"
fail=1
else
warn " * Container running with networking mode 'host': $container_id"
fi
fi
done
# We went through all the containers and found no Network Mode host
if [ $fail -eq 0 ]; then
pass "$check_5_10"
fi
# 5.11
check_5_11="5.11 - Limit memory usage for container"
# List all the running containers, ouput their ID and memory limit
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:{{ .Config.Memory }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
# Make the loop separator be a new-line in POSIX compliant fashion
for c in $cont_inspect; do
memory=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $memory = "0"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_11"
warn " * Container running without memory restrictions: $container_id"
fail=1
else
warn " * Container running without memory restrictions: $container_id"
fi
fi
done
# We went through all the containers and found no lack of Memory restrictions
if [ $fail -eq 0 ]; then
pass "$check_5_11"
fi
# 5.12
check_5_12="5.12 - Set container CPU priority appropriately"
# List all the running containers, ouput their ID and CPU Shares
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:{{.Config.CpuShares }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
shares=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $shares = "0"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_12"
warn " * Container running without CPU restrictions: $container_id"
fail=1
else
warn " * Container running without CPU restrictions: $container_id"
fi
fi
done
# We went through all the containers and found no lack of CPUShare restrictions
if [ $fail -eq 0 ]; then
pass "$check_5_12"
fi
# 5.13
check_5_13="5.13 - Mount container's root filesystem as read only"
# List all the running containers, ouput their ID and status of ReadonlyRootfs
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:{{.HostConfig.ReadonlyRootfs }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
read_status=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $read_status = "false"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_13"
warn " * Container running with root FS mounted R/W: $container_id"
fail=1
else
warn " * Container running with root FS mounted R/W: $container_id"
fi
fi
done
# We went through all the containers and found no R/W FS mounts
if [ $fail -eq 0 ]; then
pass "$check_5_13"
fi
# 5.14
check_5_14="5.14 - Bind incoming container traffic to a specific host interface"
# List all the running containers, ouput the IP where ports are being bound
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $containers; do
ip=`docker port $c | awk '{print $3}' | cut -d ':' -f1`
if test "$ip" = "0.0.0.0"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_14"
warn " * Port being bound to wildcard IP: 0.0.0.0"
fail=1
else
warn " * Port being bound to wildcard IP: 0.0.0.0"
fi
fi
done
# We went through all the containers and found no ports bound to 0.0.0.0
if [ $fail -eq 0 ]; then
pass "$check_5_14"
fi
# 5.15
check_5_15="5.15 - Do not set the 'on-failure' container restart policy to always"
# List all the running containers, ouput their ID and Restart Policy Name
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:RestartPolicyName={{.HostConfig.RestartPolicy.Name }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
policy=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $policy = "RestartPolicyName=always"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_15"
warn " * Restart Policy set to always: $container_id"
fail=1
else
warn " * Restart Policy set to always: $container_id"
fi
fi
done
# We went through all the containers and found none with restart policy always
if [ $fail -eq 0 ]; then
pass "$check_5_15"
fi
# 5.16
check_5_16="5.16 - Do not share the host's process namespace"
# List all the running containers, ouput their ID and PidMode
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:PidMode={{.HostConfig.PidMode }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
mode=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $mode = "PidMode=host"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_16"
warn " * Host PID namespace being shared with: $container_id"
fail=1
else
warn " * Host PID namespace being shared with: $container_id"
fi
fi
done
# We went through all the containers and found none with PidMode as host
if [ $fail -eq 0 ]; then
pass "$check_5_16"
fi
# 5.17
check_5_17="5.17 - Do not share the host's IPC namespace"
# List all the running containers, ouput their ID and IpcMode
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:IpcMode={{.HostConfig.IpcMode }}'`
# We have some containers running, set failure flag to 0, set failure flag to 0
fail=0
for c in $cont_inspect; do
mode=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $mode = "IpcMode=host"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
warn "$check_5_17"
warn " * Host IPC namespace being shared with: $container_id"
fail=1
else
warn " * Host IPC namespace being shared with: $container_id"
fi
fi
done
# We went through all the containers and found none with IPCMode as host
if [ $fail -eq 0 ]; then
pass "$check_5_17"
fi
# 5.18
check_5_18="5.18 - Do not directly expose host devices to containers"
# List all the running containers, ouput their ID and host devices
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:Devices={{.HostConfig.Devices }}'`
fail=0
for c in $cont_inspect; do
mode=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $mode != "Devices=[]" && test $mode != "Devices=<no value>"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
info "$check_5_18"
info " * Container has devices exposed directly: $container_id"
fail=1
else
info " * Container has devices exposed directly: $container_id"
fi
fi
done
# We went through all the containers and found none with devices
if [ $fail -eq 0 ]; then
pass "$check_5_18"
fi
# 5.19
check_5_19="5.19 - Override default ulimit at runtime only if needed"
# List all the running containers, ouput their ID and host devices
cont_inspect=`docker ps -q | xargs docker inspect --format '{{ .Id }}:Ulimits={{.HostConfig.Ulimits }}'`
fail=0
for c in $cont_inspect; do
mode=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $mode = "Ulimits=" || test $mode = "Ulimits=<no value>"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
info "$check_5_19"
info " * Container no default ulimit override: $container_id"
fail=1
else
info " * Container no default ulimit override: $container_id"
fi
fi
done
# We went through all the containers and found none without Ulimits
if [ $fail -eq 0 ]; then
pass "$check_5_19"
fi
fi

View file

@ -0,0 +1,64 @@
#!/bin/sh
logit "\n"
info "6 - Docker Security Operations"
# 6.5
check_6_5="6.5 - Use a centralized and remote log collection service"
containers=`docker ps -q`
# If containers is empty, there are no running containers
if test "$containers" = ""; then
info "$check_6_5"
info " * No containers running"
else
# List all the running containers, ouput their ID and host devices
containers=`docker ps -q | xargs docker inspect --format '{{ .Id}}:{{ .Volumes }}'`
# We have some containers running, set failure flag to 0.
fail=0
# Make the loop separator be a new-line in POSIX compliant fashion
set -f; IFS=$'
'
for c in $containers; do
mode=`printf "$c" | cut -d ":" -f 2`
container_id=`printf "$c" | cut -d ":" -f 1`
if test $mode = "map[]"; then
# If it's the first container, fail the test
if [ $fail -eq 0 ]; then
info "$check_6_5"
info " * Container has no volumes, ensure centralized logging is enabled : $container_id"
fail=1
else
info " * Container has no volumes, ensure centralized logging is enabled : $container_id"
fi
fi
done
# Only alert if there are no volumes. If there are volumes, can't know if they
# are used for logs
fi
# Make the loop separator go back to space
set +f; unset IFS
# 6.6
check_6_6="6.6 - Avoid image sprawl"
images=`docker images | wc -l | awk '{print $1}'`
if [ $images -gt 200 ]; then
warn "$check_6_6"
warn " * There are currently: $images images"
else
info "$check_6_6"
info " * There are currently: $images images"
fi
# 6.7
check_6_7="6.7 - Avoid container sprawl"
total_containers=`docker info 2>/dev/null | grep "Containers" | awk '{print $2}'`
running_containers=`docker ps -q | wc -l | awk '{print $1}'`
diff=`expr "$total_containers" - "$running_containers"`
if [ $diff -gt 25 ]; then
warn "$check_6_7"
warn " * There are currently a total of $total_containers containers, with only $running_containers of them currently running"
else
info "$check_6_7"
info " * There are currently a total of $total_containers containers, with $running_containers of them currently running"
fi