Scanning Docker infrastructure against CIS Benchmark with Wazuh

| by | Wazuh 4.9.0
Post icon

Docker has revolutionized the way to deploy applications, offering scalability, consistency, and efficiency. However, these benefits come with security challenges that must be addressed to protect your infrastructure. The Center for Internet Security (CIS) Docker Benchmark provides a comprehensive set of guidelines to secure Docker environments. This blog post shows how to automate the compliance checks against CIS Docker Benchmark v1.7.0 using the Wazuh Security Configuration Assessment (SCA) capability.

Relevance of the CIS Benchmarks for Docker

The CIS Docker Benchmarks are a set of best practices developed by security experts to secure Docker containers and hosts. These guidelines cover various aspects, including Docker daemon configuration, container images, and Docker runtime security. Adhering to these benchmarks helps organizations mitigate risks associated with containerized environments, such as unauthorized access, privilege escalation, and data breaches.

As Docker becomes increasingly used for modern application development and deployment, ensuring compliance with the CIS Docker Benchmark is important. By implementing these guidelines, you can significantly reduce the attack surface of your containerized applications and infrastructure.

Automating compliance checks with Wazuh SCA

Wazuh offers a Security Configuration Assessment (SCA) module that allows you to automate the process of checking your Docker environment against the CIS Docker Benchmark. With Wazuh, you can continuously monitor your Docker hosts and containers for compliance, receive alerts when configurations deviate from the benchmark, and generate reports to demonstrate adherence to security standards.

In this blog post, we share an SCA policy configuration file that checks for the following 98 CIS Docker Benchmark requirements:

1. Host configuration

  • 1.1.1: Ensure a separate partition for containers has been created.
  • 1.1.3: Ensure auditing is configured for the Docker daemon.
  • 1.1.4: Ensure auditing is configured for Docker files and directories – /run/containerd.
  • 1.1.5: Ensure auditing is configured for Docker files and directories – /var/lib/docker.
  • 1.1.6: Ensure auditing is configured for Docker files and directories – /etc/docker.
  • 1.1.7: Ensure auditing is configured for Docker files and directories – docker.service.
  • 1.1.8: Ensure auditing is configured for Docker files and directories – containerd.sock.
  • 1.1.9: Ensure auditing is configured for Docker files and directories – docker.socket.
  • 1.1.10: Ensure auditing is configured for Docker files and directories – /etc/default/docker.
  • 1.1.11: Ensure auditing is configured for Docker files and directories –  /etc/docker/daemon.json.
  • 1.1.12: Ensure auditing is configured for Docker files and directories – /etc/containerd/config.toml.
  • 1.1.13: Ensure auditing is configured for Docker files and directories – /etc/sysconfig/docker.
  • 1.1.14: Ensure auditing is configured for Docker files and directories – /usr/bin/containerd.
  • 1.1.15: Ensure auditing is configured for Docker files and directories – /usr/bin/containerd-shim.
  • 1.1.16: Ensure auditing is configured for Docker files and directories – /usr/bin/containerd-shim-runc-v1.
  • 1.1.17: Ensure auditing is configured for Docker files and directories – /usr/bin/containerd-shim-runc-v2.
  • 1.1.18: Ensure auditing is configured for Docker files and directories – /usr/bin/runc.

2. Docker daemon configuration

  • 2.1: Run the Docker daemon as a non-root user, if possible.
  • 2.2: Ensure network traffic is restricted between containers on the default bridge.
  • 2.3: Ensure the logging level is set to “info”.
  • 2.4: Ensure Docker is allowed to make changes to iptables.
  • 2.5: Ensure insecure registries are not used.
  • 2.6: Ensure aufs storage driver is not used.
  • 2.7: Ensure TLS authentication for Docker daemon is configured.
  • 2.8: Ensure the default ulimit is configured appropriately.
  • 2.9: Enable user namespace support.
  • 2.10: Ensure the default cgroup usage has been confirmed.
  • 2.11: Ensure base device size is not changed until needed.
  • 2.12: Ensure that authorization for Docker client commands is enabled.
  • 2.13: Ensure centralized and remote logging is configured.
  • 2.14: Ensure containers are restricted from acquiring new privileges.
  • 2.15: Ensure live restore is enabled.
  • 2.16: Ensure Userland Proxy is Disabled.
  • 2.17: Ensure that a daemon-wide custom seccomp profile is applied if appropriate.
  • 2.18: Ensure that experimental features are not implemented in production.

3. Docker daemon configuration files

  • 3.1: Ensure that the docker.service file ownership is set to root:root.
  • 3.2: Ensure that docker.service file permissions are appropriately set.
  • 3.3: Ensure that docker.socket file ownership is set to root:root.
  • 3.4: Ensure that docker.socket file permissions are set to 644 or more restrictive.
  • 3.5: Ensure that the /etc/docker directory ownership is set to root:root.
  • 3.6: Ensure that /etc/docker directory permissions are set to 755 or more restrictively.
  • 3.7: Ensure that registry certificate file ownership is set to root:root.
  • 3.8: Ensure that registry certificate file permissions are set to 444 or more restrictively.
  • 3.9: Ensure that TLS CA certificate file ownership is set to root:root.
  • 3.10: Ensure that TLS CA certificate file permissions are set to 444 or more restrictively.
  • 3.11: Ensure that Docker server certificate file ownership is set to root:root.
  • 3.12: Ensure that the Docker server certificate file permissions are set to 444 or more restrictively.
  • 3.13: Ensure that the Docker server certificate key file ownership is set to root:root.
  • 3.14: Ensure that the Docker server certificate key file permissions are set to 400.
  • 3.15: Ensure that the Docker socket file ownership is set to root:docker.
  • 3.16: Ensure that the Docker socket file permissions are set to 660 or more restrictively.
  • 3.17: Ensure that the daemon.json file ownership is set to root:root.
  • 3.18: Ensure that daemon.json file permissions are set to 644 or more restrictive.
  • 3.19: Ensure that the /etc/default/docker file ownership is set to root:root.
  • 3.20: Ensure that the /etc/default/docker file permissions are set to 644 or more restrictively.
  • 3.21: Ensure that the /etc/sysconfig/docker file permissions are set to 644 or more restrictively.
  • 3.22: Ensure that the /etc/sysconfig/docker file ownership is set to root:root.
  • 3.23: Ensure that the Containerd socket file ownership is set to root:root.
  • 3.24: Ensure that the Containerd socket file permissions are set to 660 or more restrictively.

4. Container images and build files configuration

  • 4.1: Ensure that a user for the container has been created.
  • 4.5: Ensure Content trust for Docker is Enabled.
  • 4.6: Ensure that HEALTHCHECK instructions have been added to container images.
  • 4.7: Ensure update instructions are not used alone in Dockerfiles.
  • 4.9: Ensure that COPY is used instead of ADD in Dockerfiles.

5. Container runtime configuration

  • 5.1: Ensure swarm mode is not Enabled, if not needed.
  • 5.2: Ensure that, if applicable, an AppArmor Profile is enabled.
  • 5.3: Ensure that, if applicable, SELinux security options are set.
  • 5.4: Ensure that Linux kernel capabilities are restricted within containers.
  • 5.5: Ensure that privileged containers are not used.
  • 5.6: Ensure sensitive host system directories are not mounted on containers.
  • 5.7: Ensure sshd is not run within containers.
  • 5.8: Ensure privileged ports are not mapped within containers.
  • 5.9: Ensure that only needed ports are open on the container.
  • 5.10: Ensure that the host’s network namespace is not shared.
  • 5.11: Ensure that the memory usage for containers is limited.
  • 5.12: Ensure that CPU priority is set appropriately on containers.
  • 5.13: Ensure that the container’s root filesystem is mounted as read only.
  • 5.14: Ensure that incoming container traffic is bound to a specific host interface.
  • 5.15: Ensure that the ‘on-failure’ container restart policy is set to ‘5‘.
  • 5.16: Ensure that the host’s process namespace is not shared.
  • 5.17: Ensure that the host’s IPC namespace is not shared.
  • 5.18: Ensure that host devices are not directly exposed to containers.
  • 5.19: Ensure that the default ulimit is overwritten at runtime if needed.
  • 5.20: Ensure mount propagation mode is not set to shared.
  • 5.21: Ensure that the host’s UTS namespace is not shared.
  • 5.22: Ensure the default seccomp profile is not Disabled.
  • 5.25: Ensure that cgroup usage is confirmed.
  • 5.26: Ensure that the container is restricted from acquiring additional privileges.
  • 5.27: Ensure that container health is checked at runtime.
  • 5.29: Ensure that the PIDs cgroup limit is used.
  • 5.30: Ensure that Docker’s default bridge “docker0” is not used.
  • 5.31: Ensure that the host’s user namespaces are not shared.
  • 5.32: Ensure that the Docker socket is not mounted inside any container.

Note: None of the two configuration checks in section 6 are automated with the Wazuh SCA module.

7. Docker swarm configuration

  • 7.1: Ensure that the minimum number of manager nodes have been created in a swarm.
  • 7.2: Ensure that swarm services are bound to a specific host interface.
  • 7.3: Ensure that all Docker swarm overlay networks are encrypted.
  • 7.4: Ensure that Docker’s secret management commands are used for managing secrets in a swarm cluster.
  • 7.5: Ensure that swarm manager is run in auto-lock mode.

CIS Docker Benchmark controls requiring manual checks

While we have automated compliance checks for 98 CIS Docker Benchmark requirements, certain controls require manual validation due to their complexity or reliance on specific organizational policies. These controls are listed below:

  • 1.1.2: Ensure only trusted users are allowed to control Docker daemon.
  • 1.2.1: Ensure the container host has been hardened.
  • 1.2.2: Ensure that the version of Docker is up to date.
  • 4.2: Ensure that containers use only trusted base images.
  • 4.3: Ensure that unnecessary packages are not installed in the container.
  • 4.4: Ensure images are scanned and rebuilt to include security patches.
  • 4.8: Ensure setuid and setgid permissions are removed.
  • 4.10: Ensure secrets are not stored in Dockerfiles.
  • 4.11: Ensure only verified packages are installed.
  • 4.12: Ensure all signed artifacts are validated.
  • 5.23: Ensure that docker exec commands are not used with the privileged option.
  • 5.24: Ensure that docker exec commands are not used with the user=root option.
  • 5.28: Ensure that Docker commands always make use of the latest version of their image
  • 6.1: Ensure that image sprawl is avoided.
  • 6.2: Ensure that container sprawl is avoided.
  • 7.6: Ensure that the swarm manager auto-lock key is rotated periodically.
  • 7.7: Ensure that node certificates are rotated as appropriate.
  • 7.8: Ensure that CA certificates are rotated as appropriate.
  • 7.9:  Ensure that management plane traffic is separated from data plane traffic.

Configuring Wazuh to scan endpoints against the CIS Docker Benchmark

Requirements

  • Wazuh 4.9.0 central components: Ensure you have a deployment of Wazuh 4.9.0, including the Wazuh server, Wazuh indexer, and Wazuh dashboard. To set this up, follow the Wazuh virtual machine (OVA) installation guide to download and deploy the virtual appliance containing these central components.
  • Docker installed on a Linux endpoint: Install Docker on a Linux endpoint by following the Docker installation guide to set up the Docker engine. Install the Wazuh agent on this endpoint. The endpoints equipped with both Docker and the Wazuh agent will be referred to as “monitored endpoints” throughout this guide.

Note: When in production, ensure to install the Wazuh agent on each endpoint running the Docker engine.

Configure the monitored endpoints

Perform the following steps on each monitored endpoint to configure the Wazuh SCA module to scan them against the CIS Docker Benchmarks:

1. Create a new SCA policy file /var/ossec/etc/sca_docker_audit.yml and add the following content:

# Security Configuration Assessment
# Audit for Docker hosts
# Copyright (C) 2015, Wazuh Inc.
#
# This program is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
# License (version 2) as published by the FSF - Free Software
# Foundation

policy:
  id: "docker_audit"
  file: "sca_docker_audit.yml"
  name: "CIS Docker Benchmark v1.7.0."
  description: "Guidance for establishing a secure configuration for Docker hosts."
  references:
    - https://www.cisecurity.org/benchmark/docker

requirements:
  title: "Check that the Docker daemon is present on the endpoint"
  description: "Requirements for running the SCA scan against endpoints running the Docker Daemon."
  condition: any
  rules:
    - 'd:/var/lib/docker/'
    - 'c:docker --version -> r:^Docker\sversion'

checks:
  - id: 10100
    title: "Ensure a separate partition for containers has been created."
    description: "All Docker containers and their data and metadata is stored under /var/lib/docker directory. By default, /var/lib/docker should be mounted under either the / or /var partitions dependent on how the Linux operating system in use is configured."
    rationale: "Docker depends on /var/lib/docker as the default directory where all Docker related files, including the images, are stored. This directory could fill up quickly causing both Docker and the host to become unusable. For this reason, you should create a separate partition (logical volume) for storing Docker files."
    remediation: "For new installations, you should create a separate partition for the /var/lib/docker mount point. For systems which have already been installed, you should use the Logical Volume Manager (LVM) within Linux to create a new partition."
    compliance:
      - cis: ["1.1.1"]
    condition: any
    rules:
      - 'c:sh -c "docker info | sed -n s/Docker.Root.Dir://p | xargs mountpoint" -> r:is\s*a\s*mountpoint'

  - id: 10101
    title: "Ensure auditing is configured for the Docker daemon."
    description: "Audit all Docker daemon activities."
    rationale: "As well as auditing the normal Linux file system and system calls, you should also audit the Docker daemon. Because this daemon runs with root privileges. It is very important to audit its activities and usage."
    remediation: "You should add rules for the Docker daemon. For example, add the line \"-w /usr/bin/dockerd -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.3"]
    condition: any
    rules:
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/usr/bin/dockerd\s'

  - id: 10102
    title: "Ensure auditing is configured for Docker files and directories - /run/containerd."
    description: "Audit /run/containerd."
    rationale: "As well as auditing the normal Linux file system and system calls, you should also audit all Docker related files and directories. The Docker daemon runs with root privileges and its behaviour depends on some key files and directories. /run/containerd is one such directory. As it holds all the information about containers it should be audited."
    remediation: "You should add a rule for the /run/containerd directory. For example, add the line \"-a exit,always -F path=/run/containerd -F perm=war -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.4"]
    condition: any
    rules:
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/run/containerd\s'

  - id: 10103
    title: "Ensure auditing is configured for Docker files and directories - /var/lib/docker."
    description: "Audit  /var/lib/docker."
    rationale: "As well as auditing the normal Linux file system and system calls, you should also audit all Docker related files and directories. The Docker daemon runs with root privileges and its behaviour depends on some key files and directories. /var/lib/docker is one such directory. As it holds all the information about containers it should be audited."
    remediation: "You should add a rule for the /var/lib/docker directory. For example, add the line \"-a exit,always -F path=/var/lib/docker -F perm=war -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.5"]
    condition: any
    rules:
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/var/lib/docker\s'

  - id: 10104
    title: "Ensure auditing is configured for Docker files and directories - /etc/docker."
    description: "Audit  /etc/docker."
    rationale: "As well as auditing the normal Linux file system and system calls, you should also audit all Docker related files and directories. The Docker daemon runs with root privileges and its behaviour depends on some key files and directories. /etc/docker is one such directory. As it holds all the information about containers it should be audited."
    remediation: "You should add a rule for the /etc/docker directory. For example, add the line \"-w /etc/docker -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.6"]
    condition: any
    rules:
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/etc/docker\s'

  - id: 10105
    title: "Ensure auditing is configured for Docker files and directories - docker.service."
    description: "Audit  docker.service if applicable."
    rationale: "As well as auditing the normal Linux file system and system calls, you should also audit all Docker related files and directories. The Docker daemon runs with root privileges and its behavior depends on some key files and directories with docker.service being one such file. The docker.service file might be present if the daemon parameters have been changed by an administrator. If so, it holds various parameters for the Docker daemon and should be audited."
    remediation: "You should add a rule for docker.service. For example, add the line \"-w /usr/lib/systemd/system/docker.service -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.7"]
    condition: any
    rules:
      - 'c:systemctl show -p FragmentPath docker.service -> r:^FragmentPath=$'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:docker.service'

  - id: 10106
    title: "Ensure auditing is configured for Docker files and directories - containerd.sock."
    description: "Audit  containerd.sock if applicable."
    rationale: "As well as auditing the normal Linux file system and system calls, you should also audit the Docker daemon. Because this daemon runs with root privileges, it is very important to audit its activities and usage. Its behavior depends on some key files and directories with containerd.sock being one such file, and as this holds various parameters for the Docker daemon, it should be audited."
    remediation: "You should add a rule for containerd.sock. For example, add the line \"-w /run/containerd/containerd.sock -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.8"]
    condition: any
    rules:
      - 'f:/etc/containerd/config.toml -> !r:containerd.sock'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:containerd.sock'

  - id: 10107
    title: "Ensure auditing is configured for Docker files and directories - docker.sock."
    description: "Audit  docker.socket if applicable."
    rationale: "As well as auditing the normal Linux file system and system calls, you should also audit the Docker daemon. Because this daemon runs with root privileges, it is very important to audit its activities and usage. Its behavior depends on some key files and directories with docker.socket being one such file, and as this holds various parameters for the Docker daemon, it should be audited."
    remediation: "You should add a rule for docker.socket. For example, add the line \"-w /var/run/docker.sock -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.9"]
    condition: any
    rules:
      - 'not c:sh -c "systemctl show -p FragmentPath docker.socket | cut -d= -f2 | xargs grep ListenStream" -> r:docker.sock$'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:docker.sock'

  - id: 10108
    title: "Ensure auditing is configured for Docker files and directories - /etc/default/docker."
    description: "Audit  /etc/default/docker."
    rationale: "As well as auditing the normal Linux file system and system calls, you should audit all Docker related files and directories. The Docker daemon runs with root privileges and its behavior depends on some key files and directories. /etc/default/docker is one such file. It holds various parameters related to the Docker daemon and should therefore be audited."
    remediation: "You should add a rule for the /etc/default/docker file. For example, add the line \"-w /etc/default/docker -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.10"]
    condition: any
    rules:
      - 'not f:/etc/default/docker'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/etc/default/docker'

  - id: 10109
    title: "Ensure auditing is configured for Docker files and directories - /etc/docker/daemon.json."
    description: "Audit /etc/docker/daemon.json."
    rationale: "As well as auditing the normal Linux file system and system calls, you should audit all Docker related files and directories. The Docker daemon runs with root privileges and its behavior depends on some key files and directories. /etc/docker/daemon.json is one such file. This holds various parameters for the Docker daemon, and as such it should be audited."
    remediation: "You should add a rule for the  /etc/docker/daemon.json file. For example, add the line \"-w  /etc/docker/daemon.json -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.11"]
    condition: any
    rules:
      - 'not f:/etc/docker/daemon.json'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/etc/docker/daemon.json'

  - id: 10110
    title: "Ensure auditing is configured for Docker files and directories - /etc/containerd/config.toml."
    description: "Audit /etc/containerd/config.toml."
    rationale: "As well as auditing the normal Linux file system and system calls, you should audit all Docker related files and directories. The Docker daemon runs with root privileges and its behavior depends on some key files and directories. /etc/containerd/config.toml is one such file as it contains various parameters. If present, it is important that it is audited."
    remediation: "You should add a rule for the  /etc/containerd/config.toml file. For example, add the line \"-w  /etc/containerd/config.toml -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.12"]
    condition: any
    rules:
      - 'not f:/etc/containerd/config.toml'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/etc/containerd/config.toml'

  - id: 10111
    title: "Ensure auditing is configured for Docker files and directories - /etc/sysconfig/docker."
    description: "Audit /etc/sysconfig/docker."
    rationale: "As well as auditing the normal Linux file system and system calls, you should audit all Docker related files and directories. The Docker daemon runs with root privileges and its behavior depends on some key files and directories. /etc/sysconfig/docker is one such file as it contains various parameters related to the Docker daemon when run on CentOS and RHEL based distributions. If present, it is important that it is audited."
    remediation: "You should add a rule for the  /etc/sysconfig/docker file. For example, add the line \"-w  /etc/sysconfig/docker -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.13"]
    condition: any
    rules:
      - 'not f:/etc/sysconfig/docker'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/etc/sysconfig/docker'

  - id: 10112
    title: "Ensure auditing is configured for Docker files and directories - /usr/bin/containerd."
    description: "Audit /usr/bin/containerd."
    rationale: "As well as auditing the normal Linux file system and system calls, you should audit all Docker related files and directories. The Docker daemon runs with root privileges and its behavior depends on some key files and directories. /usr/bin/containerd is one such file and should be audited."
    remediation: "You should add a rule for the  /usr/bin/containerd file. For example, add the line \"-w  /usr/bin/containerd -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.14"]
    condition: any
    rules:
      - 'not f:/usr/bin/containerd'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/usr/bin/containerd'

  - id: 10113
    title: "Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim."
    description: "Audit /usr/bin/containerd-shim."
    rationale: "As well as auditing the normal Linux file system and system calls, you should audit all Docker related files and directories. The Docker daemon runs with root privileges and its behavior depends on some key files and directories. /usr/bin/containerd-shim is one such file and should be audited."
    remediation: "You should add a rule for the  /usr/bin/containerd-shim file. For example, add the line \"-w  /usr/bin/containerd-shim -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.15"]
    condition: any
    rules:
      - 'not f:/usr/bin/containerd-shim'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/usr/bin/containerd-shim'

  - id: 10114
    title: "Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v1."
    description: "Audit /usr/bin/containerd-shim-runc-v1."
    rationale: "As well as auditing the normal Linux file system and system calls, you should audit all Docker related files and directories. The Docker daemon runs with root privileges and its behavior depends on some key files and directories. /usr/bin/containerd-shim-runc-v1 is one such file and should be audited."
    remediation: "You should add a rule for the  /usr/bin/containerd-shim-runc-v1 file. For example, add the line \"-w  /usr/bin/containerd-shim-runc-v1 -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.16"]
    condition: any
    rules:
      - 'not f:/usr/bin/containerd-shim-runc-v1'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/usr/bin/containerd-shim-runc-v1'

  - id: 10115
    title: "Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v2."
    description: "Audit /usr/bin/containerd-shim-runc-v2."
    rationale: "As well as auditing the normal Linux file system and system calls, you should audit all Docker related files and directories. The Docker daemon runs with root privileges and its behavior depends on some key files and directories. /usr/bin/containerd-shim-runc-v2 is one such file and should be audited."
    remediation: "You should add a rule for the  /usr/bin/containerd-shim-runc-v2 file. For example, add the line \"-w  /usr/bin/containerd-shim-runc-v2 -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.17"]
    condition: any
    rules:
      - 'not f:/usr/bin/containerd-shim-runc-v2'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/usr/bin/containerd-shim-runc-v2'

  - id: 10116
    title: "Ensure auditing is configured for Docker files and directories - /usr/bin/runc."
    description: "Audit /usr/bin/runc."
    rationale: "As well as auditing the normal Linux file system and system calls, you should audit all Docker related files and directories. The Docker daemon runs with root privileges and its behavior depends on some key files and directories. /usr/bin/runc is one such file and should be audited."
    remediation: "You should add a rule for the  /usr/bin/runc file. For example, add the line \"-w  /usr/bin/runc -k docker\" to the /etc/audit/rules.d/audit.rules file. Then, restart the audit daemon using the command \"systemctl restart auditd\"."
    compliance:
      - cis: ["1.1.18"]
    condition: any
    rules:
      - 'not f:/usr/bin/runc'
      - 'c:sh -c "command -v auditctl > /dev/null && auditctl -l || echo \"auditctl not found\"" -> r:\s*/usr/bin/runc'

  - id: 10117
    title: "Run the Docker daemon as a non-root user, if possible."
    description: "Rootless mode executes the Docker daemon and containers inside a user namespace, with both the daemon and the container are running without root privileges."
    rationale: "Rootless mode allows running the Docker daemon and containers as a non-root user to mitigate potential vulnerabilities in the daemon and the container runtime."
    remediation: "Follow the current Docker documentation on how to install the Docker daemon as a non-root user."
    compliance:
      - cis: ["2.1"]
    condition: none
    rules:
      - 'c:sh -c "ps -ef | grep ^root.*/dockerd | grep -v grep" -> r:^root'

  - id: 10118
    title: "Ensure network traffic is restricted between containers on the default bridge."
    description: "By default, all network traffic is allowed between containers on the same host on the default network bridge. If not desired, restrict all inter-container communication. Link specific containers together that require communication. Alternatively, you can create custom network and only join containers that need to communicate to that custom network."
    rationale: "By default, unrestricted network traffic is enabled between all containers on the same host on the default network bridge. Thus, each container has the potential of reading all packets across the container network on the same host. This might lead to an unintended and unwanted disclosure of information to other containers. Hence, restrict inter-container communication on the default network bridge."
    remediation: "Edit the Docker daemon configuration file to ensure that icc is disabled. It should include the setting \"icc\": false. Alternatively, run the docker daemon directly and pass --icc=false as an argument. For Example, \"dockerd --icc=false\"."
    compliance:
      - cis: ["2.2"]
    condition: none
    rules:
      - 'c:sh -c "docker network ls --quiet | xargs docker network inspect | grep enable_icc" -> r:enable_icc\.*true'

  - id: 10119
    title: "Ensure the logging level is set to \"info\"."
    description: "Set Docker daemon log level to info."
    rationale: "Setting up an appropriate log level, configures the Docker daemon to log events that you would want to review later. A base log level of info and above would capture all logs except debug logs. Until and unless required, you should not run Docker daemon at debug log level."
    remediation: "Ensure that the Docker daemon configuration file has the following configuration included, \"log-level\": \"info\". Alternatively, run the Docker daemon as: dockerd --log-level=\"info\"."
    compliance:
      - cis: ["2.3"]
    condition: any
    rules:
      - 'f:/etc/docker/daemon.json -> r:"log-level"\.*"info"'
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--log-level\.*info'
      - 'not c:sh -c "ps -ef | grep dockerd.*--log-level | grep -v grep || cat /etc/docker/daemon.json | grep log-level" -> r:log-level'

  - id: 10120
    title: "Ensure Docker is allowed to make changes to iptables."
    description: "The iptables firewall is used to set up, maintain, and inspect the tables of IP packet filter rules within the Linux kernel. The Docker daemon should be allowed to make changes to the iptables ruleset."
    rationale: "Docker will never make changes to your system iptables rules unless you allow it to do so. If you do allow this, Docker server will automatically make any required changes. We recommended letting Docker make changes to iptables automatically in order to avoid networking misconfigurations that could affect the communication between containers and with the outside world. Additionally, this reduces the administrative overhead of updating iptables every time you add containers or modify networking options."
    remediation: "Do not run the Docker daemon with --iptables=false parameter. For example, do not start the Docker daemon with \"docker --iptables=false\"."
    compliance:
      - cis: ["2.4"]
    condition: none
    rules:
      - 'c:cat /etc/docker/daemon.json -> r:"iptables":\s*false'
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--iptables="*false"*'

  - id: 10121
    title: "Ensure insecure registries are not used."
    description: "Docker considers a private registry either secure or insecure. By default, registries are considered secure."
    rationale: "A secure registry uses TLS. A copy of registry's CA certificate is placed on the Docker host at /etc/docker/certs.d/<registry-name>/ directory. An insecure registry is one which does not have a valid registry certificate, or one not using TLS. Insecure registries should not be used as they present a risk of traffic interception and modification. Additionally, once a registry has been marked as insecure commands such as docker pull, docker push, and docker search will not result in an error message and users may indefinitely be working with this type of insecure registry without ever being notified of the risk of potential compromise."
    remediation: "You should ensure that no insecure registries are in use."
    compliance:
      - cis: ["2.5"]
    condition: none
    rules:
      - 'c:cat /etc/docker/daemon.json -> r:"insecure-registries"\.*"\.+"'
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--insecure-registry'

  - id: 10122
    title: "Ensure aufs storage driver is not used."
    description: "Do not use aufs as the storage driver for your Docker instance."
    rationale: "The aufs storage driver is the oldest storage driver used on Linux systems. It is based on a Linux kernel patch-set that is unlikely in future to be merged into the main OS kernel. The aufs driver is also known to cause some serious kernel crashes. aufs only has legacy support within systems using Docker. Most importantly, aufs is not a supported driver in many Linux distributions using latest Linux kernels and has also been deprecated with Docker Engine release 20.10."
    remediation: "Do not explicitly use aufs as storage driver. For example, do not start Docker daemon as: \"dockerd --storage-driver aufs\"."
    compliance:
      - cis: ["2.6"]
    condition: none
    rules:
      - 'c:docker info -> r:^\s*Storage\s*Driver:\s*aufs'

  - id: 10123
    title: "Ensure TLS authentication for Docker daemon is configured."
    description: "It is possible to make the Docker daemon available remotely over a TCP port. If this is required, you should ensure that TLS authentication is configured in order to restrict access to the Docker daemon via IP address and port."
    rationale: "By default, the Docker daemon binds to a non-networked Unix socket and runs with root privileges. If you change the default Docker daemon binding to a TCP port or any other Unix socket, anyone with access to that port or socket could have full access to the Docker daemon and therefore in turn to the host system. For this reason, you should not bind the Docker daemon to another IP/port or a Unix socket. If you must expose the Docker daemon via a network socket, you should configure TLS authentication for the daemon and for any Docker Swarm APIs (if they are in use). This type of configuration restricts the connections to your Docker daemon over the network to a limited number of clients who have access to the TLS client credentials."
    remediation: "Follow the steps mentioned in the Docker documentation or other references."
    compliance:
      - cis: ["2.7"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd" -> r:unix://|fd://'
      - 'not c:sh -c "cat /etc/docker/daemon.json" -> r:"hosts"\.*tcp://'
      - 'c:sh -c "cat /etc/docker/daemon.json" -> r:"tlsverify":\s*true'
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--tlsverify'

  - id: 10124
    title: "Ensure the default ulimit is configured appropriately."
    description: "Set the default ulimit options as appropriate in your environment."
    rationale: "ulimit provides control over the resources available to the shell and to processes which it starts. Setting system resource limits judiciously can save you from disasters such as a fork bomb. On occasion, even friendly users and legitimate processes can overuse system resources and can make the system unusable. Setting the default ulimit for the Docker daemon enforces the ulimit for all container instances. In this case you would not need to setup ulimit for each container instance. However, the default ulimit can be overridden during container runtime, if needed. Therefore, in order to have proper control over system resources, define a default ulimit as is needed in your environment."
    remediation: "Run Docker in daemon mode and pass --default-ulimit as argument with respective ulimits as appropriate in your environment and in line with your security policy. For Example, \"dockerd --default-ulimit nproc=1024:2048 --default-ulimit nofile=100:200\"."
    compliance:
      - cis: ["2.8"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--default-ulimit'
      - 'c:cat /etc/docker/daemon.json -> r:"default-ulimits":\s*{\.*\w+\.*}'

  - id: 10125
    title: "Enable user namespace support."
    description: "You should enable user namespace support in Docker daemon to utilize container user to host user re-mapping. This recommendation is beneficial where the containers you are using do not have an explicit container user defined in the container image. If the container images that you are using have a pre-defined non-root user, this recommendation may be skipped as this feature is still in its infancy, and might result in unpredictable issues or difficulty in configuration."
    rationale: "The Linux kernel \"user namespace\" support within the Docker daemon provides additional security for the Docker host system. It allows a container to have a unique range of user and group IDs which are outside the traditional user and group range utilized by the host system. For example, the root user can have the expected administrative privileges inside the container but can effectively be mapped to an unprivileged UID on the host system."
    remediation: "Please consult the Docker documentation for various ways in which this can be configured depending upon your requirements."
    compliance:
      - cis: ["2.9"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--userns-remap'
      - 'c:cat /etc/docker/daemon.json -> r:"userns-remap":\s*"\w+\.*"'

  - id: 10126
    title: "Ensure the default cgroup usage has been confirmed."
    description: "The --cgroup-parent option allows you to set the default cgroup parent to use for all containers. If there is no specific usage requirement for this, the setting should be left at its default."
    rationale: "System administrators typically define cgroups under which containers are supposed to run. Even if cgroups are not explicitly defined by the system administrators, containers run under docker cgroup by default. It is possible to attach to a different cgroup other than the one which is the default, however this type of usage should be monitored and confirmed because attaching to a different cgroup other than the one that is a default, it could be possible to share resources unevenly causing resource utilization problems on the host."
    remediation: "The default setting is in line with good security practice and can be left in situ. If you wish to specifically set a non-default cgroup, pass the --cgroup-parent parameter to the Docker daemon when starting it. For example, \"dockerd --cgroup-parent=/foobar\"."
    compliance:
      - cis: ["2.10"]
    condition: none
    rules:
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--cgroup-parent'
      - 'c:cat /etc/docker/daemon.json -> r:"cgroup-parent":\s*"\w+\.*"'

  - id: 10127
    title: "Ensure base device size is not changed until needed."
    description: "Under certain circumstances, you might need containers larger than 10G. Where this applies you should carefully choose the base device size."
    rationale: "The base device size can be increased on daemon restart. Increasing the base device size allows all future images and containers to be of the new base device size. A user can use this option to expand the base device size, however shrinking is not permitted. This value affects the system wide \"base\" empty filesystem that may already be initialized and therefore inherited by pulled images. Although the file system does not allocate the increased size as long as it is empty, more space will be allocated for extra images. This may cause a denial of service condition if the allocated partition becomes full."
    remediation: "Do not set \"--storage-opt dm.basesize\" until needed."
    compliance:
      - cis: ["2.11"]
    condition: none
    rules:
      - 'c:sh -c "ps -ef | grep dockerd | grep --storage-opt" -> r:dm.basesize'

  - id: 10128
    title: "Ensure that authorization for Docker client commands is enabled."
    description: "You should use native Docker authorization plugins or a third party authorization mechanism with the Docker daemon to manage access to Docker client commands."
    rationale: "Dockers out-of-the-box authorization model is currently \"all or nothing\". This means that any user with permission to access the Docker daemon can run any Docker client command. The same is true for remote users accessing Dockers API to contact the daemon. If you require greater access control, you can create authorization plugins and add them to your Docker daemon configuration. Using an authorization plugin, a Docker administrator can configure granular access policies for managing access to the Docker daemon. Third party integrations of Docker may implement their own authorization models to require authorization with the Docker daemon outside of docker's native authorization plugin (i.e. Kubernetes, Cloud Foundry, Openshift)."
    remediation: "Install/Create an authorization plugin. Configure the authorization policy as desired. Start the docker daemon as: \"dockerd --authorization-plugin=<PLUGIN_ID>\"."
    compliance:
      - cis: ["2.12"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--authorization-plugin'
      - 'c:cat /etc/docker/daemon.json -> r:"authorization-plugins":\s*[\.*\w+\.*]'

  - id: 10129
    title: "Ensure centralized and remote logging is configured."
    description: "Docker supports various logging mechanisms. A preferable method for storing logs is one that supports centralized and remote management."
    rationale: "Centralized and remote logging ensures that all important log records are safe even in the event of a major data availability issue . Docker supports various logging methods and you should use the one that best corresponds to your IT security policy."
    remediation: "Set up the desired log driver following its documentation. Start the docker daemon using that logging driver. For example: \"dockerd --log-driver=syslog --log-opt syslog-address=tcp://192.xxx.xxx.xxx\"."
    compliance:
      - cis: ["2.13"]
    condition: none
    rules:
      - 'c:docker info --format "{{ .LoggingDriver }}" -> r:json-file'

  - id: 10130
    title: "Ensure containers are restricted from acquiring new privileges."
    description: "By default you should restrict containers from acquiring additional privileges via suid or sgid."
    rationale: "A process can set the no_new_priv bit in the kernel and this persists across forks, clones and execve. The no_new_priv bit ensures that the process and its child processes do not gain any additional privileges via suid or sgid bits. This reduces the security risks associated with many dangerous operations because there is a much reduced ability to subvert privileged binaries. Setting this at the daemon level ensures that by default all new containers are restricted from acquiring new privileges."
    remediation: "You should run the Docker daemon as below: \"dockerd --no-new-privileges\"."
    compliance:
      - cis: ["2.14"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--no-new-privileges'
      - 'c:cat /etc/docker/daemon.json -> r:"no-new-privileges":\s*true'

  - id: 10131
    title: "Ensure live restore is enabled."
    description: "The --live-restore option enables full support of daemon-less containers within Docker. It ensures that Docker does not stop containers on shutdown or restore and that it properly reconnects to the container when restarted."
    rationale: "One of the important security triads is availability. Setting the --live-restore flag within the Docker daemon ensures that container execution is not interrupted when it is not available. This also makes it easier to update and patch the Docker daemon without application downtime."
    remediation: "Run Docker in daemon mode and pass --live-restore to it as an argument. For Example, \"dockerd --live-restore\"."
    compliance:
      - cis: ["2.15"]
    condition: any
    rules:
      - 'c:docker info -> r:^\s*Live\s*Restore\s*Enabled:\s*true'
      - 'c:docker info -> r:^\s*Swarm:\s*active'
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--live-restore'

  - id: 10132
    title: "Ensure Userland Proxy is Disabled."
    description: "The Docker daemon starts a userland proxy service for port forwarding whenever a port is exposed. Where hairpin NAT is available, this service is generally superfluous to requirements and can be disabled."
    rationale: "The Docker engine provides two mechanisms for forwarding ports from the host to containers, hairpin NAT, and the use of a userland proxy. In most circumstances, the hairpin NAT mode is preferred as it improves performance and makes use of native Linux iptables functionality instead of using an additional component. Where hairpin NAT is available, the userland proxy should be disabled on startup to reduce the attack surface of the installation."
    remediation: "You should run the Docker daemon as below: \"dockerd --userland-proxy=false\"."
    compliance:
      - cis: ["2.16"]
    condition: any
    rules:
      - 'c:cat /etc/docker/daemon.json -> r:"userland-proxy":\s*false'
      - 'c:sh -c "ps -ef | grep dockerd" -> r:--userland-proxy=false'

  - id: 10133
    title: "Ensure that a daemon-wide custom seccomp profile is applied if appropriate."
    description: "You can choose to apply a custom seccomp profile at a daemon-wide level if needed with this overriding Docker's default seccomp profile."
    rationale: "A large number of system calls are exposed to every userland process with many of them not utilized during the entire lifetime of the process. Many applications do not need all these system calls and therefore benefit by having each system call currently in use reviewed in line with organizational security policy. A reduced set of system calls reduces the total kernel surface exposed to the application and therefore improves application security. A custom seccomp profile can be applied instead of Docker's default seccomp profile. Alternatively, if Docker's default profile is adequate for your environment, you can choose to ignore this recommendation."
    remediation: "By default, Docker's default seccomp profile is applied. If this is adequate for your environment, no action is necessary. Alternatively, if you choose to apply your own seccomp profile, use the --seccomp-profile flag at daemon start or put it in the daemon runtime parameters file. For example: \"dockerd --seccomp-profile </path/to/seccomp/profile>\"."
    compliance:
      - cis: ["2.17"]
    condition: any
    rules:
      - 'c:docker info --format "{{ .SecurityOptions }}" -> r:name=seccomp,profile=default'

  - id: 10134
    title: "Ensure that experimental features are not implemented in production."
    description: "Experimental features should not be enabled in production."
    rationale: "\"Experimental\" is currently a runtime Docker daemon flag rather than being a feature of a separate build. Passing --experimental as a runtime flag to the docker daemon activates experimental features. Whilst \"Experimental\" is considered a stable release, it has a number of features which may not have been fully tested and do not guarantee API stability."
    remediation: "You should not pass --experimental as a runtime parameter to the Docker daemon on production systems."
    compliance:
      - cis: ["2.18"]
    condition: any
    rules:
      - 'c:docker version --format "{{ .Server.Experimental }}" -> r:false'

  - id: 10135
    title: "Ensure that the docker.service file ownership is set to root:root."
    description: "You should verify that the docker.service file ownership and group ownership are correctly set to root."
    rationale: "The docker.service file contains sensitive parameters that may alter the behavior of the Docker daemon. It should therefore be individually and group owned by the root user in order to ensure that it is not modified or corrupted by a less privileged user."
    remediation: " Find out the file location: \"systemctl show -p FragmentPath docker.service\". If the file does not exist, this recommendation is not applicable. If the file does exist, you should execute the command below, including the correct file path, in order to set the ownership and group ownership for the file to root. For example, \"chown root:root /usr/lib/systemd/system/docker.service\"."
    compliance:
      - cis: ["3.1"]
    condition: any
    rules:
      - 'c:systemctl show -p FragmentPath docker.service -> r:^FragmentPath=$'
      - 'c:sh -c "systemctl show -p FragmentPath docker.service | cut -d= -f2 | xargs stat -c %U:%G" -> r:root:root'

  - id: 10136
    title: "Ensure that docker.service file permissions are appropriately set."
    description: "You should verify that the docker.service file permissions are either set to 644 or to a more restrictive value."
    rationale: "The docker.service file contains sensitive parameters that may alter the behavior of the Docker daemon. It should therefore not be writable by any other user other than root in order to ensure that it can not be modified by less privileged users."
    remediation: " Find out the file location: \"systemctl show -p FragmentPath docker.service\". If the file does not exist, this recommendation is not applicable. If the file exists, execute the command below including the correct file path to set the file permissions to 644. For example, \"chmod 644 /usr/lib/systemd/system/docker.service\"."
    compliance:
      - cis: ["3.2"]
    condition: any
    rules:
      - 'c:systemctl show -p FragmentPath docker.service -> r:^FragmentPath=$'
      - 'c:sh -c "systemctl show -p FragmentPath docker.service | cut -d= -f2 | xargs stat -c %a" -> n:^(\d+) compare <= 644'

  - id: 10137
    title: "Ensure that docker.socket file ownership is set to root:root."
    description: "You should verify that the docker.socket file ownership and group ownership are correctly set to root."
    rationale: "The docker.socket file contains sensitive parameters that may alter the behavior of the Docker remote API. For this reason, it should be owned and group owned by root in order to ensure that it is not modified by less privileged users."
    remediation: " Find out the file location: \"systemctl show -p FragmentPath docker.socket\". If the file does not exist, this recommendation is not applicable. If the file does exist, you should execute the command below, including the correct file path, in order to set the ownership and group ownership for the file to root. For example, \"chown root:root /usr/lib/systemd/system/docker.socket\"."
    compliance:
      - cis: ["3.3"]
    condition: any
    rules:
      - 'c:systemctl show -p FragmentPath docker.socket -> r:^FragmentPath=$'
      - 'c:sh -c "systemctl show -p FragmentPath docker.socket | cut -d= -f2 | xargs stat -c %U:%G" -> r:root:root'

  - id: 10138
    title: "Ensure that docker.socket file permissions are set to 644 or more restrictive."
    description: "You should verify that the file permissions on the docker.socket file are correctly set to 644 or more restrictively."
    rationale: "The docker.socket file contains sensitive parameters that may alter the behavior of the Docker remote API. It should therefore be writeable only by root in order to ensure that it is not modified by less privileged users."
    remediation: " Find out the file location: \"systemctl show -p FragmentPath docker.socket\".  If the file does not exist, this recommendation is not applicable. If the file does exist, you should execute the command below, including the correct file path to set the file permissions to 644. For example, \"chmod 644 /usr/lib/systemd/system/docker.socket\"."
    compliance:
      - cis: ["3.4"]
    condition: any
    rules:
      - 'c:systemctl show -p FragmentPath docker.service -> r:^FragmentPath=$'
      - 'c:sh -c "systemctl show -p FragmentPath docker.socket | cut -d= -f2 | xargs stat -c %a" -> n:^(\d+) compare <= 644'

  - id: 10139
    title: "Ensure that the /etc/docker directory ownership is set to root:root."
    description: "You should verify that the /etc/docker directory ownership and group ownership is correctly set to root."
    rationale: "The /etc/docker directory contains certificates and keys in addition to various other sensitive files. It should therefore be individual owned and group owned by root in order to ensure that it can not be modified by less privileged users."
    remediation: "To resolve this issue you should run the following command: \"chown root:root /etc/docker\". This sets the ownership and group ownership for the directory to root."
    compliance:
      - cis: ["3.5"]
    condition: any
    rules:
      - 'c:stat -c %U:%G /etc/docker -> r:root:root'

  - id: 10140
    title: "Ensure that /etc/docker directory permissions are set to 755 or more restrictively."
    description: "You should verify that the /etc/docker directory permissions are correctly set to 755 or more restrictively."
    rationale: "The /etc/docker directory contains certificates and keys in addition to various sensitive files. It should therefore only be writeable by root to ensure that it can not be modified by a less privileged user."
    remediation: "You should run the following command: \"chmod 755 /etc/docker\". This sets the permissions for the directory to 755."
    compliance:
      - cis: ["3.6"]
    condition: any
    rules:
      - 'c:stat -c %a /etc/docker -> n:^(\d+) compare <= 755'

  - id: 10141
    title: "Ensure that registry certificate file ownership is set to root:root."
    description: "You should verify that all the registry certificate files (usually found under /etc/docker/certs.d/<registry-name> directory) are individually owned and group owned by root."
    rationale: "The /etc/docker/certs.d/<registry-name> directory contains Docker registry certificates. These certificate files must be individually owned and group owned by root to ensure that less privileged users are unable to modify the contents of the directory."
    remediation: "The following command could be executed: \"chown root:root /etc/docker/certs.d/<registry-name>/*\". This would set the individual ownership and group ownership for the registry certificate files to root."
    compliance:
      - cis: ["3.7"]
    condition: none
    rules:
      - 'c:sh -c "find /etc/docker/certs.d/ -mindepth 1 -exec stat -c %U:%G {} + 2>/dev/null | grep -v root:root" -> r:\w+'

  - id: 10142
    title: "Ensure that registry certificate file permissions are set to 444 or more restrictively."
    description: "You should verify that all the registry certificate files (usually found under /etc/docker/certs.d/<registry-name> directory) have permissions of 444 or are set more restrictively. Note that, by default, this directory might not exist if no registry certificate files are in place."
    rationale: "The /etc/docker/certs.d/<registry-name> directory contains Docker registry certificates. These certificate files must have permissions of 444 or more restrictive permissions in order to ensure that unprivileged users do not have full access to them."
    remediation: "You should execute the following command: \"find /etc/docker/certs.d/ -type f -exec chmod 0444 {} \\;\". This would set the permissions for the registry certificate files to 444."
    compliance:
      - cis: ["3.8"]
    condition: none
    rules:
      - 'c:sh -c "find /etc/docker/certs.d/ -mindepth 1 -exec stat -c %a {} + 2>/dev/null" -> n:^(\d+) compare > 444'

  - id: 10143
    title: "Ensure that TLS CA certificate file ownership is set to root:root."
    description: "You should verify that the TLS CA certificate file (the file that is passed along with the --tlscacert parameter) is individually owned and group owned by root."
    rationale: "The TLS CA certificate file should be protected from any tampering. It is used to authenticate the Docker server based on a given CA certificate. It must be therefore be individually owned and group owned by root to ensure that it cannot be modified by less privileged users."
    remediation: "You should execute the following command: \"chown root:root <path to TLS CA certificate file>\". This sets the individual ownership and group ownership for the TLS CA certificate file to root."
    compliance:
      - cis: ["3.9"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd | sed -n \"s/.*tlscacert=\\([^s]\\)/\\1/p\" | sed \"s/--/ --/g\" | cut -d \" \" -f 1 | xargs stat -c %U:%G" 2>/dev/null -> r:root:root'
      - 'c:sh -c "grep -oP \"\\\"tlscacert\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json | xargs stat -c %U:%G" -> r:root:root'
      - 'not c:sh -c "grep -oP \"\\\"tlscacert\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json 2>/dev/null; ps -ef | grep dockerd | grep tlscacert= | grep -v grep" -> r:\.+'

  - id: 10144
    title: "Ensure that TLS CA certificate file permissions are set to 444 or more restrictively."
    description: "You should verify that the TLS CA certificate file (the file that is passed along with the --tlscacert parameter) has permissions of 444 or is set more restrictively."
    rationale: "The TLS CA certificate file should be protected from any tampering. It is used to authenticate the Docker server based on a given CA certificate. It must therefore have permissions of 444, or more restrictive permissions to ensure that the file cannot be modified by a less privileged user."
    remediation: "You should execute the following command: \"chmod 444 <path to TLS CA certificate file>\". This sets the file permissions on the TLS CA file to 444."
    compliance:
      - cis: ["3.10"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd | sed -n \"s/.*tlscacert=\\([^s]\\)/\\1/p\" | sed \"s/--/ --/g\" | cut -d \" \" -f 1 | xargs stat -c %a" 2>/dev/null -> n:^(\d+) compare <= 444'
      - 'c:sh -c "grep -oP \"\\\"tlscacert\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json | xargs stat -c %a" -> n:^(\d+) compare <= 444'
      - 'not c:sh -c "grep -oP \"\\\"tlscacert\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json 2>/dev/null; ps -ef | grep dockerd | grep tlscacert= | grep -v grep" -> r:\.+'

  - id: 10145
    title: "Ensure that Docker server certificate file ownership is set to root:root."
    description: "You should verify that the Docker server certificate file (the file that is passed along with the --tlscert parameter) is individual owned and group owned by root."
    rationale: "The Docker server certificate file should be protected from any tampering. It is used to authenticate the Docker server based on the given server certificate. It must therefore be individually owned and group owned by root to prevent modification by less privileged users."
    remediation: "You should run the following command: \"chown root:root <path to Docker server certificate file>\". This sets the individual ownership and the group ownership for the Docker server certificate file to root."
    compliance:
      - cis: ["3.11"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd | sed -n \"s/.*tlscert=\\([^s]\\)/\\1/p\" | sed \"s/--/ --/g\" | cut -d \" \" -f 1 | xargs stat -c %U:%G" 2>/dev/null -> r:root:root'
      - 'c:sh -c "grep -oP \"\\\"tlscert\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json | xargs stat -c %U:%G" -> r:root:root'
      - 'not c:sh -c "grep -oP \"\\\"tlscert\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json 2>/dev/null; ps -ef | grep dockerd | grep tlscert= | grep -v grep" -> r:\.+'

  - id: 10146
    title: "Ensure that the Docker server certificate file permissions are set to 444 or more restrictively."
    description: "You should verify that the Docker server certificate file (the file that is passed along with the --tlscert parameter) has permissions of 444 or more restrictive permissions."
    rationale: "The Docker server certificate file should be protected from any tampering. It is used to authenticate the Docker server based on the given server certificate. It should therefore have permissions of 444 to prevent its modification."
    remediation: "You should execute the command below: \"chmod 444 <path to Docker server certificate file>\". This sets the file permissions of the Docker server certificate file to 444."
    compliance:
      - cis: ["3.12"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd | sed -n \"s/.*tlscert=\\([^s]\\)/\\1/p\" | sed \"s/--/ --/g\" | cut -d \" \" -f 1 | xargs stat -c %a" 2>/dev/null -> n:^(\d+) compare <= 444'
      - 'c:sh -c "grep -oP \"\\\"tlscert\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json | xargs stat -c %a" -> n:^(\d+) compare <= 444'
      - 'not c:sh -c "grep -oP \"\\\"tlscert\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json 2>/dev/null; ps -ef | grep dockerd | grep tlscert= | grep -v grep" -> r:\.+'

  - id: 10147
    title: "Ensure that the Docker server certificate key file ownership is set to root:root."
    description: "You should verify that the Docker server certificate key file (the file that is passed along with the --tlskey parameter) is individually owned and group owned by root."
    rationale: "The Docker server certificate key file should be protected from any tampering or unneeded reads/writes. As it holds the private key for the Docker server certificate, it must be individually owned and group owned by root to ensure that it cannot be accessed by less privileged users."
    remediation: "You should execute the following command: \"chown root:root <path to Docker server certificate key file>\". This sets the individual ownership and group ownership for the Docker server certificate key file to root."
    compliance:
      - cis: ["3.13"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd | sed -n \"s/.*tlskey=\\([^s]\\)/\\1/p\" | sed \"s/--/ --/g\" | cut -d \" \" -f 1 | xargs stat -c %U:%G" 2>/dev/null -> r:root:root'
      - 'c:sh -c "grep -oP \"\\\"tlskey\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json | xargs stat -c %U:%G" -> r:root:root'
      - 'not c:sh -c "grep -oP \"\\\"tlskey\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json 2>/dev/null; ps -ef | grep dockerd | grep tlskey= | grep -v grep" -> r:\.+'

  - id: 10148
    title: "Ensure that the Docker server certificate key file permissions are set to 400."
    description: "You should verify that the Docker server certificate key file (the file that is passed along with the --tlskey parameter) has permissions of 400."
    rationale: "The Docker server certificate key file should be protected from any tampering or unneeded reads. It holds the private key for the Docker server certificate. It must therefore have permissions of 400 to ensure that the certificate key file is not modified."
    remediation: "You should execute the command below: \"chmod 400 <path to Docker server certificate key file>\". This sets the Docker server certificate key file permissions to 400."
    compliance:
      - cis: ["3.14"]
    condition: any
    rules:
      - 'c:sh -c "ps -ef | grep dockerd | sed -n \"s/.*tlskey=\\([^s]\\)/\\1/p\" | sed \"s/--/ --/g\" | cut -d \" \" -f 1 | xargs stat -c %a" 2>/dev/null -> n:^(\d+) compare <= 400'
      - 'c:sh -c "grep -oP \"\\\"tlskey\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json | xargs stat -c %a" -> n:^(\d+) compare <= 400'
      - 'not c:sh -c "grep -oP \"\\\"tlskey\\\":\\s*\\\"\\K[^\\\"]*\" /etc/docker/daemon.json 2>/dev/null; ps -ef | grep dockerd | grep tlskey= | grep -v grep" -> r:\.+'

  - id: 10149
    title: "Ensure that the Docker socket file ownership is set to root:docker."
    description: "You should verify that the Docker socket file is owned by root and group owned by docker."
    rationale: "The Docker daemon runs as root. The default Unix socket therefore must be owned by root. If any other user or process owns this socket, it might be possible for that nonprivileged user or process to interact with the Docker daemon. Additionally, in this case a non-privileged user or process might be able to interact with containers which is neither a secure nor desired behavior. Additionally, the Docker installer creates a Unix group called docker. You can add users to this group, and in this case, those users would be able to read and write to the default Docker Unix socket. The membership of the docker group is tightly controlled by the system administrator. However, ff any other group owns this socket, then it might be possible for members of that group to interact with the Docker daemon. Such a group might not be as tightly controlled as the docker group. Again, this is not in line with good security practice. For these reason, the default Docker Unix socket file should be owned by root and group owned by docker to maintain the integrity of the socket file."
    remediation: "You should execute the following command: \"chown root:docker /var/run/docker.sock\". This sets the ownership to root and group ownership to docker for the default Docker socket file."
    compliance:
      - cis: ["3.15"]
    condition: any
    rules:
      - 'c:stat -c %U:%G /var/run/docker.sock -> r:root:docker'

  - id: 10150
    title: "Ensure that the Docker socket file permissions are set to 660 or more restrictively."
    description: "You should verify that the Docker socket file has permissions of 660 or are configured more restrictively."
    rationale: "Only root and the members of the docker group should be allowed to read and write to the default Docker Unix socket. The Docker socket file should therefore have permissions of 660 or more restrictive permissions."
    remediation: "You should run the following command: \"chmod 660 /var/run/docker.sock\". This sets the file permissions of the Docker socket file to 660."
    compliance:
      - cis: ["3.16"]
    condition: any
    rules:
      - 'c:stat -c %a /var/run/docker.sock -> n:^(\d+) compare <= 660'

  - id: 10151
    title: "Ensure that the daemon.json file ownership is set to root:root."
    description: "You should verify that the daemon.json file individual ownership and group ownership is correctly set to root, if it is in use."
    rationale: "The daemon.json file contains sensitive parameters that could alter the behavior of the docker daemon. It should therefore be owned and group owned by root to ensure it cannot be modified by less privileged users."
    remediation: "If the daemon.json file is present, you should execute the command below: \"chown root:root /etc/docker/daemon.json\". This sets the ownership and group ownership for the file to root."
    compliance:
      - cis: ["3.17"]
    condition: any
    rules:
      - 'not f:/etc/docker/daemon.json'
      - 'c:stat -c %U:%G /etc/docker/daemon.json -> r:root:root'

  - id: 10152
    title: "Ensure that daemon.json file permissions are set to 644 or more restrictive."
    description: "You should verify that if the daemon.json is present its file permissions are correctly set to 644 or more restrictively."
    rationale: "The daemon.json file contains sensitive parameters that may alter the behavior of the docker daemon. Therefore it should be writeable only by root to ensure it is not modified by less privileged users."
    remediation: "If the file is present, you should execute the command below: \"chmod 644 /etc/docker/daemon.json\". This sets the file permissions for this file to 644."
    compliance:
      - cis: ["3.18"]
    condition: any
    rules:
      - 'not f:/etc/docker/daemon.json'
      - 'c:stat -c %a /etc/docker/daemon.json -> n:^(\d+) compare <= 644'

  - id: 10153
    title: "Ensure that the /etc/default/docker file ownership is set to root:root."
    description: "You should verify that the /etc/default/docker file ownership and group-ownership is correctly set to root."
    rationale: "The /etc/default/docker file contains sensitive parameters that may alter the behavior of the Docker daemon. It should therefore be individually owned and group owned by root to ensure that it cannot be modified by less privileged users."
    remediation: "You should execute the following command: \"chown root:root /etc/default/docker\". This sets the ownership and group ownership of the file to root."
    compliance:
      - cis: ["3.19"]
    condition: any
    rules:
      - 'not f:/etc/default/docker'
      - 'c:stat -c %U:%G /etc/default/docker -> r:root:root'

  - id: 10154
    title: "Ensure that the /etc/default/docker file permissions are set to 644 or more restrictively."
    description: "You should verify that the /etc/default/docker file permissions are correctly set to 644 or more restrictively."
    rationale: "The /etc/default/docker file contains sensitive parameters that may alter the behavior of the Docker daemon. It should therefore be writeable only by root in order to ensure that it is not modified by less privileged users."
    remediation: "You should execute the following command: \"chmod 644 /etc/default/docker\". This sets the file permissions for this file to 644."
    compliance:
      - cis: ["3.20"]
    condition: any
    rules:
      - 'not f:/etc/default/docker'
      - 'c:stat -c %a /etc/default/docker -> n:^(\d+) compare <= 644'

  - id: 10155
    title: "Ensure that the /etc/sysconfig/docker file permissions are set to 644 or more restrictively."
    description: "You should verify that the /etc/sysconfig/docker file permissions are correctly set to 644 or more restrictively."
    rationale: "The /etc/sysconfig/docker file contains sensitive parameters that may alter the behavior of the Docker daemon. It should therefore be writeable only by root in order to ensure that it is not modified by less privileged users."
    remediation: "You should execute the following command: \"chmod 644 /etc/sysconfig/docker\". This sets the file permissions for this file to 644."
    compliance:
      - cis: ["3.21"]
    condition: any
    rules:
      - 'not f:/etc/sysconfig/docker'
      - 'c:stat -c %a /etc/sysconfig/docker -> n:^(\d+) compare <= 644'

  - id: 10156
    title: "Ensure that the /etc/sysconfig/docker file ownership is set to root:root."
    description: "You should verify that the /etc/sysconfig/docker file individual ownership and group ownership is correctly set to root."
    rationale: "The /etc/sysconfig/docker file contains sensitive parameters that may alter the behavior of the Docker daemon. It should therefore be individually owned and group owned by root to ensure that it is not modified by less privileged users."
    remediation: "You should execute the following command: \"chown root:root /etc/sysconfig/docker\". This sets the ownership and group ownership of the file to root."
    compliance:
      - cis: ["3.22"]
    condition: any
    rules:
      - 'not f:/etc/sysconfig/docker'
      - 'c:stat -c %U:%G /etc/sysconfig/docker -> r:root:root'

  - id: 10157
    title: "Ensure that the Containerd socket file ownership is set to root:root."
    description: "You should verify that the Containerd socket file is owned by root and group owned by root."
    rationale: "Containerd is an underlying component used by Docker to create and manage containers. It provides a socket file similar to the Docker socket, which must be protected from unauthorized access. If any other user or process owns this socket, it might be possible for that non-privileged user or process to interact with the Containerd daemon. Additionally, in this case a non-privileged user or process might be able to interact with containers which is neither a secure nor desired behavior. Unlike the Docker socket, there is usually no requirement for non-privileged users to connect to the socket, so the ownership should be root:root."
    remediation: "You should execute the following command: \"chown root:root /run/containerd/containerd.sock\". This sets the ownership to root and group ownership to root for the default Containerd socket file."
    compliance:
      - cis: ["3.23"]
    condition: any
    rules:
      - 'not f:/run/containerd/containerd.sock'
      - 'c:stat -c %U:%G /run/containerd/containerd.sock -> r:root:root'

  - id: 10158
    title: "Ensure that the Containerd socket file permissions are set to 660 or more restrictively."
    description: "You should verify that the Containerd socket file has permissions of 660 or are configured more restrictively."
    rationale: "Only root and the members of the root group should be allowed to read and write to the default Containerd Unix socket. The Containerd socket file should therefore have permissions of 660 or more restrictive permissions."
    remediation: "You should execute the command below: \"chmod 660 /run/containerd/containerd.sock\". This sets the file permissions of the Containerd socket file to 660."
    compliance:
      - cis: ["3.24"]
    condition: any
    rules:
      - 'not f:/run/containerd/containerd.sock'
      - 'c:stat -c %a /run/containerd/containerd.sock -> n:^(\d+) compare <= 660'

  - id: 10159
    title: "Ensure that a user for the container has been created."
    description: "Containers should run as a non-root user."
    rationale: "It is good practice to run the container as a non-root user, where possible. This can be done either via the USER directive in the Dockerfile or through gosu or similar where used as part of the CMD or ENTRYPOINT directives."
    remediation: "You should ensure that the Dockerfile for each container image contains the information below: \"USER <username or ID>\". In this case, the user name or ID refers to the user that was found in the container base image. If there is no specific user created in the container base image, then make use of the useradd command to add a specific user before the USER instruction in the Dockerfile."
    compliance:
      - cis: ["4.1"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet | xargs -I{} docker exec {} cat /proc/1/status | grep ^Uid: | cut -f2" -> r:^0$'

  - id: 10160
    title: "Ensure Content trust for Docker is Enabled."
    description: "Content trust is disabled by default and should be enabled in line with organizational security policy."
    rationale: "Content trust provides the ability to use digital signatures for data sent to and received from remote Docker registries. These signatures allow client-side verification of the identity and the publisher of specific image tags and ensures the provenance of container images."
    remediation: "To enable content trust in a bash shell, you should enter the following command: \"export DOCKER_CONTENT_TRUST=1\". Alternatively, you could set this environment variable in your profile file so that content trust is enabled on every login."
    compliance:
      - cis: ["4.5"]
    condition: all
    rules:
      - 'c:echo $DOCKER_CONTENT_TRUST -> r:^1$'

  - id: 10161
    title: "Ensure that HEALTHCHECK instructions have been added to container images."
    description: "You should add the HEALTHCHECK instruction to your Docker container images in order to ensure that health checks are executed against running containers."
    rationale: "An important security control is that of availability. Adding the HEALTHCHECK instruction to your container image ensures that the Docker engine periodically checks the running container instances against that instruction to ensure that containers are still operational. Based on the results of the health check, the Docker engine could terminate containers which are not responding correctly, and instantiate new ones."
    remediation: "You should follow the Docker documentation and rebuild your container images to include the HEALTHCHECK instruction."
    compliance:
      - cis: ["4.6"]
    condition: none
    rules:
      - 'c:sh -c "for image in \$(docker images --format \"{{.ID}}\"); do docker inspect --format=\"{{json .Config.Healthcheck}}\" \$image; done" -> r:^null$'

  - id: 10162
    title: "Ensure update instructions are not used alone in Dockerfiles."
    description: "You should not use OS package manager update instructions such as apt-get update or yum update either alone or in a single line in any Dockerfiles used to generate images under review."
    rationale: "Adding update instructions in a single line on the Dockerfile will cause the update layer to be cached. When you then build any image later using the same instruction, this will cause the previously cached update layer to be used, potentially preventing any fresh updates from being applied to later builds."
    remediation: "You should use update instructions together with install instructions and version pinning for packages while installing them. This will prevent caching and force the extraction of the required versions. Alternatively, you could use the --no-cache flag during the docker build process to avoid using cached layers."
    compliance:
      - cis: ["4.7"]
    condition: none
    rules:
      - 'c:sh -c "for image in \$(docker images --format \"{{.ID}}\"); do docker history --format \"{{.CreatedBy}}\" --no-trunc \$image; done" -> r:\s*update'

  - id: 10163
    title: "Ensure that COPY is used instead of ADD in Dockerfiles."
    description: "You should use the COPY instruction instead of the ADD instruction in the Dockerfile."
    rationale: "The COPY instruction simply copies files from the local host machine to the container file system. The ADD instruction could potentially retrieve files from remote URLs and perform operations such as unpacking them. The ADD instruction therefore introduces security risks. For example, malicious files may be directly accessed from URLs without scanning, or there may be vulnerabilities associated with decompressing them."
    remediation: "You should use COPY rather than ADD instructions in Dockerfiles."
    compliance:
      - cis: ["4.9"]
    condition: none
    rules:
      - 'c:sh -c "for image in \$(docker images --format \"{{.ID}}\"); do docker history --format \"{{.CreatedBy}}\" --no-trunc \$image; done" -> r:\s*ADD\s*'

  - id: 10164
    title: " Ensure swarm mode is not Enabled, if not needed."
    description: "Do not enable swarm mode on a Docker engine instance unless this is needed."
    rationale: "By default, a Docker engine instance will not listen on any network ports, with all communications with the client coming over the Unix socket. When Docker swarm mode is enabled on a Docker engine instance, multiple network ports are opened on the system and made available to other systems on the network for the purposes of cluster management and node communications. Opening network ports on a system increases its attack surface and this should be avoided unless required. It should be noted that swarm mode is required for the operation of Docker Enterprise components."
    remediation: "If swarm mode has been enabled on a system in error, you should run the command: \"docker swarm leave\"."
    compliance:
      - cis: ["5.1"]
    condition: all
    rules:
      - 'c:docker info -> r:Swarm:\s*inactive'

  - id: 10165
    title: "Ensure that, if applicable, an AppArmor Profile is enabled."
    description: "AppArmor is an effective and easy-to-use Linux application security system. It is available on some Linux distributions by default, for example, on Debian and Ubuntu."
    rationale: "AppArmor protects the Linux OS and applications from various threats by enforcing a security policy which is also known as an AppArmor profile. You can create your own AppArmor profile for containers or use Docker's default profile. Enabling this feature enforces security policies on containers as defined in the profile."
    remediation: "If AppArmor is applicable for your Linux OS, you should enable it."
    compliance:
      - cis: ["5.2"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"AppArmorProfile={{ .AppArmorProfile }}\"" -> r:^AppArmorProfile=$|^AppArmorProfile=unconfined$|^AppArmorProfile=[]$|^AppArmorProfile=\<no\s*value>$'

  - id: 10166
    title: "Ensure that, if applicable, SELinux security options are set."
    description: "SELinux is an effective and easy-to-use Linux application security system. It is available by default on some distributions such as Red Hat and Fedora."
    rationale: "SELinux provides a Mandatory Access Control (MAC) system that greatly augments the default Discretionary Access Control (DAC) model. You can therefore add an extra layer of safety to your containers by enabling SELinux on your Linux host."
    remediation: "If SELinux is applicable for your Linux OS, you should use it."
    compliance:
      - cis: ["5.3"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"SecurityOpt={{ .HostConfig.SecurityOpt }}\"" -> r:^SecurityOpt=$|^SecurityOpt=[]$|^SecurityOpt=\<no\s*value>$'

  - id: 10167
    title: "Ensure that Linux kernel capabilities are restricted within containers."
    description: "By default, Docker starts containers with a restricted set of Linux kernel capabilities. This means that any process can be granted the required capabilities instead of giving it root access. Using Linux kernel capabilities, processes in general do not need to run as the root user."
    rationale: "Docker supports the addition and removal of capabilities. You should remove all capabilities not required for the correct function of the container. Specifically, in the default capability set provided by Docker, the NET_RAW capability should be removed if not explicitly required, as it can give an attacker with access to a container the ability to create spoofed network traffic."
    remediation: "Follow the current Docker documentation on how to restrict Linux kernel capabilities within containers."
    compliance:
      - cis: ["5.4"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"CapAdd={{ .HostConfig.CapAdd }}\" | grep -vP \"^CapAdd=($|<no value>|<nil>|\\[\\])\"" -> r:CapAdd'

  - id: 10168
    title: "Ensure that privileged containers are not used."
    description: "Using the --privileged flag provides all Linux kernel capabilities to the container to which it is applied and therefore overwrites the --cap-add and --cap-drop flags. For this reason you should ensure that it is not used."
    rationale: "The --privileged flag provides all capabilities to the container to which it is applied, and also lifts all the limitations enforced by the device cgroup controller. As a consequence this the container has most of the rights of the underlying host. This flag only exists to allow for specific use cases (for example running Docker within Docker) and should not generally be used."
    remediation: "You should not run containers with the --privileged flag."
    compliance:
      - cis: ["5.5"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"{{ .HostConfig.Privileged }}\"" -> r:true'

  - id: 10169
    title: "Ensure sensitive host system directories are not mounted on containers."
    description: "You should not allow sensitive host system directories such as those listed below to be
mounted as container volumes, especially in read-write mode. /, /boot, /dev, /etc, /lib, /proc, /sys, /usr."
    rationale: "If sensitive directories are mounted in read-write mode, it could be possible to make changes to files within them. This has obvious security implications and should be avoided."
    remediation: "You should not mount directories which are security sensitive on the host within containers, especially in read-write mode."
    compliance:
      - cis: ["5.6"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"{{ .Mounts }}\"" -> r:bind\s+/\s+|bind\s+/boot\s+|bind\s+/dev\s+|bind\s+/etc\s+|bind\s+/lib\s+|bind\s+/proc\s+|bind\s+/sys\s+|bind\s+/usr\s+'

  - id: 10170
    title: "Ensure sshd is not run within containers."
    description: "The SSH daemon should not be running within the container. You should SSH into the Docker host, and use docker exec to enter a container."
    rationale: "Running SSH within the container increases the complexity of security management by making it: Difficult to manage access policies and security compliance for SSH server; Difficult to manage keys and passwords across various containers; Difficult to manage security upgrades for SSH server. It is possible to have shell access to a container without using SSH, the needlessly increasing the complexity of security management should be avoided."
    remediation: "Uninstall the SSH daemon from the container and use docker exec to enter a container on the remote host."
    compliance:
      - cis: ["5.7"]
    condition: none
    rules:
      - 'c:sh -c "for container in \$(docker ps --quiet); do docker exec \"\$container\" ps -el 2>/dev/null | grep -c sshd; done" -> n:^(\d+) compare > 0'

  - id: 10171
    title: "Ensure privileged ports are not mapped within containers."
    description: "The TCP/IP port numbers below 1024 are considered privileged ports. Normal users and processes are not allowed to use them for various security reasons. Docker does, however allow a container port to be mapped to a privileged port."
    rationale: "By default, if the user does not specifically declare a container port to host port mapping, Docker automatically and correctly maps the container port to one available in the 49153-65535 range on the host. Docker does, however, allow a container port to be mapped to a privileged port on the host if the user explicitly declares it. This is because containers are executed with NET_BIND_SERVICE Linux kernel capability which does not restrict privileged port mapping. The privileged ports receive and transmit various pieces of data which are security sensitive and allowing containers to use them is not in line with good security practice."
    remediation: "You should not map container ports to privileged host ports when starting a container. You should also, ensure that there is no such container to host privileged port mapping declarations in the Dockerfile."
    compliance:
      - cis: ["5.8"]
    condition: none
    rules:
      - 'c:sh -c "for container in \$(docker ps --quiet --all); do docker port \$container; done" 2>/dev/null -> n:(\d+)$ compare <= 1024'

  - id: 10172
    title: "Ensure that only needed ports are open on the container."
    description: "The dockerfile for a container image defines the ports which are opened by default on a container instance. The list of ports are relevant to the application you are running within the container and should only be open if they are needed."
    rationale: "A container can be run with only the ports defined in the Dockerfile for its image or can alternatively be arbitrarily passed run time parameters to open a list of ports. Additionally, in the course of time, the Dockerfile may undergo various changes and the list of exposed ports may or may not still be relevant to the application you are running within the container. Opening unneeded ports increases the attack surface of the container and the associated containerized application. Good security practice is to only open ports that are needed for the correct operation of the application."
    remediation: "You should ensure that the Dockerfile for each container image only exposes needed ports. You can also completely ignore the list of ports defined in the Dockerfile by NOT using -P (UPPERCASE) or the --publish-all flag when starting the container. Instead, use the -p (lowercase) or --publish flag to explicitly define the ports that you need for a particular container instance."
    compliance:
      - cis: ["5.9"]
    condition: none
    rules:
      - 'c:sh -c "for container in \$(docker ps --quiet --all); do docker port \$container; done" 2>/dev/null -> r:\.+'

  - id: 10173
    title: "Ensure that the host's network namespace is not shared."
    description: "When the networking mode on a container is set to --net=host, the container is not placed inside a separate network stack. Effectively, applying this option instructs Docker to not containerize the container's networking. The consequence of this is that the container lives \"outside\" in the main Docker host and has full access to its network interfaces."
    rationale: "Selecting this option is potentially dangerous. It allows the container process to open reserved low numbered ports in the way that any other root process can. It also allows the container to access network services such as D-bus on the Docker host. A container process could potentially carry out undesired actions, such as shutting down the Docker host. This option should not be used unless there is a very specific reason for enabling it."
    remediation: "You should not pass the --net=host option when starting any container."
    compliance:
      - cis: ["5.10"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"NetworkMode={{ .HostConfig.NetworkMode }}\"" -> r:^NetworkMode=host$'

  - id: 10174
    title: "Ensure that the memory usage for containers is limited."
    description: "By default, all containers on a Docker host share resources equally. By using the resource management capabilities of the Docker host, you can control the amount of memory that a container is able to use."
    rationale: "By default a container can use all of the memory on the host. You can use memory limit mechanisms to prevent a denial of service occurring where one container consumes all of the host's resources and other containers on the same host are therefore not able to function. Having no limit on memory usage can lead to issues where one container can easily make the whole system unstable and as a result unusable."
    remediation: "You should run the container with only as much memory as it requires by using the --memory argument. For example, you could run a container using the command: \"docker run -d --memory 256m centos sleep 1000\"."
    compliance:
      - cis: ["5.11"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"Memory={{ .HostConfig.Memory }}\"" -> n:Memory=(\d+)$ compare == 0'

  - id: 10175
    title: "Ensure that CPU priority is set appropriately on containers."
    description: "By default, all containers on a Docker host share resources equally. By using the resource management capabilities of the Docker host you can control the host CPU resources that a container may consume."
    rationale: "By default, CPU time is divided between containers equally. If you wish to control available CPU resources amongst container instances, you can use the CPU sharing feature. CPU sharing allows you to prioritize one container over others and prevents lower priority containers from absorbing CPU resources which may be required by other processes. This ensures that high priority containers are able to claim the CPU runtime they require."
    remediation: "You should manage the CPU runtime between your containers dependent on their priority within your organization. To do so start the container using the --cpu-shares argument. For example, you could run a container as: \"docker run -d --cpu-shares 512 centos sleep 1000\"."
    compliance:
      - cis: ["5.12"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"CpuShares={{ .HostConfig.CpuShares }}\"" -> n:CpuShares=(\d+)$ compare == 0'

  - id: 10176
    title: "Ensure that the container's root filesystem is mounted as read only."
    description: "The container's root filesystem should be treated as a 'golden image' by using Docker run's --read-only option. This prevents any writes to the container's root filesystem at container runtime and enforces the principle of immutable infrastructure."
    rationale: "Enabling this option forces containers at runtime to explicitly define their data writing strategy to persist or not persist their data. This also reduces security attack vectors since the container instance's filesystem cannot be tampered with or written to unless it has explicit read-write permissions on its filesystem folder and directories."
    remediation: "You should add a --read-only flag at a container's runtime to enforce the container's root filesystem being mounted as read only. For example: \"docker run <Run arguments> --read-only <Container Image Name or ID> <Command>\"."
    compliance:
      - cis: ["5.13"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"ReadonlyRootfs={{ .HostConfig.ReadonlyRootfs }}\"" -> r:^ReadonlyRootfs=false$'

  - id: 10177
    title: "Ensure that incoming container traffic is bound to a specific host interface."
    description: "By default, Docker containers can make connections to the outside world, but the outside world cannot connect to containers and each outgoing connection will appear to originate from one of the host machine's own IP addresses. You should only allow container services to be contacted through a specific external interface on the host machine."
    rationale: "If you have multiple network interfaces on your host machine, the container can accept connections on exposed ports on any network interface. This might not be desirable and may not be secured. In many cases a specific, desired interface is exposed externally and services such as intrusion detection, intrusion prevention, firewall, load balancing, etc. are all run by intention there to screen incoming public traffic. You should therefore not accept incoming connections on any random interface, but only the one designated for this type of traffic."
    remediation: "You should bind the container port to a specific host interface on the desired host port. For example: \"docker run --detach --publish 10.2.3.4:49153:80 nginx\"."
    compliance:
      - cis: ["5.14"]
    condition: none
    rules:
      - 'c:sh -c "for container in \$(docker ps --quiet --all); do docker port \$container; done" -> r:0.0.0.0:\d+$'

  - id: 10178
    title: "Ensure that the 'on-failure' container restart policy is set to '5'."
    description: "By using the --restart flag in the docker run command you can specify a restart policy for how a container should or should not be restarted on exit. You should choose the on-failure restart policy and limit the restart attempts to 5."
    rationale: "If you indefinitely keep trying to start the container, it could possibly lead to a denial of service on the host. It could be an easy way to do a distributed denial of service attack especially if you have many containers on the same host. Additionally, ignoring the exit status of the container and always attempting to restart the container, leads to noninvestigation of the root cause behind containers getting terminated. If a container gets terminated, you should investigate the reason behind it instead of just attempting to restart it indefinitely. You should use the on-failure restart policy to limit the number of container restarts to a maximum of 5 attempts."
    remediation: "If you wish a container to be automatically restarted, a sample command is as below: \"docker run --detach --restart=on-failure:5 nginx\"."
    compliance:
      - cis: ["5.15"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"MaximumRetryCount={{ .HostConfig.RestartPolicy.MaximumRetryCount }}\"" -> n:MaximumRetryCount=(\d+) compare > 5'

  - id: 10179
    title: "Ensure that the host's process namespace is not shared."
    description: "The Process ID (PID) namespace isolates the process ID space, meaning that processes in different PID namespaces can have the same PID. This creates process level isolation between the containers and the host."
    rationale: "PID namespace provides separation between processes. It prevents system processes from being visible, and allows process ids to be reused including PID 1. If the host's PID namespace is shared with containers, it would basically allow these to see all of the processes on the host system. This reduces the benefit of process level isolation between the host and the containers. Under these circumstances a malicious user who has access to a container could get access to processes on the host itself, manipulate them, and even be able to kill them. This could allow for the host itself being shut down, which could be extremely serious, particularly in a multi-tenanted environment. You should not share the host's process namespace with the containers running on it."
    remediation: "You should not start a container with the --pid=host argument. For example, do not start a container with the command: \"docker run --interactive --tty --pid=host centos /bin/bash\"."
    compliance:
      - cis: ["5.16"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"PidMode={{ .HostConfig.PidMode }}\"" -> r:^PidMode=host$'

  - id: 10180
    title: "Ensure that the host's IPC namespace is not shared."
    description: "IPC (POSIX/SysV IPC) namespace provides separation of named shared memory segments, semaphores and message queues. The IPC namespace on the host should therefore not be shared with containers and should remain isolated."
    rationale: "The IPC namespace provides separation of IPC between the host and containers. If the host's IPC namespace is shared with the container, it would allow processes within the container to see all of IPC communications on the host system. This would remove the benefit of IPC level isolation between host and containers. An attacker with access to a container could get access to the host at this level with major consequences. The IPC namespace should therefore not be shared between the host and its containers."
    remediation: "You should not start a container with the --ipc=host argument. For example, do not start a container with the command: \"docker run --interactive --tty --ipc=host centos /bin/bash\"."
    compliance:
      - cis: ["5.17"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"IpcMode={{ .HostConfig.IpcMode }}\"" -> r:^IpcMode=host$'

  - id: 10181
    title: "Ensure that host devices are not directly exposed to containers."
    description: "Host devices can be directly exposed to containers at runtime. Do not directly expose host devices to containers, especially to containers that are not trusted."
    rationale: "The --device option exposes host devices to containers and as a result of this, containers can directly access these devices. The container would not need to run in privileged mode to access and manipulate them, as by default, the container is granted this type of access. Additionally, it would be possible for containers to remove block devices from the host. You therefore should not expose host devices to containers directly. If for some reason you wish to expose the host device to a container you should consider which sharing permissions you wish to use on a case by case base as appropriate to your organization: r - read only, w - writable, m - mknod allowed."
    remediation: "You should not directly expose host devices to containers. If you do need to expose host devices to containers, you should use granular permissions as appropriate to your organization. For example, do not start a container using the command: \"docker run --interactive --tty --device=/dev/tty0:/dev/tty0:rwm --device=/dev/temp_sda:/dev/temp_sda:rwm centos bash\". You should only share the host device using appropriate permissions: \"docker run --interactive --tty --device=/dev/tty0:/dev/tty0:rw --device=/dev/temp_sda:/dev/temp_sda:r centos bash\"."
    compliance:
      - cis: ["5.18"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"Devices={{ .HostConfig.Devices }}\" | grep -vP \"^Devices=($|<no value>|\\[\\])\"" -> r:^Devices'

  - id: 10182
    title: "Ensure that the default ulimit is overwritten at runtime if needed."
    description: "The default ulimit is set at the Docker daemon level. However, if you need to, you may override the default ulimit setting during container runtime."
    rationale: "ulimit provides control over the resources available to the shell and to processes started by it. Setting system resource limits in a prudent fashion, protects against denial of service conditions. On occasion, legitimate users and processes can accidentally overuse system resources and cause systems to be degraded or even unresponsive. The default ulimit set at the Docker daemon level should be honored. If the default ulimit settings are not appropriate for a particular container instance, you may override them as an exception, but this should not be done routinely. If many of your container instances are exceeding your ulimit settings, you should consider changing the default settings to something that is more appropriate for your needs."
    remediation: "You should only override the default ulimit settings if needed in a specific case. For example, to override default ulimit settings start a container as: \"docker run -ti -d --ulimit nofile=1024:1024 centos sleep 1000\"."
    compliance:
      - cis: ["5.19"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"Ulimits={{ .HostConfig.Ulimits }}\"" -> r:^Ulimits=$|^Ulimits=[]$|^Ulimits=\<no\s*value>$'

  - id: 10183
    title: "Ensure mount propagation mode is not set to shared."
    description: "Mount propagation mode allows mounting volumes in shared, slave or private mode on a container. Do not use shared mount propagation mode unless explicitly needed."
    rationale: "A shared mount is replicated at all mounts and changes made at any mount point are propagated to all other mount points. Mounting a volume in shared mode does not restrict any other container from mounting and making changes to that volume. As this is likely not a desirable option from a security standpoint, this feature should not be used unless explicitly required."
    remediation: "Do not mount volumes in shared mode propagation. For example, do not start a container as: \"docker run <Run arguments> --volume=/hostPath:/containerPath:shared <Container Image Name or ID> <Command>\"."
    compliance:
      - cis: ["5.20"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"Propagation={{range .Mounts}} {{.Propagation}} {{end}}\"" -> r:shared'

  - id: 10184
    title: "Ensure that the host's UTS namespace is not shared."
    description: "UTS namespaces provide isolation between two system identifiers: the hostname and the NIS domain name. It is used to set the hostname and the domain which are visible to running processes in that namespace. Processes running within containers do not typically require to know either the hostname or the domain name. The UTS namespace should therefore not be shared with the host."
    rationale: "Sharing the UTS namespace with the host provides full permission for each container to change the hostname of the host. This is not in line with good security practice and should not be permitted."
    remediation: "You should not start a container with the --uts=host argument. For example, do not start a container with the command: \"docker run --rm --interactive --tty --uts=host rhel7.2\"."
    compliance:
      - cis: ["5.21"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"UTSMode={{ .HostConfig.UTSMode }}\"" -> r:^UTSMode=host$'

  - id: 10185
    title: "Ensure the default seccomp profile is not Disabled."
    description: "Seccomp filtering provides a means for a process to specify a filter for incoming system calls. The default Docker seccomp profile works on a whitelist basis and allows for a large number of common system calls, whilst blocking all others. This filtering should not be disabled unless it causes a problem with your container application usage."
    rationale: "A large number of system calls are exposed to every userland process with many of them going unused for the entire lifetime of the process. Most applications do not need all these system calls and would therefore benefit from having a reduced set of available system calls. Having a reduced set of system calls reduces the total kernel surface exposed to the application and thus improvises application security."
    remediation: "By default, seccomp profiles are enabled. You do not need to do anything unless you want to modify and use a modified seccomp profile."
    compliance:
      - cis: ["5.22"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"SecurityOpt={{ .HostConfig.SecurityOpt }}\"" -> r:seccomp:unconfined|seccomp=unconfined'

  - id: 10186
    title: "Ensure that cgroup usage is confirmed."
    description: "It is possible to attach to a particular cgroup when a container is instantiated. Confirming cgroup usage would ensure that containers are running in defined cgroups."
    rationale: "System administrators typically define cgroups in which containers are supposed to run. If cgroups are not explicitly defined by the system administrator, containers run in the docker cgroup by default. At run time, it is possible to attach a container to a different cgroup other than the one originally defined. This usage should be monitored and confirmed, as by attaching to a different cgroup, excess permissions and resources might be granted to the container and this can therefore prove to be a security risk."
    remediation: "You should not use the --cgroup-parent option within the docker run command unless strictly required."
    compliance:
      - cis: ["5.25"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"CgroupParent={{ .HostConfig.CgroupParent }}\"" -> r:^CgroupParent=\.+'

  - id: 10187
    title: "Ensure that the container is restricted from acquiring additional privileges."
    description: "You should restrict the container from acquiring additional privileges via suid or sgid bits."
    rationale: "A process can set the no_new_priv bit in the kernel and this persists across forks, clones and execve. The no_new_priv bit ensures that the process and its child processes do not gain any additional privileges via suid or sgid bits. This reduces the danger associated with many operations because the possibility of subverting privileged binaries is lessened."
    remediation: "You should start your container with the options below: \"docker run --rm -it --security-opt=no-new-privileges ubuntu bash\"."
    compliance:
      - cis: ["5.26"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"SecurityOpt={{ .HostConfig.SecurityOpt }}\" | grep -v no-new-privileges" -> r:SecurityOpt='

  - id: 10188
    title: "Ensure that container health is checked at runtime."
    description: "If the container image does not have an HEALTHCHECK instruction defined, you should use the --health-cmd parameter at container runtime to check container health."
    rationale: "If the container image you are using does not have a pre-defined HEALTHCHECK instruction, use the --health-cmd parameter to check container health at runtime. Based on the reported health status, remedial actions can be taken if necessary."
    remediation: "You should run the container using the --health-cmd parameter. For example: \"docker run -d --health-cmd='stat /etc/passwd || exit 1' nginx\"."
    compliance:
      - cis: ["5.27"]
    condition: none
    rules:
      - 'c:sh -c "for container in \$(docker ps --quiet --all); do if docker inspect --format=\"Health={{ .State.Health.Status }}\" \$container 2>/dev/null | grep -q \"Health=\"; then docker inspect --format=\"Health={{ .State.Health.Status }}\" \$container; else echo \"no_health_check\"; fi; done" -> r:no_health_check'

  - id: 10189
    title: "Ensure that the PIDs cgroup limit is used."
    description: "You should use the --pids-limit flag at container runtime."
    rationale: "Attackers could launch a fork bomb with a single command inside the container. This fork bomb could crash the entire system and would require a restart of the host to make the system functional again. Using the PIDs cgroup parameter --pids-limit would prevent this kind of attack by restricting the number of forks that can happen inside a container within a specified time frame."
    remediation: "Use --pids-limit flag with an appropriate value when launching the container. For example: \"docker run -it --pids-limit 100 <Image ID>\". In the above example, the number of processes allowed to run at any given time is set to 100. After a limit of 100 concurrently running processes is reached, Docker would restrict any new process creation."
    compliance:
      - cis: ["5.29"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"PidsLimit={{ .HostConfig.PidsLimit }}\"" -> r:^PidsLimit=\<nil>|^PidsLimit=0$|^PidsLimit=-1$'

  - id: 10190
    title: "Ensure that Docker's default bridge \"docker0\" is not used."
    description: "You should not use Docker's default bridge docker0. Instead you should use Docker's user-defined networks for container networking."
    rationale: "Docker connects virtual interfaces created in bridge mode to a common bridge called docker0. This default networking model is vulnerable to ARP spoofing and MAC flooding attacks as there is no filtering applied to it."
    remediation: "You should follow the Docker documentation and set up a user-defined network. All the containers should be run in this network."
    compliance:
      - cis: ["5.30"]
    condition: none
    rules:
      - 'c:sh -c "for network in \$(docker network ls --quiet 2>/dev/null); do if docker network inspect --format \"{{ .Options }}\" \$network 2>/dev/null | grep \"com.docker.network.bridge.name:docker0\" >/dev/null 2>&1; then docker0Containers=\$(docker network inspect --format=\"{{ range .Containers }}{{ .Name }} {{ end }}\" \$network | sed -e \"s/^ //\" -e \"s/  /\n/g\" 2>/dev/null); echo \"\$docker0Containers\"; fi; done" -> r:\.+'

  - id: 10191
    title: "Ensure that the host's user namespaces are not shared."
    description: "You should not share the host's user namespaces with containers running on it."
    rationale: "User namespaces ensure that a root process inside the container will be mapped to a non-root process outside the container. Sharing the user namespaces of the host with the container does not therefore isolate users on the host from users in the containers."
    remediation: "You should not share user namespaces between host and containers. For example, you should not run the command: \"docker run --rm -it --userns=host ubuntu bash\"."
    compliance:
      - cis: ["5.31"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"UsernsMode={{ .HostConfig.UsernsMode }}\"" -> r:^UsernsMode=host$'

  - id: 10192
    title: "Ensure that the Docker socket is not mounted inside any container."
    description: "The Docker socket docker.sock should not be mounted inside a container."
    rationale: "If the Docker socket is mounted inside a container it could allow processes running within the container to execute Docker commands which would effectively allow for full control of the host."
    remediation: "You should ensure that no containers mount docker.sock as a volume."
    compliance:
      - cis: ["5.32"]
    condition: none
    rules:
      - 'c:sh -c "docker ps --quiet --all | xargs docker inspect --format \"{{ .Mounts }}\"" -> r:docker.sock'

  - id: 10193
    title: "Ensure that the minimum number of manager nodes have been created in a swarm."
    description: "You should ensure that the minimum number of required manager nodes is created in a swarm."
    rationale: "Manager nodes within a swarm have control over the swarm and can change its configuration, including modifying security parameters. Having excessive manager nodes could render the swarm more susceptible to compromise. If fault tolerance is not required in the manager nodes, a single node should be elected as a manager. If fault tolerance is required then the smallest odd number to achieve the appropriate level of tolerance should be configured. This should always be an odd number in order to ensure that a quorum is reached."
    remediation: "If an excessive number of managers is configured, the excess nodes can be demoted to workers using the following command: \"docker node demote <ID>\". Where <ID> is the node ID value of the manager to be demoted."
    compliance:
      - cis: ["7.1"]
    condition: any
    rules:
      - 'c:docker info -> r:Swarm:\s*inactive'
      - 'c:sh -c "if docker info 2>/dev/null | grep -e \"Swarm: active\" >/dev/null 2>&1; then echo \$(docker node ls | grep -c Leader); fi" -> n:^(\d+) compare == 1'

  - id: 10194
    title: "Ensure that swarm services are bound to a specific host interface."
    description: "By default, Docker swarm services will listen on all interfaces on the host. This may not be necessary for the operation of the swarm where the host has multiple network interfaces."
    rationale: "When a swarm is initialized the default value for the --listen-addr flag is 0.0.0.0:2377 which means that swarm services will listen on all interfaces on the host. If a host has multiple network interfaces this may be undesirable as it could expose swarm services to networks which are not involved with the operation of the swarm. By passing a specific IP address to the --listen-addr, a specific network interface can be specified, limiting this exposure."
    remediation: "Resolving this issue requires re-initialization of the swarm, specifying a specific interface for the --listen-addr parameter."
    compliance:
      - cis: ["7.2"]
    condition: any
    rules:
      - 'c:docker info -> r:Swarm:\s*inactive'
      - 'c:sh -c "if docker info 2>/dev/null | grep -e \"Swarm: active\" >/dev/null 2>&1; then echo \$(ss -lp | grep -P \"\\[::\\]:2377|:::2377|\\*\\:2377|0\\.0\\.0\\.0:2377|\\[::\\]:7946|:::7946|\\*\\:7946|0\\.0\\.0\\.0:7946\" | grep -E \"2377|7946\" | grep -c \"2377\\|7946\"); fi" -> n:^(\d+) compare == 0'

  - id: 10195
    title: "Ensure that all Docker swarm overlay networks are encrypted."
    description: "Ensure that all Docker swarm overlay networks are encrypted."
    rationale: "By default, data exchanged between containers on nodes on the overlay network is not encrypted. This could potentially expose traffic between containers."
    remediation: "You should create overlay networks with the --opt encrypted flag."
    compliance:
      - cis: ["7.3"]
    condition: any
    rules:
      - 'c:docker info -> r:Swarm:\s*inactive'
      - 'c:sh -c "docker network ls --filter driver=overlay --quiet 2>&1 | xargs docker network inspect --format \"{{.Name}} {{ .Options }}\" 2>&1 | grep -vc encrypted:" -> n:^(\d+) compare == 0'

  - id: 10196
    title: "Ensure that Docker's secret management commands are used for managing secrets in a swarm cluster."
    description: "You should use Docker's in-built secret management command for control of secrets."
    rationale: "Docker has various commands for managing secrets in a swarm cluster."
    remediation: "You should follow the docker secret documentation and use it to manage secrets effectively."
    compliance:
      - cis: ["7.4"]
    condition: any
    rules:
      - 'c:docker info -> r:Swarm:\s*inactive'
      - 'c:sh -c "docker secret ls --quiet 2>&1 | wc -l" -> n:^(\d+) compare >= 1'

  - id: 10197
    title: "Ensure that swarm manager is run in auto-lock mode."
    description: "You should review whether you wish to run Docker swarm manager in auto-lock mode."
    rationale: "When Docker restarts, both the TLS key used to encrypt communication among swarm nodes, and the key used to encrypt and decrypt Raft logs on disk, are loaded into each manager node's memory. You could protect the mutual TLS encryption key and the key used to encrypt and decrypt Raft logs at rest. This protection could be enabled by initializing the swarm with the --autolock flag. With --autolock enabled, when Docker restarts, you must unlock the swarm first, using a key encryption key generated by Docker when the swarm was initialized. This has benefits in a high security environment, however these should be balanced against the support issues caused by the swarm not starting automatically if for example, the host were to experience an outage."
    remediation: "If you are initializing a swarm, use the command: \"docker swarm init --autolock\". If you want to set --autolock on an existing swarm manager node, use the following command: \"docker swarm update --autolock\"."
    compliance:
      - cis: ["7.5"]
    condition: any
    rules:
      - 'c:docker info -> r:Swarm:\s*inactive'
      - 'c:sh -c "docker info --format \"Swarm Autolock: {{ .Swarm.Cluster.Spec.EncryptionConfig.AutoLockManagers }}\"" -> r:Swarm\s*Autolock:\s*true'

2. Change the ownership and permission of the file so that the root user and the wazuh group have access to it:

# chown root:wazuh /var/ossec/etc/sca_docker_audit.yml
# chmod 640 /var/ossec/etc/sca_docker_audit.yml

3. Enable the policy by appending the following configuration to the /var/ossec/etc/ossec.conf file on the monitored endpoint:

<ossec_config>
  <sca>
    <enabled>yes</enabled>
    <scan_on_start>yes</scan_on_start>
    <interval>24h</interval>
    <skip_nfs>yes</skip_nfs>
    <policies> 
      <policy>/var/ossec/etc/sca_docker_audit.yml</policy>  
    </policies>
  </sca>
</ossec_config>

4. Restart the Wazuh agent to apply the changes:

# systemctl restart wazuh-agent

Visualizing the scan results

Navigate to the Configuration Assessment page on the Wazuh dashboard. Select the monitored Docker endpoint, and then select CIS Docker Benchmark v1.7.0  to view the scan results.

Docker Scan Results

See sample scan results below:

CIS Docker Benchmark

Conclusion

In addition to performing configuration checks, you can also enable the Wazuh Docker listener to monitor Docker in real time. The Docker listener monitors user interaction with Docker resources, such as detecting image creation and deletion, and generating alerts when users open  container interactive shells. You can also monitor container runtime logs.

Securing your Docker infrastructure is a critical step in safeguarding your applications and data. By leveraging the Wazuh SCA module, you can automate much of the compliance checking process against the CIS Docker Benchmark. However, it’s important to recognize that some checks require manual review and adjustment based on the specific security policies and requirements of your organization.

Implementing these automated checks, along with manual assessments where needed, will provide a comprehensive approach to Docker security. Regularly review your compliance status and update your policies as necessary to keep up with evolving security threats.

References