Implementing CIS Docker Benchmark

Implementing CIS Docker Benchmark

The Center for Internet Security (CIS) Docker Benchmark provides comprehensive security guidelines for Docker deployments. These guidelines cover host configuration, Docker daemon settings, container images, and runtime configurations. Implementing CIS benchmarks provides a strong security baseline while demonstrating due diligence to auditors.

Host configuration requirements form the foundation of CIS Docker compliance. Separate partitions for Docker data prevent resource exhaustion. Audit rules track Docker daemon activities. User namespace remapping provides additional isolation. These host-level controls create secure foundations for container deployments. Regular assessment ensures continued compliance as systems evolve.

#!/bin/bash
# Example: CIS Docker Benchmark implementation script

# Script to implement and verify CIS Docker Benchmark controls
set -e

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

echo "CIS Docker Benchmark Implementation Script"
echo "========================================="

# Function to check and report status
check_status() {
    local check_name=$1
    local status=$2
    local message=$3
    
    if [ "$status" = "PASS" ]; then
        echo -e "${GREEN}[PASS]${NC} $check_name"
    elif [ "$status" = "FAIL" ]; then
        echo -e "${RED}[FAIL]${NC} $check_name - $message"
    else
        echo -e "${YELLOW}[WARN]${NC} $check_name - $message"
    fi
}

# 1.1 Host Configuration
echo -e "\n1. Host Configuration"
echo "---------------------"

# 1.1.1 Create separate partition for containers
check_docker_partition() {
    if mountpoint -q /var/lib/docker; then
        check_status "1.1.1 Separate partition for containers" "PASS" ""
    else
        check_status "1.1.1 Separate partition for containers" "FAIL" "/var/lib/docker is not a separate partition"
        
        # Remediation guidance
        echo "   Remediation: Create separate partition for /var/lib/docker"
        echo "   Example: Add to /etc/fstab:"
        echo "   /dev/sdb1 /var/lib/docker ext4 defaults 0 0"
    fi
}

# 1.1.2 Harden container host
harden_host() {
    # Remove unnecessary packages
    echo "Removing unnecessary packages..."
    
    # Update system
    apt-get update && apt-get upgrade -y
    
    # Install required packages
    apt-get install -y \
        auditd \
        apparmor \
        apparmor-utils
    
    # Enable and configure auditd
    cat > /etc/audit/rules.d/docker.rules <<EOF
# Docker audit rules
-w /usr/bin/docker -p wa
-w /var/lib/docker -p wa
-w /etc/docker -p wa
-w /lib/systemd/system/docker.service -p wa
-w /lib/systemd/system/docker.socket -p wa
-w /usr/bin/containerd -p wa
-w /usr/bin/runc -p wa
EOF
    
    systemctl restart auditd
    check_status "1.1.2 Host hardening" "PASS" "Audit rules configured"
}

# 2. Docker Daemon Configuration
echo -e "\n2. Docker Daemon Configuration"
echo "------------------------------"

# 2.1 Configure Docker daemon
configure_docker_daemon() {
    local daemon_file="/etc/docker/daemon.json"
    
    # Create secure daemon configuration
    cat > $daemon_file <<EOF
{
    "icc": false,
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "100m",
        "max-file": "5"
    },
    "userland-proxy": false,
    "disable-legacy-registry": true,
    "live-restore": true,
    "no-new-privileges": true,
    "seccomp-profile": "/etc/docker/seccomp.json",
    "storage-driver": "overlay2",
    "storage-opts": [
        "overlay2.override_kernel_check=true"
    ],
    "authorization-plugins": [],
    "default-ulimits": {
        "nofile": {
            "Hard": 64000,
            "Soft": 64000
        }
    },
    "features": {
        "buildkit": true
    }
}
EOF
    
    # Set proper permissions
    chmod 644 $daemon_file
    
    # Restart Docker
    systemctl restart docker
    
    check_status "2.1 Docker daemon configuration" "PASS" "Secure configuration applied"
}

# 2.2 Configure TLS for Docker daemon
configure_docker_tls() {
    local cert_dir="/etc/docker/certs"
    mkdir -p $cert_dir
    
    # Generate CA certificate
    openssl genrsa -out $cert_dir/ca-key.pem 4096
    openssl req -new -x509 -days 365 -key $cert_dir/ca-key.pem \
        -sha256 -out $cert_dir/ca.pem -subj "/C=US/ST=State/L=City/O=Company/CN=docker-ca"
    
    # Generate server certificate
    openssl genrsa -out $cert_dir/server-key.pem 4096
    openssl req -subj "/CN=$(hostname)" -sha256 -new \
        -key $cert_dir/server-key.pem -out $cert_dir/server.csr
    
    # Sign server certificate
    echo subjectAltName = DNS:$(hostname),IP:127.0.0.1 > $cert_dir/extfile.cnf
    openssl x509 -req -days 365 -sha256 -in $cert_dir/server.csr \
        -CA $cert_dir/ca.pem -CAkey $cert_dir/ca-key.pem \
        -out $cert_dir/server-cert.pem -extfile $cert_dir/extfile.cnf
    
    # Set permissions
    chmod 400 $cert_dir/*-key.pem
    chmod 444 $cert_dir/*.pem
    
    check_status "2.2 Docker TLS configuration" "PASS" "TLS certificates generated"
}

# 3. Docker Runtime Security
echo -e "\n3. Docker Runtime Security"
echo "--------------------------"

# 3.1 AppArmor profiles
configure_apparmor() {
    # Create custom AppArmor profile for containers
    cat > /etc/apparmor.d/docker-default-cis <<EOF
#include <tunables/global>

profile docker-default-cis flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>

  network,
  capability,
  file,
  umount,

  # Deny potentially dangerous operations
  deny @{PROC}/** w,
  deny /sys/** w,
  deny mount,
  deny umount,
  deny pivot_root,
  deny ptrace,

  # Allow necessary operations
  /usr/bin/** ix,
  /bin/** ix,
  /lib/** r,
  
  # Prevent writing to root filesystem
  deny / w,
  deny /root/** w,
  deny /etc/** w,
}
EOF
    
    # Load profile
    apparmor_parser -r /etc/apparmor.d/docker-default-cis
    
    check_status "3.1 AppArmor profiles" "PASS" "Custom profile loaded"
}

# 3.2 Seccomp profiles
configure_seccomp() {
    local seccomp_file="/etc/docker/seccomp.json"
    
    # Create restrictive seccomp profile
    cat > $seccomp_file <<'EOF'
{
    "defaultAction": "SCMP_ACT_ERRNO",
    "architectures": [
        "SCMP_ARCH_X86_64",
        "SCMP_ARCH_X86",
        "SCMP_ARCH_X32"
    ],
    "syscalls": [
        {
            "names": [
                "accept", "accept4", "access", "alarm", "bind",
                "brk", "chdir", "chmod", "chown", "clock_gettime",
                "clone", "close", "connect", "dup", "dup2", "dup3",
                "epoll_create", "epoll_create1", "epoll_ctl", "epoll_wait",
                "execve", "exit", "exit_group", "fchdir", "fchmod",
                "fchown", "fcntl", "fstat", "fsync", "ftruncate",
                "futex", "getcwd", "getdents", "getdents64", "getegid",
                "geteuid", "getgid", "getpgrp", "getpid", "getppid",
                "getrlimit", "getsockname", "getsockopt", "getuid",
                "ioctl", "kill", "listen", "lseek", "madvise", "mkdir",
                "mmap", "mprotect", "munmap", "nanosleep", "open",
                "openat", "pipe", "poll", "pread64", "pwrite64",
                "read", "readlink", "recvfrom", "recvmsg", "rename",
                "rt_sigaction", "rt_sigprocmask", "rt_sigreturn",
                "sched_getaffinity", "sched_yield", "select", "sendmsg",
                "sendto", "set_tid_address", "setgid", "setgroups",
                "setsockopt", "setuid", "shutdown", "sigaltstack",
                "socket", "stat", "statfs", "sysinfo", "umask",
                "uname", "unlink", "wait4", "write"
            ],
            "action": "SCMP_ACT_ALLOW"
        }
    ]
}
EOF
    
    chmod 644 $seccomp_file
    check_status "3.2 Seccomp profile" "PASS" "Restrictive profile created"
}

# 4. Image Security
echo -e "\n4. Image Security"
echo "-----------------"

# 4.1 Image scanning policy
create_image_policy() {
    cat > /etc/docker/policies/image-policy.json <<EOF
{
    "version": "1.0",
    "rules": [
        {
            "action": "DENY",
            "gate": "vulnerabilities",
            "trigger": "package",
            "params": {
                "package_type": "all",
                "severity_comparison": ">=",
                "severity": "high"
            }
        },
        {
            "action": "DENY",
            "gate": "dockerfile",
            "trigger": "exposed_ports",
            "params": {
                "ports": "22,23,3389",
                "type": "blacklist"
            }
        },
        {
            "action": "WARN",
            "gate": "dockerfile",
            "trigger": "no_user",
            "params": {}
        }
    ]
}
EOF
    
    check_status "4.1 Image scanning policy" "PASS" "Policy created"
}

# 5. Runtime Security Policies
echo -e "\n5. Runtime Security Policies"
echo "----------------------------"

# Create security policies for container runtime
create_runtime_policies() {
    # PodSecurityPolicy for Kubernetes environments
    cat > /etc/docker/policies/pod-security-policy.yaml <<EOF
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
  name: cis-restricted
spec:
  privileged: false
  allowPrivilegeEscalation: false
  requiredDropCapabilities:
    - ALL
  volumes:
    - 'configMap'
    - 'emptyDir'
    - 'projected'
    - 'secret'
    - 'downwardAPI'
    - 'persistentVolumeClaim'
  hostNetwork: false
  hostIPC: false
  hostPID: false
  runAsUser:
    rule: 'MustRunAsNonRoot'
  seLinux:
    rule: 'RunAsAny'
  supplementalGroups:
    rule: 'RunAsAny'
  fsGroup:
    rule: 'RunAsAny'
  readOnlyRootFilesystem: true
  defaultAddCapabilities: []
  defaultAllowPrivilegeEscalation: false
  allowedHostPaths: []
  allowedFlexVolumes: []
  allowedUnsafeSysctls: []
  forbiddenSysctls:
    - "*"
EOF
    
    check_status "5.1 Runtime security policies" "PASS" "Policies created"
}

# 6. Compliance Reporting
echo -e "\n6. Compliance Reporting"
echo "-----------------------"

generate_compliance_report() {
    local report_file="/var/log/docker-cis-compliance-$(date +%Y%m%d).json"
    
    # Run compliance checks and generate report
    docker run --rm --net host --pid host --userns host --cap-add audit_control \
        -e DOCKER_CONTENT_TRUST=$DOCKER_CONTENT_TRUST \
        -v /var/lib:/var/lib \
        -v /var/run/docker.sock:/var/run/docker.sock \
        -v /usr/lib/systemd:/usr/lib/systemd \
        -v /etc:/etc --label docker_bench_security \
        docker/docker-bench-security > $report_file
    
    check_status "6.1 Compliance report generation" "PASS" "Report saved to $report_file"
}

# Main execution
main() {
    echo "Starting CIS Docker Benchmark implementation..."
    
    check_docker_partition
    harden_host
    configure_docker_daemon
    configure_docker_tls
    configure_apparmor
    configure_seccomp
    create_image_policy
    create_runtime_policies
    generate_compliance_report
    
    echo -e "\nCIS Docker Benchmark implementation complete!"
    echo "Please review any failed checks and implement remediations."
}

# Run main function
main