From a91d99164f915cee0ff10041214c47cf07cdd2ec Mon Sep 17 00:00:00 2001 From: Alexei Ledenev Date: Fri, 13 May 2016 18:20:50 +0300 Subject: [PATCH] Implemented tests for CIS 3.x section --- README.md | 2 +- bats.Dockerfile | 34 +++ test/1_host_configuration.bats | 25 +- test/2_docker_daemon_configuration.bats | 2 +- test/3_docker_daemon_configuration_files.bats | 223 ++++++++++++++++++ 5 files changed, 274 insertions(+), 12 deletions(-) create mode 100644 bats.Dockerfile create mode 100644 test/3_docker_daemon_configuration_files.bats diff --git a/README.md b/README.md index 8689545..38ffd23 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ docker run -it --net host --pid host --cap-add audit_control \ Docker bench requires Docker 1.6.2 or later in order to run, since it depends on the `--label` to exclude the current container from being inspected. If you can't upgrade to 1.6.2, feel free to remove the `--label` flag or run the shell script locally (see below). -Additionally, there was a bug in Docker 1.6.0 that would not allow mounting `-v /dev:/dev`. If you are getting an error while accessing `resolv.conf`, please update your docker to 1.6.2. +Additionally, there was a bug in Docker 1.6.0 that would not allow mounting `-v /dev:/dev`. If you are getting an error while accessing `resolv.conf`, please update your docker to 1.6.2. Also note that the default image and `Dockerfile` uses `FROM: alpine` which doesn't contain `auditctl`, this will generate errors in section 1.8 to 1.18. Distribution specific Dockerfiles that fixes this issue are available in the [distros directory](https://github.com/docker/docker-bench-security/tree/master/distros). ## Building Docker Bench for Security diff --git a/bats.Dockerfile b/bats.Dockerfile new file mode 100644 index 0000000..376746a --- /dev/null +++ b/bats.Dockerfile @@ -0,0 +1,34 @@ +# REPOSITORY https://github.com/docker/docker-bench-securit +FROM alpine:3.3 + +MAINTAINER dockerbench.com +MAINTAINER Alexei Ledenev + +ENV VERSION 1.10.0 +ENV BATS_VERSION 0.4.0 + +WORKDIR /usr/bin + +RUN apk update && \ + apk upgrade && \ + apk --update add curl bash && \ + curl -sS https://get.docker.com/builds/Linux/x86_64/docker-$VERSION > docker-$VERSION && \ + curl -sS https://get.docker.com/builds/Linux/x86_64/docker-$VERSION.sha256 > docker-$VERSION.sha256 && \ + sha256sum -c docker-$VERSION.sha256 && \ + ln -s docker-$VERSION docker && \ + chmod u+x docker-$VERSION && \ + rm -rf /var/cache/apk/* + +RUN curl -o "/tmp/v${BATS_VERSION}.tar.gz" -L \ + "https://github.com/sstephenson/bats/archive/v${BATS_VERSION}.tar.gz" \ + && tar -x -z -f "/tmp/v${BATS_VERSION}.tar.gz" -C /tmp/ \ + && bash "/tmp/bats-${BATS_VERSION}/install.sh" /usr/local \ + && rm -rf /tmp/* + +RUN mkdir /docker-bench-security + +COPY . /docker-bench-security + +WORKDIR /docker-bench-security + +ENTRYPOINT ["/usr/local/bin/bats", "/docker-bench-security/test"] diff --git a/test/1_host_configuration.bats b/test/1_host_configuration.bats index dfa283d..62ad15b 100644 --- a/test/1_host_configuration.bats +++ b/test/1_host_configuration.bats @@ -21,8 +21,13 @@ load "$BATS_TEST_DIRNAME/../helper_lib.sh" @test "1.4 - 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 -c LISTEN) - refute [ "$listening_services" -eq 0 ] "1.4 - Failed to get listening services for check: $BATS_TEST_NAME" - refute [ "$listening_services" -gt 5 ] "Host listening on: $listening_services ports" + if [ "$listening_services" -eq 0 ]; then + fail "Failed to get listening services for check: $BATS_TEST_NAME" + else + if [ "$listening_services" -gt 5 ]; then + fail "Host listening on: $listening_services ports" + fi + fi } # 1.5 @@ -68,7 +73,7 @@ load "$BATS_TEST_DIRNAME/../helper_lib.sh" # 1.8 @test "1.8 - Audit Docker files and directories - /var/lib/docker" { directory="/var/lib/docker" - refute [ -d "$directory" ] "'$directory' Directory not found" + assert [ -d "$directory" ] run command -v auditctl >/dev/null assert_success run auditctl -l | grep $directory @@ -78,7 +83,7 @@ load "$BATS_TEST_DIRNAME/../helper_lib.sh" # 1.9 @test "1.9 - Audit Docker files and directories - /etc/docker" { directory="/etc/docker" - refute [ -d "$directory" ] "'$directory' Directory not found" + assert [ -d "$directory" ] run command -v auditctl assert_success run auditctl -l | grep $directory @@ -88,7 +93,7 @@ load "$BATS_TEST_DIRNAME/../helper_lib.sh" # 1.10 @test "1.10 - Audit Docker files and directories - docker.service" { file="$(get_systemd_service_file docker.service)" - refute [ -f "$file" ] "'docker.service' file not found" + assert [ -f "$file" ] run command -v auditctl assert_success run auditctl -l | grep "$file" @@ -98,7 +103,7 @@ load "$BATS_TEST_DIRNAME/../helper_lib.sh" # 1.11 @test "1.11 - Audit Docker files and directories - docker.socket" { file="$(get_systemd_service_file docker.socket)" - refute [ -e "$file" ] "'docker.socket' file not found" + assert [ -e "$file" ] run command -v auditctl assert_success run auditctl -l | grep "$file" @@ -108,7 +113,7 @@ load "$BATS_TEST_DIRNAME/../helper_lib.sh" # 1.12 @test "1.12 - Audit Docker files and directories - /etc/default/docker" { file="/etc/default/docker" - refute [ -f "$file" ] "'$file' file not found" + assert [ -f "$file" ] run command -v auditctl assert_success run auditctl -l | grep $file @@ -118,7 +123,7 @@ load "$BATS_TEST_DIRNAME/../helper_lib.sh" # 1.13 @test "1.13 - Audit Docker files and directories - /etc/docker/daemon.json" { file="/etc/docker/daemon.json" - refute [ -f "$file" ] "'$file' file not found" + assert [ -f "$file" ] run command -v auditctl assert_success run auditctl -l | grep $file @@ -128,7 +133,7 @@ load "$BATS_TEST_DIRNAME/../helper_lib.sh" # 1.14 @test "1.14 - Audit Docker files and directories - /usr/bin/docker-containerd" { file="/usr/bin/docker-containerd" - refute [ -f "$file" ] "'$file' file not found" + assert [ -f "$file" ] run command -v auditctl assert_success run auditctl -l | grep $file @@ -138,7 +143,7 @@ load "$BATS_TEST_DIRNAME/../helper_lib.sh" # 1.15 @test "1.15 - Audit Docker files and directories - /usr/bin/docker-runc" { file="/usr/bin/docker-runc" - refute [ -f "$file" ] "'$file' file not found" + assert [ -f "$file" ] run command -v auditctl assert_success run auditctl -l | grep $file diff --git a/test/2_docker_daemon_configuration.bats b/test/2_docker_daemon_configuration.bats index 776c500..de46c62 100644 --- a/test/2_docker_daemon_configuration.bats +++ b/test/2_docker_daemon_configuration.bats @@ -69,7 +69,7 @@ load "$BATS_TEST_DIRNAME/../helper_lib.sh" result=$(get_docker_effective_command_line_args '--cgroup-parent') run grep "cgroup-parent" <<< "$result" if [ $status -eq 0 ]; then - refute_output_contains "docker" + assert_output_contains "docker" fi } diff --git a/test/3_docker_daemon_configuration_files.bats b/test/3_docker_daemon_configuration_files.bats new file mode 100644 index 0000000..de99861 --- /dev/null +++ b/test/3_docker_daemon_configuration_files.bats @@ -0,0 +1,223 @@ +#!/usr/bin/env bats + +load "test_helper/bats-support/load" +load "test_helper/bats-assert/load" +load "$BATS_TEST_DIRNAME/../helper_lib.sh" + +# 3.1 +@test "3.1 - Verify that docker.service file ownership is set to root:root" { + file="$(get_systemd_service_file docker.service)" + if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -ne 00 ]; then + fail "Wrong ownership for $file" + fi + fi +} + +# 3.2 +@test "3.2 - Verify that docker.service file permissions are set to 644" { + file="$(get_systemd_service_file docker.service)" + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -ne 644 ]; then + fail "Wrong permissions for $file" + fi + fi +} + +# 3.3 +@test "3.3 - Verify that docker.socket file ownership is set to root:root" { + file="$(get_systemd_service_file docker.socket)" + if [ -f "$file" ]; then + if [ "$(stat -c %u%g $file)" -ne 00 ]; then + fail "Wrong ownership for $file" + fi + fi +} + +# 3.4 +@test "3.4 - Verify that docker.socket file permissions are set to 644" { + file="$(get_systemd_service_file docker.socket)" + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -ne 644 ]; then + fail "Wrong permissions for $file" + fi + fi +} + +# 3.5 +@test "3.5 - Verify that /etc/docker directory ownership is set to root:root" { + directory="/etc/docker" + if [ -d "$directory" ]; then + if [ "$(stat -c %u%g $directory)" -ne 00 ]; then + fail "Wrong ownership for $directory" + fi + fi +} + +# 3.6 +@test "3.6 - Verify that /etc/docker directory permissions are set to 755 or 700" { + directory="/etc/docker" + if [ -d "$directory" ]; then + if [ "$(stat -c %a $directory)" -ne 755 -a "$(stat -c %a $directory)" -ne 700 ]; then + fail "Wrong permissions for $directory : $(stat -c %a $directory)" + fi + fi +} + +# 3.7 +@test "3.7 - 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 "%s" "$p" | grep "root" >/dev/null 2>&1 + if [ $? -ne 0 ]; then + fail=1 + fi + done + if [ $fail -eq 1 ]; then + fail "Wrong ownership for $directory" + fi + fi +} + +# 3.8 +@test "3.8 - 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 [ "$p" != "-r--r--r--." -a "$p" = "-r--------." ]; then + fail=1 + fi + done + if [ $fail -eq 1 ]; then + fail "Wrong permissions for $directory" + fi + fi +} + +# 3.9 +@test "3.9 - Verify that TLS CA certificate file ownership is set to root:root" { + tlscacert=$(get_docker_effective_command_line_args '--tlscacert' | sed -n 's/.*tlscacert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -f "$tlscacert" ]; then + if [ "$(stat -c %u%g "$tlscacert")" -ne 00 ]; then + fail "Wrong ownership for $tlscacert : $(stat -c %u%g "$tlscacert")" + fi + fi +} + +# 3.10 +@test "3.10 - Verify that TLS CA certificate file permissions are set to 444" { + tlscacert=$(get_docker_effective_command_line_args '--tlscacert' | sed -n 's/.*tlscacert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -f "$tlscacert" ]; then + perms=$(ls -ld "$tlscacert" | awk '{print $1}') + if [ "$perms" != "-r--r--r--" ]; then + fail "Wrong permissions for $tlscacert" + fi + fi +} + +# 3.11 +@test "3.11 - Verify that Docker server certificate file ownership is set to root:root" { + tlscert=$(get_docker_effective_command_line_args '--tlscert' | sed -n 's/.*tlscert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -f "$tlscert" ]; then + if [ "$(stat -c %u%g "$tlscert")" -ne 00 ]; then + fail "Wrong ownership for $tlscert : $(stat -c %u%g "$tlscert")" + fi + fi +} + +# 3.12 +@test "3.12 - Verify that Docker server certificate file permissions are set to 444" { + tlscert=$(get_docker_effective_command_line_args '--tlscert' | sed -n 's/.*tlscert=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -f "$tlscert" ]; then + perms=$(ls -ld "$tlscert" | awk '{print $1}') + if [ "$perms" != "-r--r--r--" ]; then + fail "Wrong permissions for $tlscert" + fi + fi +} + +# 3.13 +@test "3.13 - Verify that Docker server key file ownership is set to root:root" { + tlskey=$(get_docker_effective_command_line_args '--tlskey' | sed -n 's/.*tlskey=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -f "$tlskey" ]; then + if [ "$(stat -c %u%g "$tlskey")" -ne 00 ]; then + fail "Wrong ownership for $tlskey : $(stat -c %u%g "$tlskey")" + fi + fi +} + +# 3.14 +@test "3.14 - Verify that Docker server key file permissions are set to 400" { + tlskey=$(get_docker_effective_command_line_args '--tlskey' | sed -n 's/.*tlskey=\([^s]\)/\1/p' | sed 's/--/ --/g' | cut -d " " -f 1) + if [ -f "$tlskey" ]; then + perms=$(ls -ld "$tlskey" | awk '{print $1}') + if [ "$perms" != "-r--------" ]; then + fail "Wrong permissions for $tlskey" + fi + fi +} + +# 3.15 +@test "3.15 - Verify that Docker socket file ownership is set to root:docker" { + file="/var/run/docker.sock" + if [ -S "$file" ]; then + if [ "$(stat -c %U:%G $file)" != 'root:docker' ]; then + fail "Wrong ownership for $file" + fi + fi +} + +# 3.16 +@test "3.16 - Verify that Docker socket file permissions are set to 660" { + file="/var/run/docker.sock" + if [ -S "$file" ]; then + if [ "$(stat -c %a $file)" -ne 660 ]; then + fail "Wrong permissions for $file" + fi + fi +} + +# 3.17 +@test "3.17 - Verify that daemon.json file ownership is set to root:root" { + file="/etc/docker/daemon.json" + if [ -f "$file" ]; then + if [ "$(stat -c %U:%G $file)" != 'root:root' ]; then + fail "Wrong ownership for $file" + fi + fi +} + +# 3.18 +@test "3.18 - Verify that daemon.json file permissions are set to 644" { + file="/etc/docker/daemon.json" + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -ne 644 ]; then + fail "Wrong permissions for $file" + fi + fi +} + +# 3.19 +@test "3.19 - Verify that /etc/default/docker file ownership is set to root:root" { + file="/etc/default/docker" + if [ -f "$file" ]; then + if [ "$(stat -c %U:%G $file)" != 'root:root' ]; then + fail "Wrong ownership for $file" + fi + fi +} + +# 3.20 +@test "3.20 - Verify that /etc/default/docker file permissions are set to 644" { + file="/etc/default/docker" + if [ -f "$file" ]; then + if [ "$(stat -c %a $file)" -ne 644 ]; then + fail "Wrong permissions for $file" + fi + fi +}