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.
İç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
# 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
# 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
# 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
# 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.
# 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
# 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.
# 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
// 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
# 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
# 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
# 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
# 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
# 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
# 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
# CPU ve bellek limiti
docker run -d \
--name myapp \
--memory 512m \
--memory-swap 512m \
--cpus 1.0 \
--pids-limit 100 \
myapp:latest
# 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
// /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.
İlgili Makaleler
K3s ile Kubernetes Kurulumu: Hafif Konteyner Orkestrasyonu
K3s ile tek node ve çok node Kubernetes cluster kurulumu, kubectl kullanımı, deployment ve service oluşturma, Helm ile uygulama yönetimi. VPS üzerinde Kubernetes rehberi.
Docker Volume ve Network Yönetimi: Kalıcı Depolama ve Ağ Yapılandırması
Docker volume türleri (named, bind mount, tmpfs), volume yönetimi, Docker network modları (bridge, host, overlay), özel ağ oluşturma ve konteyner iletişimi. Kapsamlı rehber.
Konteyner Loglama: Docker ve Kubernetes Log Yönetimi
Docker log sürücüleri, docker logs komutu, Kubernetes pod logları, merkezi log toplama (Loki, ELK Stack), log rotasyonu ve production ortamında log yönetimi en iyi pratikleri.