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