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 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.
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.
En temel güvenlik önlemi: konteynerleri root olmayan kullanıcı ile çalıştırmak.
# 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"]
# 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
# 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
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
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
// 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"
}
]
}
# 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"]
# 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
# 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!
# 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
# 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
# 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
// /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"
}
}
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.
Konteyner içindeki root kullanıcısı, container escape açığı durumunda host'ta da root yetkisi kazanabilir. Ayrıca root ile çalışan konteyner, yanlışlıkla kritik sistem dosyalarını değiştirebilir. Dockerfile'da USER direktifi ile root olmayan kullanıcı tanımlayın ve --user parametresi ile çalıştırın.
Trivy en popüler açık kaynak araçtır: docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:latest image IMAGE_ADI. CI/CD pipeline'ınıza entegre ederek her build'de otomatik tarama yapabilirsiniz. Docker Scout da resmi Docker aracıdır ve docker scout cves IMAGE_ADI ile kullanılır.
Neredeyse hiçbir zaman. --privileged konteyner'a host'a neredeyse tam erişim verir ve tüm güvenlik izolasyonunu ortadan kaldırır. Gerçekten gerekiyorsa (örn: Docker-in-Docker), sadece geliştirme ortamında kullanın. Production'da --cap-add ile sadece ihtiyaç duyulan capabilities'i ekleyin.
Üç yöntem: 1) .env dosyası (basit ama .gitignore'a eklenmeli), 2) Docker secrets (Swarm modu gerektirir, /run/secrets/ altında erişilebilir), 3) HashiCorp Vault veya AWS Secrets Manager gibi harici secret yönetim araçları. Asla secrets'ı Dockerfile'a veya image'a gömmeyin.
no-new-privileges, konteyner içindeki süreçlerin setuid/setgid binary'ler aracılığıyla yeni yetkiler kazanmasını engeller. Bu, privilege escalation saldırılarına karşı önemli bir koruma katmanıdır. /etc/docker/daemon.json'a ekleyerek tüm konteynerler için varsayılan olarak etkinleştirebilirsiniz.
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 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.
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.