diff --git a/Dockerfile b/Dockerfile index 10f9f0ff..61ea4dce 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.18@sha256:eece025e432126ce23f223450a0326fbebde39cdf496a85d8c016293fc851978 +FROM alpine:3@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1 LABEL \ org.label-schema.name="docker-bench-security" \ @@ -6,9 +6,10 @@ LABEL \ org.label-schema.vcs-url="https://github.com/docker/docker-bench-security.git" RUN apk add --no-cache iproute2 \ - docker-cli \ - dumb-init \ - jq + docker-cli \ + dumb-init \ + jq \ + bash COPY . /usr/local/bin/ @@ -16,5 +17,5 @@ HEALTHCHECK CMD exit 0 WORKDIR /usr/local/bin -ENTRYPOINT [ "/usr/bin/dumb-init", "/bin/sh", "docker-bench-security.sh" ] +ENTRYPOINT [ "/usr/bin/dumb-init", "/bin/bash", "docker-bench-security.sh" ] CMD [""] diff --git a/README.md b/README.md index dd3e73e4..0ee953c0 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,19 @@ ![Docker Bench for Security running](img/benchmark_log.png) -The Docker Bench for Security is a script that checks for dozens of common best-practices around deploying Docker containers in production. The tests are all automated, and are based on the [CIS Docker Benchmark v1.6.0](https://www.cisecurity.org/benchmark/docker/). +The Docker Bench for Security is a script that checks for dozens of common best-practices around deploying Docker containers in production. The tests are all automated, and are based on the [CIS Docker Benchmark v1.8.0](https://www.cisecurity.org/benchmark/docker/). 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. -Release | CIS | -:---:|:---:| -1.6.0|1.6.0| -1.5.0|1.5.0| -1.3.6|1.4.0| -1.3.5|1.2.0| -1.3.3|1.1.0| -1.3.0|1.13.0| +| Release | CIS | +| :-----: | :----: | +| 1.8.0 | 1.8.0 | +| 1.6.0 | 1.6.0 | +| 1.5.0 | 1.5.0 | +| 1.3.6 | 1.4.0 | +| 1.3.5 | 1.2.0 | +| 1.3.3 | 1.1.0 | +| 1.3.0 | 1.13.0 | ## Running Docker Bench for Security @@ -24,7 +25,7 @@ You can simply run this script from your base host by running: ```sh git clone https://github.com/docker/docker-bench-security.git cd docker-bench-security -sudo sh docker-bench-security.sh +sudo bash docker-bench-security.sh ``` > Note: [`jq`](https://jqlang.github.io/jq/) is an optional but recommended dependency. @@ -126,8 +127,36 @@ Note that when distributions don't contain `auditctl`, the audit tests will chec -x EXCLUDE optional Comma delimited list of patterns within a container or image name to exclude from check -t LABEL optional Comma delimited list of labels within a container or image to check -n LIMIT optional In JSON output, when reporting lists of items (containers, images, etc.), limit the number of reported items to LIMIT. Default 0 (no limit). - -p PRINT optional Disable the printing of remediation measures. Default: print remediation measures. + -p PRINT optional Print remediation measures. Default: Don't print remediation measures. ``` +Subsets of tests available : +- cis + - host_configuration + - docker_daemon_configuration + - docker_daemon_files + - container_images + - container_runtime + - docker_security_operations + - docker_swarm_configuration +- cis_level1 + - host_configuration_level1 + - docker_daemon_configuration_level1 + - docker_daemon_files_level1 + - container_images_level1 + - container_runtime_level1 + - docker_security_operations_level1 + - docker_swarm_configuration_level1 +- cis_controls_v8_ig1 +- cis_controls_v8_ig2 +- cis_controls_v8_ig3 +- docker_enterprise_configuration + - docker_enterprise_configuration_level1 +- docker_trusted_registry_configuration +- universal_control_plane_configuration +- community + - community_checks +- all + By default the Docker Bench for Security script will run all available CIS tests and produce logs in the log folder from current directory, named `docker-bench-security.log.json` and @@ -137,16 +166,16 @@ If the docker container is used then the log files will be created inside the co The CIS based checks are named `check_
_`, e.g. `check_2_6` and community contributed checks are named `check_c_`. -`sh docker-bench-security.sh -c check_2_2` will only run check `2.2 Ensure the logging level is set to 'info'`. +`bash docker-bench-security.sh -c check_2_2` will only run check `2.2 Ensure the logging level is set to 'info'`. -`sh docker-bench-security.sh -e check_2_2` will run all available checks except `2.2 Ensure the logging level is set to 'info'`. +`bash docker-bench-security.sh -e check_2_2` will run all available checks except `2.2 Ensure the logging level is set to 'info'`. -`sh docker-bench-security.sh -e docker_enterprise_configuration` will run all available checks except the docker_enterprise_configuration group +`bash docker-bench-security.sh -e docker_enterprise_configuration` will run all available checks except the docker_enterprise_configuration group -`sh docker-bench-security.sh -e docker_enterprise_configuration,check_2_2` will run all available checks except the docker_enterprise_configuration group and `2.2 Ensure the logging level is set to 'info'` +`bash docker-bench-security.sh -e docker_enterprise_configuration,check_2_2` will run all available checks except the docker_enterprise_configuration group and `2.2 Ensure the logging level is set to 'info'` -`sh docker-bench-security.sh -c container_images,container_runtime` will run just the container_images and container_runtime checks +`bash docker-bench-security.sh -c container_images,container_runtime` will run just the container_images and container_runtime checks -`sh docker-bench-security.sh -c container_images -e check_4_5` will run just the container_images checks except `4.5 Ensure Content trust for Docker is Enabled` +`bash docker-bench-security.sh -c container_images -e check_4_5` will run just the container_images checks except `4.5 Ensure Content trust for Docker is Enabled` Note that when submitting checks, provide information why it is a reasonable test to add and please include some kind of official documentation verifying that information. diff --git a/docker-bench-security.sh b/docker-bench-security.sh index d4041a8d..864acbaf 100755 --- a/docker-bench-security.sh +++ b/docker-bench-security.sh @@ -7,7 +7,7 @@ # Checks for dozens of common best-practices around deploying Docker containers in production. # -------------------------------------------------------------------------------------------- -version='1.6.0' +version='1.8.0' LIBEXEC="." # Distributions can change this to /usr/libexec or similar. @@ -38,17 +38,17 @@ usage () { cat </dev/null 2>&1; then if auditctl -l | grep "$file" >/dev/null 2>&1; then diff --git a/tests/2_docker_daemon_configuration.sh b/tests/2_docker_daemon_configuration.sh index 000381fd..b8198026 100644 --- a/tests/2_docker_daemon_configuration.sh +++ b/tests/2_docker_daemon_configuration.sh @@ -128,7 +128,7 @@ check_2_6() { local id="2.6" local desc="Ensure aufs storage driver is not used (Scored)" local remediation="Do not start Docker daemon as using dockerd --storage-driver aufs option." - local remediationImpact="aufs is the only storage driver that allows containers to share executable and shared library memory. Its use should be reviewed in line with your organization's security policy." + local remediationImpact="aufs is the only storage driver that allows containers to share executable and shared library memory. Its use should be reviewed in line with your organization's security policy." local check="$id - $desc" starttestjson "$id" "$desc" @@ -143,13 +143,30 @@ check_2_6() { check_2_7() { local id="2.7" + local desc="Ensure devicemapper storage driver is not used (Scored)" + local remediation="Do not start Docker daemon as using dockerd --storage-driver devicemapper option." + local remediationImpact="If you are using Device Mapper, you must migrate to a supported storage driver before upgrading to Docker Engine v25.0., it has been removed in Docker Engine v25.0" + local check="$id - $desc" + starttestjson "$id" "$desc" + + if docker info 2>/dev/null | grep -e "^\sStorage Driver:\s*devicemapper\s*$" >/dev/null 2>&1; then + warn -s "$check" + logcheckresult "WARN" + return + fi + pass -s "$check" + logcheckresult "PASS" +} + +check_2_8() { + local id="2.8" local desc="Ensure TLS authentication for Docker daemon is configured (Scored)" local remediation="Follow the steps mentioned in the Docker documentation or other references. By default, TLS authentication is not configured." local remediationImpact="You would need to manage and guard certificates and keys for the Docker daemon and Docker clients." local check="$id - $desc" starttestjson "$id" "$desc" - if $(grep -qE "host.*tcp://" "$CONFIG_FILE") || \ + if $(grep -qE "host.*tcp://" "$CONFIG_FILE") || \ [ $(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 @@ -174,8 +191,8 @@ check_2_7() { logcheckresult "INFO" "Docker daemon not listening on TCP" } -check_2_8() { - local id="2.8" +check_2_9() { + local id="2.9" local desc="Ensure the default ulimit is configured appropriately (Manual)" local remediation="Run Docker in daemon mode and pass --default-ulimit as option with respective ulimits as appropriate in your environment and in line with your security policy. Example: dockerd --default-ulimit nproc=1024:2048 --default-ulimit nofile=100:200" local remediationImpact="If ulimits are set incorrectly this could cause issues with system resources, possibly causing a denial of service condition." @@ -197,8 +214,8 @@ check_2_8() { logcheckresult "INFO" "Default ulimit doesn't appear to be set" } -check_2_9() { - local id="2.9" +check_2_10() { + local id="2.10" local desc="Enable user namespace support (Scored)" local remediation="Please consult the Docker documentation for various ways in which this can be configured depending upon your requirements. The high-level steps are: Ensure that the files /etc/subuid and /etc/subgid exist. Start the docker daemon with --userns-remap flag." local remediationImpact="User namespace remapping is incompatible with a number of Docker features and also currently breaks some of its functionalities." @@ -219,8 +236,8 @@ check_2_9() { logcheckresult "WARN" } -check_2_10() { - local id="2.10" +check_2_11() { + local id="2.11" local desc="Ensure the default cgroup usage has been confirmed (Scored)" local remediation="The default setting is in line with good security practice and can be left in situ." local remediationImpact="None." @@ -243,8 +260,8 @@ check_2_10() { logcheckresult "PASS" } -check_2_11() { - local id="2.11" +check_2_12() { + local id="2.12" local desc="Ensure base device size is not changed until needed (Scored)" local remediation="Do not set --storage-opt dm.basesize until needed." local remediationImpact="None." @@ -265,8 +282,8 @@ check_2_11() { logcheckresult "PASS" } -check_2_12() { - local id="2.12" +check_2_13() { + local id="2.13" local desc="Ensure that authorization for Docker client commands is enabled (Scored)" local remediation="Install/Create an authorization plugin. Configure the authorization policy as desired. Start the docker daemon using command dockerd --authorization-plugin=" local remediationImpact="Each Docker command needs to pass through the authorization plugin mechanism. This may have a performance impact" @@ -287,8 +304,8 @@ check_2_12() { logcheckresult "WARN" } -check_2_13() { - local id="2.13" +check_2_14() { + local id="2.14" local desc="Ensure centralized and remote logging is configured (Scored)" local remediation="Set up the desired log driver following its documentation. Start the docker daemon using that logging driver. Example: dockerd --log-driver=syslog --log-opt syslog-address=tcp://192.xxx.xxx.xxx" local remediationImpact="None." @@ -304,8 +321,8 @@ check_2_13() { logcheckresult "PASS" } -check_2_14() { - local id="2.14" +check_2_15() { + local id="2.15" local desc="Ensure containers are restricted from acquiring new privileges (Scored)" local remediation="You should run the Docker daemon using command: dockerd --no-new-privileges" local remediationImpact="no_new_priv prevents LSMs such as SELinux from escalating the privileges of individual containers." @@ -326,8 +343,8 @@ check_2_14() { logcheckresult "WARN" } -check_2_15() { - local id="2.15" +check_2_16() { + local id="2.16" local desc="Ensure live restore is enabled (Scored)" local remediation="Run Docker in daemon mode and pass --live-restore option." local remediationImpact="None." @@ -353,8 +370,8 @@ check_2_15() { logcheckresult "WARN" } -check_2_16() { - local id="2.16" +check_2_17() { + local id="2.17" local desc="Ensure Userland Proxy is Disabled (Scored)" local remediation="You should run the Docker daemon using command: dockerd --userland-proxy=false" local remediationImpact="Some systems with older Linux kernels may not be able to support hairpin NAT and therefore require the userland proxy service. Also, some networking setups can be impacted by the removal of the userland proxy." @@ -375,8 +392,8 @@ check_2_16() { logcheckresult "WARN" } -check_2_17() { - local id="2.17" +check_2_18() { + local id="2.18" local desc="Ensure that a daemon-wide custom seccomp profile is applied if appropriate (Manual)" local remediation="By default, Docker's default seccomp profile is applied. If this is adequate for your environment, no action is necessary." local remediationImpact="A misconfigured seccomp profile could possibly interrupt your container environment. You should therefore exercise extreme care if you choose to override the default settings." @@ -392,11 +409,11 @@ check_2_17() { logcheckresult "INFO" } -check_2_18() { +check_2_19() { docker_version=$(docker version | grep -i -A2 '^server' | grep ' Version:' \ | awk '{print $NF; exit}' | tr -d '[:alpha:]-,.' | cut -c 1-4) - local id="2.18" + local id="2.19" local desc="Ensure that experimental features are not implemented in production (Scored)" local remediation="You should not pass --experimental as a runtime parameter to the Docker daemon on production systems." local remediationImpact="None." diff --git a/tests/5_container_runtime.sh b/tests/5_container_runtime.sh index 93ee77f5..ee8acf0d 100644 --- a/tests/5_container_runtime.sh +++ b/tests/5_container_runtime.sh @@ -615,22 +615,24 @@ check_5_15() { container_name=$(docker inspect "$c" --format '{{.Name}}') if [ "$(docker info --format '{{.Swarm.LocalNodeState}}')" = "active" ]; then for s in $(docker service ls --format '{{.Name}}'); do - if echo $container_name | grep -q "$s"; then + if echo "$container_name" | grep -q "$s"; then task_id=$(docker inspect "$c" --format '{{.Name}}' | awk -F '.' '{print $NF}') # a container name could arbitrary include a service one: it belongs to a service (created by Docker # as part of the service), if the container task ID matches one of the task IDs of the service. if docker service ps --no-trunc "$s" --format '{{.ID}}' | grep -q "$task_id"; then - restart_policy=$(docker inspect --format '{{ .Spec.TaskTemplate.RestartPolicy.MaxAttempts }}' "$s") + maxAttempts=$(docker inspect --format '{{ .Spec.TaskTemplate.RestartPolicy.MaxAttempts }}' "$s") + restart_policy=$(docker inspect --format '{{ .Spec.TaskTemplate.RestartPolicy.Name }}' "$s") break fi fi done fi if docker inspect --format '{{ .HostConfig.RestartPolicy.MaximumRetryCount }}' "$c" &>/dev/null; then - restart_policy=$(docker inspect --format '{{ .HostConfig.RestartPolicy.MaximumRetryCount }}' "$c") + maxAttempts=$(docker inspect --format '{{ .HostConfig.RestartPolicy.MaximumRetryCount }}' "$c") + restart_policy=$(docker inspect --format '{{ .HostConfig.RestartPolicy.Name }}' "$c") fi - if [ "$restart_policy" -gt "5" ]; then + if [ "$maxAttempts" -gt "5" ] || [ "$restart_policy" != "on-failure" ]; then # If it's the first container, fail the test if [ $fail -eq 0 ]; then warn -s "$check"