يتطلب مستوى: محترف
لو بتـ deploy صور Docker من غير ما تفحصها، انت بتشحن ثغرات معروفة للإنتاج وانت مش حاسس. الجملة دي مش تهويل: أغلب الصور الجاهزة بتيجي ومعاها عشرات الثغرات المسجّلة. هنا هتبني بوابة Trivy في الـ CI توقف أي صورة مصابة قبل ما توصل السيرفر، في أقل من 15 ثانية لكل build، وبصفر تكلفة.
المشكلة باختصار
خلّينا نبدأ بمثال بسيط للمبتدئ. تخيّل بوابة تفتيش في المطار. كل شنطة بتعدّي على جهاز الأشعة، والجهاز بيقارن اللي جوّاها بقائمة أشياء ممنوعة معروفة. لو لقى حاجة خطيرة، الشنطة بتتوقف قبل ما تركب الطيارة. مش منطقي إن الجهاز يعرف إن فيه سكينة جوّه ويسيبها تعدّي.
دلوقتي بالتفاصيل العلمية. صورة Docker مش ملف واحد، هي طبقات فيها مئات الحزم: نظام تشغيل أساسي (Debian مثلًا)، مكتبات نظام (OpenSSL، zlib)، ثم اعتماديات مشروعك. أي حزمة فيها ثغرة متسجّلة برقم CVE (رقم موحّد عالميًا للثغرة) في قاعدة NVD التابعة للحكومة الأمريكية، بتبقى باب دخول محتمل للمهاجم. Trivy هو جهاز الأشعة: بيقرأ كل حزمة في الصورة، يقارنها بقواعد الثغرات، ويقولك بالظبط أنهي حزمة فيها إيه وأنهي إصدار بيصلّحها.
الافتراض هنا: عندك pipeline CI (GitHub Actions أو GitLab CI) بيبني صورة ويدفعها لـ registry قبل الإنتاج. لو لسه بتبني وبتـ push بإيدك من اللاب توب، البوابة دي مش هتشتغل لوحدها.
ليه صورتك مليانة ثغرات وانت مكتبتش الكود ده
ركز في النقطة دي لأنها بتوفر 90% من المجهود. أغلب الثغرات مش في كودك، هي في الصورة الأساسية اللي بنيت عليها. لو بدأت بـ node:20 الكاملة، انت ورّثت توزيعة لينكس كاملة بكل أدواتها.
node:20الكاملة: وقت كتابة المقال بترجّع أكتر من 100 ثغرة بدرجة HIGH/CRITICAL (الرقم بيتغيّر يوميًا مع اكتشاف ثغرات جديدة).node:20-slim: بتنزّلهم لعشرات قليلة، لأنها بتشيل أدوات مش محتاجها في الإنتاج.gcr.io/distroless/nodejs20: قريبة من صفر، لأنها فيها الـ runtime بس من غير shell ولا package manager.
الـ trade-off هنا واضح: distroless بتوفّر لك أمان ومساحة، بتخسر إن الـ debugging أصعب (مفيش bash جوّه الحاوية). لو فريقك بيدخل على الحاويات في الإنتاج بـ exec كتير، ابدأ بـ slim مش distroless.
الحل: خلّي Trivy بوابة في الـ CI
الطريقة الشائعة الغلط: تشغّل Trivy وتطبع النتيجة في اللوج بس. ده بيفشل لأن محدّش بيقرأ اللوج. البديل الصح: خلّي الأمر يرجّع exit-code 1 لما يلاقي ثغرة، فالـ build نفسه يفشل ويمنع الدمج.
أبسط أمر تشغّله محليًا الأول:
trivy image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 myapp:latest