Ana içeriğe geç
Kategoriye Dön

Docker Güvenliği: Konteyner Ortamını Sertleştirme

Docker güvenlik en iyi pratikleri: root olmayan kullanıcı, read-only filesystem, seccomp profilleri, image tarama, Docker socket güvenliği, network izolasyonu ve secrets yönetimi.

Okuma süresi: 17 dk Konteyner & Orkestrasyon
dockergüvenlikkonteynerseccompapparmorimage taramasecretssertleştirme

İçindekiler

Docker Güvenliği: Konteyner Ortamını Sertleştirme

Docker konteynerleri, varsayılan yapılandırmada birçok güvenlik açığı barındırabilir. Root kullanıcısı ile çalışan konteynerler, aşırı yetkili konteynerler ve güvenli olmayan image'lar ciddi riskler oluşturur. Bu rehberde Docker güvenliğini katman katman ele alacağız.

1. Root Olmayan Kullanıcı ile Çalışma

En temel güvenlik önlemi: konteynerleri root olmayan kullanıcı ile çalıştırmak.

Dockerfile'da Kullanıcı Tanımlama

hljs dockerfile
# Kötü pratik — root ile çalışma
FROM node:20
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]

# İyi pratik — root olmayan kullanıcı
FROM node:20

# Kullanıcı ve grup oluştur
RUN groupadd -r appgroup && useradd -r -g appgroup appuser

WORKDIR /app
COPY --chown=appuser:appgroup . .
RUN npm ci --only=production

# Root olmayan kullanıcıya geç
USER appuser

CMD ["node", "server.js"]

Çalışma Zamanında Kullanıcı Belirtme

hljs bash
# Belirli kullanıcı ile çalıştır
docker run -d --user 1000:1000 myapp:latest

# Mevcut kullanıcı ile çalıştır
docker run -d --user $(id -u):$(id -g) myapp:latest

# Kullanıcıyı kontrol et
docker exec CONTAINER_NAME whoami
docker exec CONTAINER_NAME id

2. Read-Only Filesystem

hljs bash
# Read-only root filesystem ile çalıştır
docker run -d \
  --name myapp \
  --read-only \
  --tmpfs /tmp \
  --tmpfs /var/run \
  myapp:latest

# Belirli dizinleri yazılabilir yap
docker run -d \
  --name myapp \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=100m \
  -v app-logs:/app/logs \
  myapp:latest
hljs yaml
# docker-compose.yml
services:
  app:
    image: myapp:latest
    read_only: true
    tmpfs:
      - /tmp
      - /var/run
    volumes:
      - app-logs:/app/logs

3. Capability Yönetimi

Linux capabilities, root yetkilerini granüler olarak kontrol eder.

hljs bash
# Tüm capabilities'i kaldır, sadece gerekli olanları ekle
docker run -d \
  --name myapp \
  --cap-drop ALL \
  --cap-add NET_BIND_SERVICE \
  myapp:latest

# Privileged modu KULLANMA (güvenlik riski)
# docker run --privileged myapp  # KÖTÜ PRATİK

# Mevcut capabilities'i kontrol et
docker exec CONTAINER_NAME cat /proc/1/status | grep Cap
hljs yaml
# docker-compose.yml
services:
  app:
    image: myapp:latest
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE
      - CHOWN

4. Seccomp Profilleri

Seccomp, konteynerın kullanabileceği sistem çağrılarını kısıtlar.

hljs bash
# Varsayılan seccomp profili ile çalıştır (önerilen)
docker run -d --security-opt seccomp=default myapp:latest

# Özel seccomp profili
docker run -d \
  --security-opt seccomp=/path/to/seccomp-profile.json \
  myapp:latest

# Seccomp'u devre dışı bırakma (güvenlik riski)
# docker run --security-opt seccomp=unconfined myapp  # KÖTÜ PRATİK

Özel Seccomp Profili

hljs json
// seccomp-profile.json
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": ["SCMP_ARCH_X86_64"],
  "syscalls": [
    {
      "names": [
        "read", "write", "open", "close", "stat", "fstat",
        "mmap", "mprotect", "munmap", "brk", "rt_sigaction",
        "rt_sigprocmask", "ioctl", "access", "pipe", "select",
        "sched_yield", "mremap", "msync", "mincore", "madvise",
        "dup", "dup2", "nanosleep", "getitimer", "alarm",
        "setitimer", "getpid", "sendfile", "socket", "connect",
        "accept", "sendto", "recvfrom", "sendmsg", "recvmsg",
        "shutdown", "bind", "listen", "getsockname", "getpeername",
        "socketpair", "setsockopt", "getsockopt", "clone", "fork",
        "vfork", "execve", "exit", "wait4", "kill", "uname",
        "fcntl", "flock", "fsync", "fdatasync", "truncate",
        "ftruncate", "getdents", "getcwd", "chdir", "fchdir",
        "rename", "mkdir", "rmdir", "creat", "link", "unlink",
        "symlink", "readlink", "chmod", "fchmod", "chown",
        "fchown", "lchown", "umask", "gettimeofday", "getrlimit",
        "getrusage", "sysinfo", "times", "ptrace", "getuid",
        "syslog", "getgid", "setuid", "setgid", "geteuid",
        "getegid", "setpgid", "getppid", "getpgrp", "setsid",
        "setreuid", "setregid", "getgroups", "setgroups",
        "setresuid", "getresuid", "setresgid", "getresgid",
        "getpgid", "setfsuid", "setfsgid", "getsid", "capget",
        "capset", "rt_sigpending", "rt_sigtimedwait",
        "rt_sigqueueinfo", "rt_sigsuspend", "sigaltstack",
        "utime", "mknod", "uselib", "personality", "ustat",
        "statfs", "fstatfs", "sysfs", "getpriority",
        "setpriority", "sched_setparam", "sched_getparam",
        "sched_setscheduler", "sched_getscheduler",
        "sched_get_priority_max", "sched_get_priority_min",
        "sched_rr_get_interval", "mlock", "munlock", "mlockall",
        "munlockall", "vhangup", "modify_ldt", "pivot_root",
        "prctl", "arch_prctl", "adjtimex", "setrlimit", "chroot",
        "sync", "acct", "settimeofday", "mount", "umount2",
        "swapon", "swapoff", "reboot", "sethostname",
        "setdomainname", "iopl", "ioperm", "create_module",
        "init_module", "delete_module", "get_kernel_syms",
        "query_module", "quotactl", "nfsservctl", "getpmsg",
        "putpmsg", "afs_syscall", "tuxcall", "security",
        "gettid", "readahead", "setxattr", "lsetxattr",
        "fsetxattr", "getxattr", "lgetxattr", "fgetxattr",
        "listxattr", "llistxattr", "flistxattr", "removexattr",
        "lremovexattr", "fremovexattr", "tkill", "time",
        "futex", "sched_setaffinity", "sched_getaffinity",
        "set_thread_area", "io_setup", "io_destroy",
        "io_getevents", "io_submit", "io_cancel",
        "get_thread_area", "lookup_dcookie", "epoll_create",
        "epoll_ctl_old", "epoll_wait_old", "remap_file_pages",
        "getdents64", "set_tid_address", "restart_syscall",
        "semtimedop", "fadvise64", "timer_create",
        "timer_settime", "timer_gettime", "timer_getoverrun",
        "timer_delete", "clock_settime", "clock_gettime",
        "clock_getres", "clock_nanosleep", "exit_group",
        "epoll_wait", "epoll_ctl", "tgkill", "utimes",
        "vserver", "mbind", "set_mempolicy", "get_mempolicy",
        "mq_open", "mq_unlink", "mq_timedsend",
        "mq_timedreceive", "mq_notify", "mq_getsetattr",
        "kexec_load", "waitid", "add_key", "request_key",
        "keyctl", "ioprio_set", "ioprio_get", "inotify_init",
        "inotify_add_watch", "inotify_rm_watch", "migrate_pages",
        "openat", "mkdirat", "mknodat", "fchownat", "futimesat",
        "newfstatat", "unlinkat", "renameat", "linkat",
        "symlinkat", "readlinkat", "fchmodat", "faccessat",
        "pselect6", "ppoll", "unshare", "set_robust_list",
        "get_robust_list", "splice", "tee", "sync_file_range",
        "vmsplice", "move_pages", "utimensat", "epoll_pwait",
        "signalfd", "timerfd_create", "eventfd", "fallocate",
        "timerfd_settime", "timerfd_gettime", "accept4",
        "signalfd4", "eventfd2", "epoll_create1", "dup3",
        "pipe2", "inotify_init1", "preadv", "pwritev",
        "rt_tgsigqueueinfo", "perf_event_open", "recvmmsg",
        "fanotify_init", "fanotify_mark", "prlimit64",
        "name_to_handle_at", "open_by_handle_at",
        "clock_adjtime", "syncfs", "sendmmsg", "setns",
        "getcpu", "process_vm_readv", "process_vm_writev",
        "kcmp", "finit_module", "sched_setattr",
        "sched_getattr", "renameat2", "seccomp",
        "getrandom", "memfd_create", "kexec_file_load",
        "bpf", "execveat", "userfaultfd", "membarrier",
        "mlock2", "copy_file_range", "preadv2", "pwritev2",
        "pkey_mprotect", "pkey_alloc", "pkey_free",
        "statx", "io_pgetevents", "rseq"
      ],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

5. Docker Image Güvenliği

Güvenli Dockerfile Pratikleri

hljs dockerfile
# Multi-stage build ile minimal image
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# Production image — minimal
FROM node:20-alpine

# Güvenlik güncellemelerini uygula
RUN apk update && apk upgrade && apk add --no-cache dumb-init

# Root olmayan kullanıcı
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules

USER appuser

# Sağlık kontrolü
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget -qO- http://localhost:3000/health || exit 1

ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/server.js"]

Image Tarama

hljs bash
# Trivy ile image tarama (önerilen)
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy:latest image myapp:latest

# Sadece kritik ve yüksek seviye açıklar
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  aquasec/trivy:latest image \
  --severity CRITICAL,HIGH \
  myapp:latest

# Docker Scout ile tarama
docker scout cves myapp:latest
docker scout recommendations myapp:latest

6. Docker Socket Güvenliği

hljs bash
# Docker socket'e erişimi kısıtla
# Sadece gerekli kullanıcıları docker grubuna ekle
usermod -aG docker appuser

# Docker socket'i read-only bağlama (monitoring için)
docker run -d \
  --name monitoring \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  monitoring-app:latest

# Docker socket'i asla production konteynerlerine bağlama
# Bu, host'a tam erişim sağlar!

7. Secrets Yönetimi

hljs bash
# Ortam değişkeni ile secret (güvenli değil — docker inspect ile görünür)
docker run -e DB_PASSWORD=secret myapp  # KÖTÜ PRATİK

# Docker secret kullan (Swarm modu)
echo "GucluSifre123!" | docker secret create db_password -

docker service create \
  --name myapp \
  --secret db_password \
  myapp:latest
# Secret /run/secrets/db_password dosyasında erişilebilir

# .env dosyası ile (docker-compose)
# .env dosyasını .gitignore'a ekle!
cat > .env << 'EOF'
DB_PASSWORD=GucluSifre123!
API_KEY=abc123
EOF
hljs yaml
# docker-compose.yml
services:
  app:
    image: myapp:latest
    env_file:
      - .env
    secrets:
      - db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt

8. Network Güvenliği

hljs bash
# Konteynerler arası iletişimi kısıtla
docker network create \
  --driver bridge \
  --opt com.docker.network.bridge.enable_icc=false \
  secure-network

# Sadece gerekli portları aç
docker run -d \
  --name myapp \
  -p 127.0.0.1:8080:8080 \
  myapp:latest
# 127.0.0.1 ile sadece localhost'tan erişim

9. Resource Limitleri

hljs bash
# CPU ve bellek limiti
docker run -d \
  --name myapp \
  --memory 512m \
  --memory-swap 512m \
  --cpus 1.0 \
  --pids-limit 100 \
  myapp:latest
hljs yaml
# docker-compose.yml
services:
  app:
    image: myapp:latest
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

10. Docker Daemon Güvenliği

hljs json
// /etc/docker/daemon.json
{
  "icc": false,
  "no-new-privileges": true,
  "userns-remap": "default",
  "live-restore": true,
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Sonuç

Docker güvenliği çok katmanlı bir yaklaşım gerektirir. Root olmayan kullanıcı, read-only filesystem, minimal capabilities ve image tarama ile başlayın. Secrets'ı asla ortam değişkeni olarak geçirmeyin, Docker socket'ini gereksiz yere bağlamayın ve resource limitleri ile DoS saldırılarına karşı koruma sağlayın. REXE sunucularında bu güvenlik önlemleri ile konteyner altyapınızı güvende tutabilirsiniz.