
فرض کنید یک 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 رفتاری داشته باشیم، این چند رویداد بهسرعت مشکوک میشوند:
اجرای sh توسط process اصلی application
اجرای curl داخل container
ایجاد فایل اجرایی در /tmp
اتصال خروجی به مقصد جدید
تلاش برای خواندن token یا metadata
هر رویداد بهتنهایی ممکن است false positive باشد؛ کنار هم قرار گرفتن آنها میتواند نشانهٔ جدی compromise باشد.
سه قابلیت را باید از هم جدا کنیم:
چه processهایی اجرا شدند؟ چه فایلهایی خوانده یا تغییر داده شدند؟ چه اتصالهایی ایجاد شد؟
آیا رفتار مشاهدهشده با رفتار مورد انتظار workload سازگار است؟
پس از تشخیص، آیا میتوانیم workload را isolate، متوقف یا credentialهای آن را revoke کنیم؟
سیستمی که فقط log تولید میکند اما alert قابلاستفاده ندارد، در زمان incident کمک محدودی میکند. از طرف دیگر، سیستمی که هر رفتار را بهعنوان حمله اعلام کند، alert fatigue ایجاد میکند و تیم به هشدارها بیاعتماد میشود.
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، بررسی شود.
هشدار «shell اجرا شد» بهتنهایی اطلاعات کمی دارد. برای تصمیمگیری بهتر باید بدانیم:
نام Pod و namespace چیست؟
image و digest کدام است؟
process والد چه بوده است؟
چه کاربری command را اجرا کرده است؟
command از طریق kubectl exec آمده یا application آن را ساخته است؟
مقصد شبکهای بعدی کجاست؟
آیا این رفتار قبلاً هم دیده شده است؟
برای مثال، اجرای shell در یک Pod ابزار debug ممکن است عادی باشد، اما اجرای bash از داخل process یک payment API در production، severity متفاوتی دارد.
قانون detection باید تا حد امکان context داشته باشد؛ وگرنه تیم با حجم زیادی از هشدارهای مبهم مواجه میشود.
اگر 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 ایجاد کند.
اگر application به Kubernetes API نیاز ندارد، هر request از داخل آن به API Server باید بررسی شود؛ بهخصوص اگر با token مربوط به Service Account همراه باشد.
استفاده از runtime socket، mountهای حساس، capabilityهای پرخطر یا دسترسی به namespaceهای host باید بهعنوان رویدادهای با اولویت بالا دیده شوند.
یک مدل ساده برای severity میتواند این باشد:
رفتار غیرمعمول اما کمخطر؛ مثلاً اجرای یک ابزار debug در namespace staging توسط تیم مجاز.
رفتار غیرمنتظره در production؛ مثلاً اجرای curl داخل containerای که نباید به اینترنت دسترسی داشته باشد.
ترکیب چند رفتار مشکوک؛ مثلاً اجرای shell، دانلود binary و اتصال به مقصد ناشناس.
نشانهٔ دسترسی به host، tokenهای حساس، Kubernetes API با permission بالا یا تلاش برای ایجاد workload جدید.
severity باید با context workload و اثر احتمالی event تعیین شود، نه فقط بر اساس نام command.
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 را خاموش کند. اینجا پاسخ مرحلهای مهم است.
واکنش عجولانه میتواند شواهد مهم را از بین ببرد. حذف فوری Pod ممکن است حمله را متوقف کند، اما اطلاعاتی مثل process tree، connectionهای فعال و فایلهای موقت را هم از بین میبرد.
یک روند مناسب میتواند این باشد:
alert را با logهای application و Kubernetes تطبیق دهید.
Pod، namespace، node، image digest و Service Account را ثبت کنید.
مشخص کنید event از چه زمانی شروع شده است.
ارتباط شبکهای و process tree را بررسی کنید.
در صورت امکان ابتدا workload را network-isolate کنید.
credentialهای در معرض خطر را revoke یا rotate کنید.
سپس Pod را terminate و از image سالم redeploy کنید.
همهٔ workloadهایی را که همان image یا credential را داشتهاند بررسی کنید.
در محیطهای بسیار حساس، snapshot یا forensic collection ممکن است قبل از حذف workload لازم باشد. این تصمیم باید با توجه به اثر سرویس و برنامهٔ incident response از قبل مشخص شده باشد.
اگر فقط یک Pod مشکوک شده است، خاموش کردن کل node یا cluster معمولاً اولین انتخاب خوبی نیست. میتوان دامنهٔ حادثه را محدود کرد:
اعمال NetworkPolicy موقت
قطع دسترسی خروجی Pod
حذف Service Account token
cordon کردن node در صورت نیاز
انتقال workload سالم به node دیگر
block کردن digest مشکوک در registry یا admission
این اقدامات باید از قبل تمرین شده باشند. در زمان incident، تیم نباید برای اولین بار دنبال این باشد که چگونه یک namespace را isolate کند.
برای فهمیدن رفتار business و خطاهای application لازم است.
شامل eventهای Pod، تغییرات deployment، ایجاد Secret، تغییر RoleBinding و درخواستهای API است.
برای دیدن processها، syscallها، اتصالها و رفتار container لازم است.
ترکیب این سه سطح مهم است. مثلاً لاگ application میگوید یک request خاص خطا داده، لاگ runtime نشان میدهد بعد از همان request یک shell اجرا شده و audit log نشان میدهد credential دیگری خوانده شده است.
برای هر alert مهم باید مشخص باشد:
مالک بررسی اولیه چه تیمی است؟
severity چگونه تعیین میشود؟
چه زمانی باید incident اعلام شود؟
چه کسی اجازهٔ isolate کردن workload را دارد؟
credentialها چگونه rotate میشوند؟
چه زمانی Pod حذف میشود؟
چه اطلاعاتی باید در گزارش نهایی ثبت شود؟
این موارد باید در runbook نوشته و با یک تمرین کوچک آزمایش شوند. یک rule عالی بدون runbook ممکن است فقط یک پیام دیگر در سیستم مانیتورینگ باشد.
این کار معمولاً alert fatigue ایجاد میکند. ruleها باید با رفتار واقعی workloadها تنظیم شوند.
حذف Pod ممکن است فقط نشانه را پاک کند. قبل از terminate باید image، digest، credential، node و workloadهای مشابه بررسی شوند.
مهاجم میتواند binary یا process را با نامی شبیه ابزارهای عادی اجرا کند. مسیر فایل، parent process، hash و context شبکه هم مهم هستند.
اگر تیمها برای debug دائماً با kubectl exec وارد production شوند، تشخیص استفادهٔ مهاجم از همان مسیر دشوار میشود. دسترسی عملیاتی باید محدود و audit شود.
معماری application تغییر میکند. ruleی که شش ماه قبل دقیق بوده ممکن است امروز false positive یا false negative زیادی تولید کند.
اگر Runtime Security هنوز در سازمان شما جدی پیاده نشده است، از این ترتیب شروع کنید:
workloadهای حیاتی را مشخص کنید.
image، digest، namespace و Service Account آنها را فهرست کنید.
processها و ارتباطهای معمول را در حالت مشاهده ثبت کنید.
ruleهای high-signal مثل shell در production و دسترسی به metadata را فعال کنید.
alertها را به runbook مشخص متصل کنید.
یک سناریوی compromise را در staging تمرین کنید.
isolation و credential rotation را آزمایش کنید.
بعد از 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 آلوده به حادثهٔ گستردهتر، واکنش درست نشان دهیم.