أمان التبعيات والحاويات

تقوية الصور الأساسية والحاويات بدون توزيعة

3 دقيقة للقراءة

الطريقة الأكثر فعالية لتقليل ثغرات الحاويات هي تقليل ما بداخلها. برمجيات أقل = ثغرات أقل = سطح هجوم أصغر.

مشكلة الصور القياسية

صورة node:20 نموذجية تحتوي على:

node:20 (قائمة على debian)
├── بيئة تشغيل Node.js
├── npm/yarn
├── Bash shell
├── مدير حزم apt
├── curl, wget
├── مترجم gcc
├── Python (أدوات البناء)
└── 400+ ميغابايت من حزم النظام

النتيجة: 200-500 CVE، معظمها غير مرتبط بتطبيقك.

مقارنة حجم الصور

الصورة الأساسية الحجم CVEs النموذجية
node:20 1.1 غيغابايت 200-500
node:20-slim 250 ميغابايت 50-150
node:20-alpine 140 ميغابايت 10-50
gcr.io/distroless/nodejs20 130 ميغابايت 0-10
scratch + ثنائي ثابت ~10 ميغابايت 0

استراتيجية التقوية 1: صور Alpine

Alpine Linux يستخدم musl libc بدلاً من glibc، مما ينتج صوراً صغيرة:

# بدلاً من node:20
FROM node:20-alpine

# تثبيت فقط ما تحتاجه
RUN apk add --no-cache dumb-init

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .

# التشغيل كغير root
USER node
CMD ["dumb-init", "node", "server.js"]

الإيجابيات: صغيرة، CVEs أقل، دعم واسع السلبيات: بعض حزم npm تفشل (الروابط الأصلية تتوقع glibc)

استراتيجية التقوية 2: صور Distroless

صور Distroless تحتوي فقط على تطبيقك وتبعيات وقت التشغيل—بدون shell، بدون مدير حزم، بدون إضافات.

# مرحلة البناء
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# مرحلة الإنتاج - distroless
FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["dist/server.js"]

صور distroless المتاحة:

  • gcr.io/distroless/static - للثنائيات المجمعة ثابتياً (Go، Rust)
  • gcr.io/distroless/base - glibc للثنائيات المرتبطة ديناميكياً
  • gcr.io/distroless/nodejs20 - بيئة تشغيل Node.js
  • gcr.io/distroless/python3 - بيئة تشغيل Python
  • gcr.io/distroless/java21 - بيئة تشغيل Java

استراتيجية التقوية 3: بناء متعدد المراحل

فصل تبعيات وقت البناء عن وقت التشغيل:

# المرحلة 1: البناء
FROM golang:1.22 AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /server

# المرحلة 2: وقت التشغيل (scratch = صورة فارغة)
FROM scratch
COPY --from=builder /server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]

قائمة التحقق من أفضل الممارسات الأمنية

# 1. تثبيت إصدارات محددة (ليس :latest)
FROM node:20.10.0-alpine3.19

# 2. إنشاء مستخدم غير root
RUN addgroup -g 1001 appgroup && \
    adduser -u 1001 -G appgroup -D appuser

# 3. تعيين الملكية
COPY --chown=appuser:appgroup . .

# 4. إسقاط جميع الصلاحيات
USER appuser

# 5. استخدام نظام ملفات للقراءة فقط (عند التشغيل)
# docker run --read-only my-app

# 6. لا صلاحيات جديدة
# docker run --security-opt=no-new-privileges my-app

# 7. فحص الصحة
HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget -q --spider http://localhost:8080/health || exit 1

فحص الصور المقواة

قارن قبل وبعد:

# قبل (الصورة القياسية)
trivy image node:20
# Total: 487 (HIGH: 42, CRITICAL: 8)

# بعد (distroless)
trivy image gcr.io/distroless/nodejs20
# Total: 3 (HIGH: 0, CRITICAL: 0)

صور Chainguard

Chainguard يوفر صوراً مقواة مع SBOM:

# Chainguard Node.js (صفر CVEs)
FROM cgr.dev/chainguard/node:latest
الميزة Distroless Chainguard
صفر CVEs غالباً مضمون
SBOM مضمن لا نعم
صور موقعة لا نعم (Sigstore)
الدعم مجتمعي تجاري

النقاط الرئيسية

  1. ابدأ صغيراً: استخدم -alpine، -slim، أو distroless
  2. بناء متعدد المراحل: افصل البناء عن وقت التشغيل
  3. ثبت الإصدارات: لا تستخدم :latest في الإنتاج أبداً
  4. شغّل كغير root: حدد USER دائماً
  5. افحص بانتظام: CVEs تظهر في الصور الأساسية يومياً

في الوحدة التالية، سنستكشف الاختبار الديناميكي مع DAST وأمان وقت التشغيل. :::

اختبار

اختبار الوحدة 3: أمان التبعيات والحاويات

خذ الاختبار