ویرگول
ورودثبت نام
سپهر فصیحی - Sepehr Fassihi
سپهر فصیحی - Sepehr FassihiDevOps Engineer | Telegram : @SepiFa
سپهر فصیحی - Sepehr Fassihi
سپهر فصیحی - Sepehr Fassihi
خواندن ۱۰ دقیقه·۱ ماه پیش

امنیت زمان اجرا در Kubernetes؛ وقتی Image سالم است اما Container مشکوک رفتار می‌کند

فرض کنید یک image تمام اسکن‌های امنیتی را با موفقیت پشت سر گذاشته، signature معتبر دارد و با digest مشخص در production deploy شده است. چند ساعت بعد، یکی از containerها رفتاری نشان می‌دهد که در زمان build قابل مشاهده نبوده است:

  • process جدیدی مثل curl یا bash اجرا می‌شود.

  • container تلاش می‌کند از داخل به metadata service وصل شود.

  • فایلی در مسیر حساس host یا container تغییر می‌کند.

  • یک Pod به‌صورت غیرمنتظره به Kubernetes API درخواست می‌فرستد.

  • process اصلی application یک shell فرزند ایجاد می‌کند.

در این نقطه، image scanning و admission control دیگر کافی نیستند. باید بدانیم در زمان اجرا چه اتفاقی داخل cluster می‌افتد.

این حوزه را معمولاً امنیت زمان اجرا یا Runtime Security می‌نامیم. هدف آن این نیست که فقط بعد از وقوع حادثه گزارش تهیه کنیم؛ هدف این است که رفتار غیرعادی را سریع ببینیم، دامنهٔ حادثه را محدود کنیم و شواهد لازم برای پاسخ‌گویی داشته باشیم.

چرا امنیت زمان اجرا لازم است؟

کنترل‌های قبل از deploy دربارهٔ چیزی صحبت می‌کنند که انتظار داریم اجرا شود. Runtime Security دربارهٔ چیزی صحبت می‌کند که واقعاً در حال اجراست.

یک image scanner ممکن است بگوید packageهای image آسیب‌پذیری شناخته‌شده‌ای ندارند. اما scanner معمولاً نمی‌بیند که:

  • application در اثر یک ورودی مخرب command اجرا کرده است.

  • یک مهاجم credential داخل process را استخراج کرده است.

  • container در حال برقراری ارتباط با مقصدی ناشناخته است.

  • یک shell از داخل process اصلی ایجاد شده است.

  • یک workload در حال خواندن فایل‌هایی خارج از رفتار معمول خود است.

این‌ها رفتارهای runtime هستند و باید در زمان اجرا مشاهده شوند.

یک سناریوی قابل لمس

فرض کنید سرویس order-api در یک فروشگاه آنلاین بزرگ اجرا می‌شود. این سرویس در حالت عادی باید:

  • process اصلی application را اجرا کند.

  • به database و سرویس پرداخت دسترسی داشته باشد.

  • روی پورت مشخص listen کند.

  • log تولید کند.

  • به registry یا اینترنت عمومی دسترسی مستقیم نداشته باشد.

حالا یک آسیب‌پذیری در endpoint جست‌وجو باعث می‌شود مهاجم بتواند command دلخواه اجرا کند. مهاجم ابتدا sh اجرا می‌کند، سپس با curl یک فایل دانلود می‌کند و در نهایت تلاش می‌کند به metadata service یا Kubernetes API متصل شود.

اگر فقط image را اسکن کرده باشیم، احتمالاً این زنجیره را نمی‌بینیم. اما اگر برای order-api baseline رفتاری داشته باشیم، این چند رویداد به‌سرعت مشکوک می‌شوند:

  1. اجرای sh توسط process اصلی application

  2. اجرای curl داخل container

  3. ایجاد فایل اجرایی در /tmp

  4. اتصال خروجی به مقصد جدید

  5. تلاش برای خواندن token یا metadata

هر رویداد به‌تنهایی ممکن است false positive باشد؛ کنار هم قرار گرفتن آن‌ها می‌تواند نشانهٔ جدی compromise باشد.

Runtime Security فقط لاگ جمع کردن نیست

سه قابلیت را باید از هم جدا کنیم:

مشاهده

چه processهایی اجرا شدند؟ چه فایل‌هایی خوانده یا تغییر داده شدند؟ چه اتصال‌هایی ایجاد شد؟

تشخیص

آیا رفتار مشاهده‌شده با رفتار مورد انتظار workload سازگار است؟

پاسخ

پس از تشخیص، آیا می‌توانیم workload را isolate، متوقف یا credentialهای آن را revoke کنیم؟

سیستمی که فقط log تولید می‌کند اما alert قابل‌استفاده ندارد، در زمان incident کمک محدودی می‌کند. از طرف دیگر، سیستمی که هر رفتار را به‌عنوان حمله اعلام کند، alert fatigue ایجاد می‌کند و تیم به هشدارها بی‌اعتماد می‌شود.

Falco چه کاری انجام می‌دهد؟

Falco یک ابزار تشخیص رفتار مشکوک در Linux و Kubernetes است. ایدهٔ اصلی آن بررسی eventهای سیستم و مقایسهٔ آن‌ها با ruleهای امنیتی است.

برای مثال می‌توان ruleای تعریف کرد که اجرای shell داخل container production را گزارش کند:

- rule: Shell Spawned in Production Container desc: Detect a shell started inside a production container condition: > container_started and evt.type in (execve, execveat) and proc.name in (sh, bash, zsh) and k8s.ns.name = "production" output: > Shell spawned in production container (user=%user.name command=%proc.cmdline container=%container.name pod=%k8s.pod.name namespace=%k8s.ns.name image=%container.image.repository) priority: WARNING tags: [container, kubernetes, shell]

این rule به‌تنهایی نمی‌گوید حمله قطعی رخ داده است. ممکن است تیم عملیات برای debug وارد container شده باشد. اما باید event ثبت شود و در صورت production بودن workload، بررسی شود.

Rule خوب باید context داشته باشد

هشدار «shell اجرا شد» به‌تنهایی اطلاعات کمی دارد. برای تصمیم‌گیری بهتر باید بدانیم:

  • نام Pod و namespace چیست؟

  • image و digest کدام است؟

  • process والد چه بوده است؟

  • چه کاربری command را اجرا کرده است؟

  • command از طریق kubectl exec آمده یا application آن را ساخته است؟

  • مقصد شبکه‌ای بعدی کجاست؟

  • آیا این رفتار قبلاً هم دیده شده است؟

برای مثال، اجرای shell در یک Pod ابزار debug ممکن است عادی باشد، اما اجرای bash از داخل process یک payment API در production، severity متفاوتی دارد.

قانون detection باید تا حد امکان context داشته باشد؛ وگرنه تیم با حجم زیادی از هشدارهای مبهم مواجه می‌شود.

چند رفتار مهم که باید پایش شوند

اجرای process غیرمنتظره

اگر container فقط باید Java یا Node.js اجرا کند، اجرای bash، nc، curl، wget، python یا ابزارهای مشابه باید بررسی شود.

تغییر فایل‌های حساس

تغییر فایل‌هایی مثل این‌ها می‌تواند مهم باشد:

  • فایل‌های تنظیمات application

  • فایل‌های startup

  • مسیرهای credential

  • فایل‌های مربوط به SSH

  • فایل‌های mountشده از Secret

  • مسیرهای حساس host در صورت وجود mount

ایجاد فایل اجرایی در مسیر موقت

نوشتن و اجرای binary از /tmp یا مسیرهای قابل‌نوشتن همیشه حمله نیست، اما در کنار download از شبکه یا اجرای shell باید severity بالاتری بگیرد.

اتصال شبکه‌ای غیرمنتظره

یک سرویس داخلی ممکن است فقط به database و چند API مشخص نیاز داشته باشد. اتصال به IP ناشناخته، اینترنت عمومی یا metadata service باید alert ایجاد کند.

دسترسی به Kubernetes API

اگر application به Kubernetes API نیاز ندارد، هر request از داخل آن به API Server باید بررسی شود؛ به‌خصوص اگر با token مربوط به Service Account همراه باشد.

تلاش برای escape یا دسترسی به host

استفاده از runtime socket، mountهای حساس، capabilityهای پرخطر یا دسترسی به namespaceهای host باید به‌عنوان رویدادهای با اولویت بالا دیده شوند.

همه‌چیز را با یک severity گزارش نکنید

یک مدل ساده برای severity می‌تواند این باشد:

سطح پایین

رفتار غیرمعمول اما کم‌خطر؛ مثلاً اجرای یک ابزار debug در namespace staging توسط تیم مجاز.

سطح متوسط

رفتار غیرمنتظره در production؛ مثلاً اجرای curl داخل containerای که نباید به اینترنت دسترسی داشته باشد.

سطح بالا

ترکیب چند رفتار مشکوک؛ مثلاً اجرای shell، دانلود binary و اتصال به مقصد ناشناس.

سطح بحرانی

نشانهٔ دسترسی به host، tokenهای حساس، Kubernetes API با permission بالا یا تلاش برای ایجاد workload جدید.

severity باید با context workload و اثر احتمالی event تعیین شود، نه فقط بر اساس نام command.

baseline رفتاری چیست؟

Baseline یعنی تصویری از رفتار معمول یک workload. برای order-api می‌توان ثبت کرد:

  • processهای مجاز

  • مقصدهای شبکه‌ای مجاز

  • مسیرهای قابل‌نوشتن

  • account و Service Account مورد انتظار

  • namespace و nodeهای مجاز

  • پورت‌های مورد استفاده

  • commandهای عملیاتی قابل‌قبول

Baseline نباید آن‌قدر سخت‌گیرانه باشد که هر deploy جدید را خراب کند. بهتر است ابتدا در حالت مشاهده جمع‌آوری شود، رفتارهای عادی از رفتارهای غیرعادی جدا شوند و بعد ruleها به‌تدریج enforce شوند.

مثال عملی برای سرویس شبیه فیلیمو

فرض کنید سرویس transcoder برای پردازش فایل ویدئو به چند ابزار مشخص نیاز دارد. این سرویس ممکن است ffmpeg اجرا کند، اما نباید:

  • shell تعاملی باز کند.

  • به Kubernetes API متصل شود.

  • به metadata service دسترسی داشته باشد.

  • فایل اجرایی ناشناخته از اینترنت دانلود کند.

  • به database پرداخت متصل شود.

در این حالت، ruleها باید بین رفتار مورد انتظار و رفتار مشکوک تفاوت بگذارند. اجرای ffmpeg alert نیست؛ اجرای bash -c و سپس curl به یک IP ناشناخته alert است.

اگر rule بدون context نوشته شود، تیم امنیت با صدها هشدار مربوط به اجرای عادی ffmpeg مواجه می‌شود. اگر context درست باشد، فقط زنجیرهٔ غیرعادی برجسته می‌شود.

مثال عملی برای سرویس شبیه اسنپ یا تپسی

فرض کنید سرویس driver-location در تعداد زیادی Pod اجرا می‌شود و releaseهای متوالی دارد. این سرویس باید به message broker و cache دسترسی داشته باشد، اما نباید command اجرایی جدید داخل container بسازد.

در این سناریو، detection زیر ارزشمند است:

  • اجرای processی که در image وجود نداشته است.

  • ارتباط با مقصدی خارج از allowlist.

  • اجرای shell توسط process اصلی.

  • تلاش برای خواندن Service Account token.

  • باز شدن پورت جدید داخل container.

اگر یک Pod compromise شود، تیم باید بتواند همان Pod را isolate کند بدون اینکه کل سرویس location را خاموش کند. اینجا پاسخ مرحله‌ای مهم است.

پاسخ به incident؛ اول شواهد را حفظ کنید

واکنش عجولانه می‌تواند شواهد مهم را از بین ببرد. حذف فوری Pod ممکن است حمله را متوقف کند، اما اطلاعاتی مثل process tree، connectionهای فعال و فایل‌های موقت را هم از بین می‌برد.

یک روند مناسب می‌تواند این باشد:

  1. alert را با logهای application و Kubernetes تطبیق دهید.

  2. Pod، namespace، node، image digest و Service Account را ثبت کنید.

  3. مشخص کنید event از چه زمانی شروع شده است.

  4. ارتباط شبکه‌ای و process tree را بررسی کنید.

  5. در صورت امکان ابتدا workload را network-isolate کنید.

  6. credentialهای در معرض خطر را revoke یا rotate کنید.

  7. سپس Pod را terminate و از image سالم redeploy کنید.

  8. همهٔ workloadهایی را که همان image یا credential را داشته‌اند بررسی کنید.

در محیط‌های بسیار حساس، snapshot یا forensic collection ممکن است قبل از حذف workload لازم باشد. این تصمیم باید با توجه به اثر سرویس و برنامهٔ incident response از قبل مشخص شده باشد.

Isolation بهتر از خاموش کردن کل cluster است

اگر فقط یک Pod مشکوک شده است، خاموش کردن کل node یا cluster معمولاً اولین انتخاب خوبی نیست. می‌توان دامنهٔ حادثه را محدود کرد:

  • اعمال NetworkPolicy موقت

  • قطع دسترسی خروجی Pod

  • حذف Service Account token

  • cordon کردن node در صورت نیاز

  • انتقال workload سالم به node دیگر

  • block کردن digest مشکوک در registry یا admission

این اقدامات باید از قبل تمرین شده باشند. در زمان incident، تیم نباید برای اولین بار دنبال این باشد که چگونه یک namespace را isolate کند.

لاگ‌ها را در سه سطح جمع کنید

لاگ application

برای فهمیدن رفتار business و خطاهای application لازم است.

لاگ Kubernetes

شامل eventهای Pod، تغییرات deployment، ایجاد Secret، تغییر RoleBinding و درخواست‌های API است.

لاگ node و runtime

برای دیدن processها، syscallها، اتصال‌ها و رفتار container لازم است.

ترکیب این سه سطح مهم است. مثلاً لاگ application می‌گوید یک request خاص خطا داده، لاگ runtime نشان می‌دهد بعد از همان request یک shell اجرا شده و audit log نشان می‌دهد credential دیگری خوانده شده است.

هشدار بدون فرایند پاسخ ارزشی ندارد

برای هر alert مهم باید مشخص باشد:

  • مالک بررسی اولیه چه تیمی است؟

  • severity چگونه تعیین می‌شود؟

  • چه زمانی باید incident اعلام شود؟

  • چه کسی اجازهٔ isolate کردن workload را دارد؟

  • credentialها چگونه rotate می‌شوند؟

  • چه زمانی Pod حذف می‌شود؟

  • چه اطلاعاتی باید در گزارش نهایی ثبت شود؟

این موارد باید در runbook نوشته و با یک تمرین کوچک آزمایش شوند. یک rule عالی بدون runbook ممکن است فقط یک پیام دیگر در سیستم مانیتورینگ باشد.

خطاهای رایج در Runtime Security

فعال کردن همهٔ ruleها بدون tuning

این کار معمولاً alert fatigue ایجاد می‌کند. ruleها باید با رفتار واقعی workloadها تنظیم شوند.

حذف Pod بدون بررسی دامنهٔ حادثه

حذف Pod ممکن است فقط نشانه را پاک کند. قبل از terminate باید image، digest، credential، node و workloadهای مشابه بررسی شوند.

اعتماد به نام process

مهاجم می‌تواند binary یا process را با نامی شبیه ابزارهای عادی اجرا کند. مسیر فایل، parent process، hash و context شبکه هم مهم هستند.

نادیده گرفتن رفتارهای عادی اما پرخطر

اگر تیم‌ها برای debug دائماً با kubectl exec وارد production شوند، تشخیص استفادهٔ مهاجم از همان مسیر دشوار می‌شود. دسترسی عملیاتی باید محدود و audit شود.

نداشتن زمان‌بندی برای نگهداری ruleها

معماری application تغییر می‌کند. ruleی که شش ماه قبل دقیق بوده ممکن است امروز false positive یا false negative زیادی تولید کند.

یک برنامهٔ عملی برای شروع

اگر Runtime Security هنوز در سازمان شما جدی پیاده نشده است، از این ترتیب شروع کنید:

  1. workloadهای حیاتی را مشخص کنید.

  2. image، digest، namespace و Service Account آن‌ها را فهرست کنید.

  3. processها و ارتباط‌های معمول را در حالت مشاهده ثبت کنید.

  4. ruleهای high-signal مثل shell در production و دسترسی به metadata را فعال کنید.

  5. alertها را به runbook مشخص متصل کنید.

  6. یک سناریوی compromise را در staging تمرین کنید.

  7. isolation و credential rotation را آزمایش کنید.

  8. بعد از tuning، ruleهای مهم را enforce کنید.

لازم نیست از روز اول همهٔ syscallها و تمام namespaceها را زیر نظر بگیرید. چند detection دقیق و قابل‌پاسخ بهتر از صدها هشدار بی‌استفاده است.

جمع‌بندی

امنیت container فقط قبل از اجرا اتفاق نمی‌افتد. image ممکن است اسکن شده، sign شده و با policy درست deploy شده باشد، اما application در زمان اجرا همچنان compromise شود.

Runtime Security کمک می‌کند رفتار واقعی workload را ببینیم: چه processی اجرا شده، چه فایلی تغییر کرده، به کجا متصل شده و با چه هویتی به Kubernetes API درخواست داده است.

ابزارهایی مثل Falco زمانی ارزش واقعی دارند که با baseline درست، alertهای دارای context، لاگ‌های متمرکز و runbook پاسخ به incident همراه شوند.

قاعدهٔ عملی این است:

اگر نمی‌دانیم workload در حالت عادی چگونه رفتار می‌کند، تشخیص رفتار غیرعادی آن تقریباً غیرممکن است.

هدف نهایی خاموش کردن همهٔ containerها نیست؛ هدف این است که یک رفتار مشکوک را زود ببینیم، دامنهٔ آن را محدود کنیم و قبل از تبدیل شدن یک Pod آلوده به حادثهٔ گسترده‌تر، واکنش درست نشان دهیم.

kubernetesامنیتدواپسdevops
۳۱
۰
سپهر فصیحی - Sepehr Fassihi
سپهر فصیحی - Sepehr Fassihi
DevOps Engineer | Telegram : @SepiFa
شاید از این پست‌ها خوشتان بیاید