دنبال کنیدجویا هاشمیخواندن ۲۵ دقیقه·۳ روز پیشExposed Kubernetes API Server and Kubelet APIExposed Kubernetes API Server and Kubelet APIExposed Kubernetes API Server یکی از مشکلات امنیتی در محیط‌های مبتنی بر Kubernetes که معمولاً به دلیل پیکربندی ناامن و تنظیمات اشتباه به وجود می‌آید.این مشکل امنیتی معمولا ضعف ذاتی در خود Kubernetes نیست بلکه حاصل تنظیمات اشتباه و نحوه دسترسی به API Server می‌باشد.API Server نقطه اصلی ورود به کلاستر Kubernetes می‌باشد و بیشتر درخواست‌های مدیریتی و ارتباط بین Componentها از طریق آن انجام می‌شود.این مشکل امنیتی می‌تواند در Kubelet که یکی دیگر از Componentهای اصلی Kubernetes در هر Worker Node می‌باشد اتفاق بیفتد و سطح حمله مستقلی از API Server را ایجاد کند که در ادامه به ارزیابی آن خواهیم پرداخت.

در دنیای در زمان حاضر بسیاری از سازمان‌ها با هدف رشد کیفیت خدمات خود و پاسخ‌گویی بهتر به نیازمندی‌های کسب‌وکار زیرساخت‌های سنتی خود را با تکنولوژی‌های مدرن جایگزین کرده‌اند.بر همین اساس استفاده از محیط‌های مبتنی بر Container به‌ویژه در بستر Kubernetes به یکی از اجزای کلیدی در زیرساخت‌های مدرن تبدیل گردیده است.با این حال هرگونه پیکربندی ناامن و Misconfig در این محیط‌ها می‌تواند منجر به شکل‌گیری آسیب‌پذیری‌های بحرانی گردد و پیامدهای امنیتی قابل‌توجهی برای یک سازمان به همراه داشته باشد.

قبل از اینکه به تحلیل این آسیب‌پذیری‌ها بپردازیم ابتدا لازم است به‌صورت مختصر با مفاهیم DevOps آشنا شویم چرا که Kubernetes یا k8s یکی از ابزارهای کاربردی در این حوزه می‌باشد سپس به آشنایی و معماری Kubernetes خواهیم پرداخت تا بتوانیم درک بهتری از زمینه‌ای که آسیب‌پذیری در آن شکل می‌گیرد به دست آوریم.

DevOps در واقع یک رویکردی در توسعه نرم‌افزار است که بر همکاری نزدیک و منسجم میان تیم‌های توسعه (Development) و عملیات (Operations) تاکید دارد.این رویکرد تلاش می‌کند با ایجاد هماهنگی و کار تیمی موثر نرم‌افزار با کیفیت بالاتری ساخته شود.بسیاری از فعالیت‌هایی که در گذشته به‌صورت دستی و سنتی انجام می‌شدند در DevOps از طریق Automation تشتابان می‌شوند.این مسئله علاوه بر بیشتر شدن دقت و سرعت باعث نزول زمان ارائه محصول به بازار (Time to Market) نیز می‌شود.به همین دلیل DevOps امروزه به‌عنوان یکی از رویکردهای مدرن در مدیریت چرخه عمر توسعه نرم‌افزار (SDLC) شناخته می‌شود.باید توجه داشت که DevOps تنها به استفاده از ابزارها خلاصه نمی‌شود اگر در یک سازمانی فرهنگ همکاری و تعامل بین تیم‌های مختلف کاری شکل نگرفته باشد نمی‌توان آن محیط را DevOps واقعی دانست حتی اگر از ابزارهای مختلف Automation استفاده شده باشد.در اینجا ابزارها صرفاً نقش موثرتری در تولید نرم‌افزار دارند به عبارتی DevOps خود Automation نیست اما بدون آن معنا و اثربخشی واقعی نخواهد داشت.

در DevOps پایبند بودن به اصول و استانداردهای پذیرفته شده اهمیت بسیار بالایی دارد و این رویکرد نباید طبق روابط شخصی یا تصمیم‌گیری‌های سلیقه‌ای پیش برود بلکه باید بر پایه یک Collaboration، تعامل موثر و فرهنگ کاری صحیح شکل بگیرد.مسئلهی که اهمیت بالایی در زیرساخت‌های مدرن همچون Kubernetes به همراه دارد چرا که رفتن به سمت تکنولوژی‌های مدرن اگر بدون در نظر گرفتن اقدامات امنیتی لازم انجام گردد می‌تواند پیامدهای امنیتی قابل‌توجهی برای یک سازمان به همراه داشته باشد برای همین امنیت باید در ابتدا وارد این چرخه دواپسی شود.در زمان حاضره بسیاری از سازمان‌ها از Kubernetes به عنوان بستر اجرا و مدیریت سرویس‌های کانتینری خود استفاده می‌کنند چه در دل محیط‌های مبتنی بر DevOps و چه به‌صورت مستقل یا (Standalone) اما باید توجه داشت که پیکربندی ناامن در این محیط‌ها می‌تواند زمینه‌ساز دسترسی غیرمجاز به کلاستر Kubernetes گردد.

برای شرح بیشتر برای کسانی که به حوزه DevOps علاقه‌مند هستند و به دنبال یک مسیر یادگیری مشخص هستند سایت زیر منبع بدون هزینهی است که مسیر یادگیری این حوزه را پوشش می‌دهد.

قبل از اینکه وارد تحلیل این آسیب‌پذیری‌ها شویم ابتدا با پلتفرم Kubernetes و معماری آن آشنا می‌شویم و در ادامه به نحوه کشف و شناسایی این آسیب‌پذیری‌ها خواهیم پرداخت.

Kubernetes پلتفرمی است که ما از آن برای استقرار و مدیریت خودکار Containerها در سطح Cluster استفاده می کنیم که این کار باعث ساده‌ترشدن مدیریت Containerها و کم شدن فرآیندهای دستی مرتبط با آن‌ها می‌شود.

شاید این سوال مطرح شود که وقتی ما پلتفرمی مانند Docker را داریم و از آن می‌توانیم برای اجرا و مدیریت Containerها استفاده کنیم استفاده از Kubernetes چه مزیتی برای سازمان ما می‌تواند به همراه داشته باشد؟

به‌طور کلی Docker پلتفرمی است که ما از آن برای ساخت Image و اجرای آن‌ در قالب Container استفاده می‌کنیم و اگر از Docker به‌تنهایی برای اجرا و مدیریت Containerها استفاده کنیم بخش زیادی از این فرآیندها به‌صورت دستی انجام و مدیریت خواهد شد.این شیوه برای مدیریت تعداد زیادی Container در زیرساخت‌های بزرگ دشوار و مستعد خطا خواهد بود.یکی از چالش‌های مهمی که در زیرساخت‌های بزرگ وجود دارد معمولا راه‌اندازی و مستقر کردن برنامه‌هاست و وقتی اسکیل برنامه‌ها بزرگ می‌شود قابلیت اشتباهات پیکربندی هم به‌مراتب زیاد می‌شود. معمولا اکثر سازمان‌ها به‌دنبال آن هستند که استقرار و مدیریت سرویس‌های کانتینری خود را خودکار کنند و علاوه بر آن دسترس‌پذیری بالا (High Availability) و تحمل خطا (Fault Tolerance) را برای این سرویس‌ها فراهم سازند و از این طریق مطمئن شوند که برنامه‌های کانتینری خود همیشه در دسترس خواهد بود.Kubernetes به‌عنوان یک Container Orchestration آمده که این مشکلات را برای ما حل کند و تمامی این قابلیت‌ها را از طریق یک سلوشن یکپارچه به ما ارائه می‌دهد.پیاده‌سازی مستقل هر کدام از این قابلیت‌ها می‌تواند برای یک سازمان پرهزینه و دشوار باشد.Kubernetes کمک می‌کند که ما برنامه‌های کانتینری خود را راحتر مدیریت کنیم و بخش زیادی از فرآیندهای دستی را کم شدن و به‌صورت خودکار انجام دهیم و در نهایت اگر طراحی و پیکربندی Kubernetes به‌درستی انجام شود می‌تواند باعث در دسترس‌پذیری (High Availability) و تحمل خطا (Fault Tolerance) سرویس‌ کانتیری ما شود.

برای آشنایی بیشتر با قابلیت‌ها و فرصتات Kubernetes می‌توان به مستندات رسمی Kubernetes به آدرس زیر مراجعه کرد.

مسئله دیگری که باید به آن توجه داشت این است که بدون Kubernetes هم توانایی Orchestration کانتینرها وجود دارد.به‌عنوان مثال Docker قابلیتی دارد به‌نام Docker Swarm که یک Container Orchestration محسوب می‌شود و ما با استفاده از آن می‌توانیم بسیاری از فرآیندها را خودکار کنیم.اما Kubernetes به‌دلیل قابلیت‌های بیشتر و اکوسیستم قدرتمندتر به یکی از پراستفاده‌ترین پلتفرم‌های Container Orchestration در صنعت محسوب می‌شود و بر همین اساس هم است که بر پایه Kubernetes توزیع‌ها و پلتفرم‌های مختلفی ساخته شده است.برای مثال OpenShift محصول شرکت Red Hat یک پلتفرم سازمانی مبتنی بر Kubernetes است که با هدف و رویکرد جامعاً Enterprise طراحی گردیده است و قابلیت‌های امنیتی و مدیریتی یکپارچه‌ای را برای اجرا و مدیریت Containerها در اختیار سازمان‌ها قرار می‌دهد.یا توزیع‌های دیگر از جمله RKE2 و K3s که توسط Rancher Labs توسعه داده شده‌اند و اکنون این شرکت تحت مالکیت شرکت SUSE قرار دارد. RKE2 یک توزیع سازگار با Kubernetes است که با تمرکز بر نیازهای سازمانی و ملاحظات امنیتی طراحی گردیده است.در مقابل K3s توزیع سبک‌تری از Kubernetes است که منابع کمتری را مصرف می‌کند و نصب و مدیریت ساده‌تری دارد و برای محیط‌های توسعه می‌تواند گزینه مناسبی باشد.

انتخاب هر یک از این توزیع‌ها و پلتفرم‌ها باید بر پایه نیازمندی‌های سازمان انتخاب و استفاده شود.مدیریت و پیکربندی صحیح و امن Kubernetes نیازمند دانش فنی و امنیتی افراد دارد چرا که امنیت Cluster همچنان به نحوه طراحی و مدیریت آن وابسته است حتی در پلتفرم‌هایی که کنترل‌های امنیتی بیشتری را به‌صورت پیش‌فرض ارائه می‌دهند پیکربندی نادرست و ناامن یا غیرفعال‌کردن کنترل‌های امنیتی آن می‌تواند زیرساخت ما را مستعد آسیب‌پذیری کند.

حال که به صورت مختصر با Kubernetes آشنا شدیم به معماری آن می‌پردازیم تا با شناخت Componentهای آن چگونگی شکل‌گیری مشکلات امنیتی ناشی از پیکربندی ناامن را بهتر درک کنیم.

معماری Kubernetes از دو بخش اصلی یعنی Control Plane و Worker Node تشکیل شده است که هرکدام از این بخش‌ها دارای یک‌سری Component می‌باشند و هرکدام وظیفه خاص و مشخصی را انجام می‌دهند.بخش Control Plane که قبلاً به‌عنوان Master شناخته می‌شد وظیفه مدیریت کلاستر Kubernetes و تصمیم‌گیری‌های اصلی را بر عهده دارد و بخش Worker Nodeها محیط اجرای Workloadهای کانتینری را فراهم می‌کنند.در اینجا منظور از Workload برنامه‌ها و سرویس‌هایی هستند که معمولاً در قالب Pod اجرا می‌شوند آشنایی با هرکدام از Componentها به ما کمک می‌کند تا بفهمیم یک آسیب‌پذیری چطور به وجود می‌آید اگرچه Kubernetes از قابلیت‌های امنیتی مناسبی برخوردار است اما این پیکربندی‌های ناامن و Misconfigها هستند که Kubernetes را مستعد آسیب‌پذیری می‌کند.این نکته را هم باید در نظر گرفت که بعضی از این Componentها در برخی از ویرایش‌های Kubernetes دارای CVE می‌باشند که در این شرایط باید نسخه جدید Kubernetes آپدیت گردد تا رفع آسیب‌پذیری صورت گیرد.

در شکل زیر همان‌طور که مشاهده می‌شود معماری کلی Kubernetes شامل دو بخش Control Plane و Worker Node می‌باشد که این بخش‌ها دارای یکسری Componentها می‌باشند که در ادامه به‌ صورت خلاصه به معرفی هر یک از Componentها خواهیم پرداخت.

ابتدا به معرفی Componentهای بخش Control Plane می‌پردازیم:

API Server: این Component نقطه اصلی ورود به کلاستر Kubernetes می‌باشد و بیشتر درخواست‌های مدیریتی و ارتباط بین Componentها از طریق آن انجام می‌شود.ما با استفاده از این Component می‌توانیم با کلاستر Kubernetes صحبت کنیم.معمولاً برای مدیریت کلاستر Kubernetes از ابزارها و روش‌های مختلفی استفاده می‌شود یکی از روش‌ها به‌صورت CLI (کامندلاین) که از طریق kubectl که ابزار تخصصی خود Kubernetes می‌باشد و دیگری به‌صورت WebUI (اینترفیس گرافیکی) مثل Kubernetes Dashboard یا استفاده از ابزارهای مدیریت Cluster مانند Rancher است در تمامی این روش‌ها تمامی درخواست‌ها در قالب درخواست‌های HTTP به API Server ارسال می‌شوند و در صورت مجاز بودن درخواست API Server آن را پردازش می‌کند و خروجی را به ما برمی‌گرداند.این Component به‌صورت پیش‌فرض از پورت 6443 استفاده می‌کند.

برای مثال زمانی که دستور kubectl get nodes مطابق شکل زیر را برای مشاهده فهرست Nodeهای Cluster اجرا می‌کنیم ابزار kubectl در Background یک درخواست HTTP با متد GET را به API Server که پورت آن 6443 می‌باشد ارسال می‌کند.البته متد این درخواست‌ها به نوع کاری که انجام می‌دهیم بستگی دارد به‌عنوان مثال برای مشاهده منابع Cluster از متد GET یا برای ایجاد یک منبع نوین از متد POST استفاده می‌شود.

این درخواست در Background به صورت فرمت زیر به API Server ارسال می‌شود.

اگر دستورات kubectl را بدون هیچ ابزار جانبی بخواهیم در Background ببینیم که به چه صورت ارسال می‌شود مطابق شکل زیر از دستور زیر استفاده می‌کنیم همانطور که مشخص می‌باشد این درخواست در Background به صورت فرمت HTTP به API Server ارسال می‌شود.

Controller Manager: این Component مجموعه‌ای از Controllerهای مختلف را اجرا می‌کند و وضعیت فعلی و مطلوب منابع Cluster را از طریق API Server دریافت و با یکدیگر مقایسه می‌کند و اگر میان این دو وضعیت اختلافی وجود داشته باشد اقدامات لازم را از طریق API Server انجام می‌دهد.این گزارش‌ها توسط API Server در etcd ذخیره می‌شود و Controller Manager بدون ارتباط مستقیم با etcd شرح را از API Server دریافت می‌کند این Component وظایف متعددی دیگر را هم بر عهده دارد.

Scheduler: این Component وظیفه زمان‌بندی Podها و انتخاب مناسب‌ترین Worker Node را برای قرارگیری آن‌ها بر عهده دارد.علاوه بر این از طریق API Server در واقع Podهایی را که ایجاد شده‌اند و هنوز Node خاصی به آن‌ها اختصاص داده نشده است را شناسایی می‌کند و سپس از طریق یکسری الگوریتم‌های پیش‌فرض که بعداً از طریق تنظیمات این Component قابل تغییر می‌باشد مناسب‌ترین Node را برای آن Pod انتخاب می‌کند.

etcd (DB): این Component دیتابیس اصلی Kubernetes می‌باشد و وضعیت منابع Cluster مانند Podها، Nodeها، Secretها و ConfigMapها و غیره در آن ذخیره می‌شود. API Server تنها Component اصلی Kubernetes است که به‌صورت مستقیم با این Component ارتباط برقرار می‌کند و سایر Componentها از طریق API Server شرحات را از etcd دریافت و ثبت می‌کنند. به‌عنوان مثال، هنگامی که ما دستور kubectl get nodes را اجرا می‌کنیم درخواست به API Server ارسال می‌شود و API Server داده‌ها Nodeها را از etcd دریافت و حاصل را در اختیار ما قرار می‌دهد.

این مواردی که بیان گردید جزو Componentهای اصلی Control Plane می‌باشد.البته ما در این بخش Component دیگری به‌نام Cloud Controller Manager را هم داریم که این Component به‌صورت Optional می‌باشد و زمانی استفاده می‌شود که ما بخواهیم Kubernetes را با APIها و سرویس‌های یک Cloud Provider یکپارچه کنیم.خوبی Kubernetes این است که روی هر زیرساختی قابل نصب و اجرا می‌باشد از سرورهای فیزیکی یا مجازی در محیط On-Premises گرفته تا زیرساخت‌های ابری یا Cloud که می‌توان آن را مدیریت و اجرا کرد.

حال به معرفی Componentهای Worker Node می‌پردازیم:

Kubelet: یکی از Componentهای اصلی در هر Worker Node می‌باشد و وظیفه اصلی آن دریافت مشخصات Podهای اختصاص‌یافته به همان Worker Node از طریق API Server می‌باشد و در ادامه مدیریت اجرای آن‌ها را بر عهده دارد. این Component از طریق اینترفیس CRI از Container Runtime می‌خواهد Containerهای تعریف‌شده را در آن Pod ایجاد و اجرا کند. علاوه بر این وضعیت Podها و Containerهای همان Worker Node را به API Server گزارش می‌دهد.این Component روی پورت 10250 کار می‌کند.

Kube-Proxy: این Component معمولاً روی هر Worker Node اجرا می‌شود و وظیفه آن پیاده‌سازی ارتباطات شبکه‌ای مربوط به Serviceها است.از سوی دیگر گزارش‌ها Serviceها و Endpointهای مرتبط با آن‌ها را از طریق API Server دریافت می‌کند و با ایجاد و ارتقا Ruleهای شبکه روی Node ترافیک ورودی به هر Service را به یکی از Podهای مرتبط با آن هدایت می‌کند.

Container Runtime: این Component اجرای Containerها و مدیریت lifecycle آن‌ها را روی Node بر عهده دارد.Kubernetes به‌صورت مستقل Container Runtime را پیاده‌سازی نکرده است و وظیفه این کار را به Runtimeهایی سازگار مانند Containerd یا CRI-O واگذار کرده است.زمانی که یک Pod به یک Worker Node مشخص اختصاص داده می‌شود Kubelet مشخصات آن را از طریق API Server دریافت می‌کند و سپس با استفاده از CRI با Container Runtime همان Worker Node ارتباط برقرار می‌کند. در ادامه Container Runtime عملیات Lifecycle (ایجاد، اجرا، توقف و حذف) Containerهای تعریف‌شده در Pod را طبق درخواست Kubelet انجام می‌دهد.

اکنون که با Componentهای Kubernetes آشنا شدیم به صورت مختصر به معرفی Pod می‌پردازیم.

POD: کوچکترین واحد مدیریتی در Kubernetes می‌باشد که از یک یا چند Container تشکیل می‌شود.ما در Docker می‌توانستیم Containerها را به صورت مستقیم اجرا کنیم ولی در Kubernetes تمام Containerها در قالب یک Pod ایجاد و اجرا می‌شوند در اینجا ما به جای Container به Podها IP می‌دهیم و Containerهای درون هر Pod از یک IP مشترک استفاده می‌کنند از آنجا که Containerها در یک Pod دارای Network Namespace مشترک هستند می‌توانند از طریق "LocalHost" و شماره Port با یکدیگر ارتباط برقرار کنند.به همین دلیل دو Container داخل یک Pod نمی‌توانند هم‌زمان روی یک Port یکسان Listen کنند.

حال که با معماری و Componentهای اصلی Kubernetes آشنا شدیم به محور اصلی می‌پردازیم و ارزیابی می‌کنیم که چگونه پیکربندی ناامن همراه با قرار گرفتن API Server و Kubelet در شبکه می‌تواند زمینه افشای اطلاعات یا دسترسی غیرمجاز به Cluster را فراهم کند.

ابتدا به بخش اول آسیب‌پذیری یعنی Exposed Kubernetes API Server می‌پردازیم:

زمانی که ما اقدام به راه‌اندازی کلاستر Kubernetes می‌کنیم هر Component در بخش مربوط به خود نصب و اجرا می‌شود و Componentهایی که سرویس شبکه‌ای از طریق یک API ارائه می‌دهند برای دریافت درخواست‌ها روی پورت مشخص و پیش فرضی آغاز به Listen کردن می‌کنند.با توجه به شکل زیر و دستور ss می‌توان شماره پورت هر یک از Componentها را مشاهده کرد.

در بین این Componentهایی که در شکل مربوطه مشاهده می‌شود API Server روی پورت 6443 در دسترس می باشد و همانطور که بیان داده بودیم این Component اینترفیس اصلی مدیریت و ارتباط با کلاستر Kubernetes می‌باشد.حالا اگر این پورت 6443 از طریق شبکه سازمان یا اینترنت بدون تنظیمات امنیتی لازم در دسترس قرار بگیرد می‌تواند باعث دسترسی به یکسری مسیرهای پیش‌فرض شود و در صورت احرازهویت نامناسب و اشتباه می‌تواند باعث دسترسی به منابع کلاستر Kubernetes گردد.این نکته را باید در نظر بگیریم که Kubernetes و Docker دو پلتفرمی هستند که فرصت مدیریت و دسترسی به صورت Remote را برای ادمین‌های شبکه فراهم می‌کنند.بدون آنکه نیاز باشد به سرور SSH بزنیم از طریق ابزارهای Docker CLI و Kubectl می‌توان به هر کدام از API مربوط به پلتفرم ها متصل شد و آن را مدیریت کرد.در Docker معمولا باید Docker Engine API روی یک TCP Socket پیکربندی گردد اما در Kubernetes اگر دسترسی به API Server از روی شبکه فراهم و دارای مجوزهای لازم باشد فرصت مدیریت کلاستر به‌صورت Remote نیز فراهم می‌شود.

نکته:در برخی پیکربندی‌های Kubernetes از پورت‌ 8443 برای دسترسی به API Server استفاده می‌شود یا در ویرایش‌های قدیمی‌تر Kubernetes از پورت 8080 به صورت Insecure استفاده می‌شد.

پس آسیب‌پذیری Exposed Kubernetes API Server به حالتی گفته می‌شود که API Server روی پورت پیش فرض 6443 در شبکه سازمان یا بستر اینترنت قابل دسترس و همزمان تنظیمات Authentication یا Authorization یا مجوزهای بیش‌ازحد RBAC که به‌درستی پیکربندی نشده باشد به عنوان مثال Anonymous Access فعال باشد و دارای مجوزهای لازم بدون احرازهویت باشد.در این حالت به هکر این فرصت را می‌دهد بدون نیاز به Credential منابع Cluster را شناسایی کند و در برخی شرایط کنترل Cluster را به دست گیرد.

Kubernetes برای کنترل دسترسی به API Server از دو مرحله اصلی یعنی Authentication و Authorization استفاده می‌کند.در مرحله Authentication هویت درخواست‌ها که می‌تواند از سمت کاربر یا ServiceAccount و Componentها باشد از طریق روش‌های رایج مانند Token و Client Certificate مورد تحلیل قرار می‌گیرد و پس از آن در مرحله Authorization مشخص می‌شود که درخواست کننده اجازه دسترسی به چه منابع یا مسیرهایی را دارد.یکی از رایج‌ترین مکانیزم‌های Authorization در Kubernetes در واقع RBACها می‌باشد که از این طریق مجوزهای کاربران و گروه‌ها و ServiceAccountها را مشخص می‌کنیم.هنگامی که پورت API Server یا Kubelet در معرض دسترس قرار می‌گیرد مکانیزم‌های Authentication و Authorization که RBAC یکی از رایج‌ترین آن‌هاست نقش اصلی را در جلوگیری از دسترسی غیرمجاز به کلاستر Kubernetes ایفا می‌کند و پیکربندی اشتباه هرکدام از این موارد می‌تواند پیامدهای امنیتی جدی ایجاد کند.

قبل از اینکه به شناسایی آسیب‌پذیری بپردازیم لازم است به یک نکته کلیدی توجه کنیم که در دسترس بودن پورت 6443 روی شبکه به‌خودی‌خود آسیب‌پذیری محسوب نمی‌شود زیرا در یک کلاستر Multi-Node در واقع Worker Nodeهای مجاز و ابزارهای مدیریتی باید بتوانند با API Server از طریق شبکه ارتباط برقرار کنند.فعال یا غیرفعال بودن Anonymous Authentication به صورت پیش‌فرض می‌تواند به روش‌های راه‌اندازی کلاستر Kubernetes و توزیع‌های آن بستگی داشته باشد.زیرا در Kubernetes استاندارد گزینه anonymous-auth برابر true می‌باشد و ما با هرکدام از روش‌های نصب کلاستر مانند kubeadm یا ابزارهایی مانند kind یا Kubespray اگر در پروسه نصب این مقدار تغییر داده نشود Anonymous Authentication فعال باقی می‌ماند.در مقابل توزیعی با تنظیمات امنیتی پیش‌فرض مانند RKE2 گزینه anonymous-auth برابر false در نظر گرفته شده است در شکل‌های زیر تفاوت Kubernetes استاندارد و توزیع RKE2 مشاهده می‌شود.اگر در هنگام مرور API Server روی سرور گزینه anonymous-auth در خروجی مشاهده نگردید مقدار این گزینه به صورت true در نظر گرفته می‌شود.البته این خروجی فقط زمانی معتبر است که تنظیمات Anonymous Authentication از طریق گزینه authentication-config-- در فایل دیگری تعریف نشده باشد.

بنابراین فعال‌بودن Anonymous Authentication یا به دلیل تنظیمات پیش‌فرض روش نصب Kubernetes یا توسط ادمین شبکه فعال می‌شود.بااین‌حال این وضعیت تنها زمانی به یک مشکل امنیتی تبدیل می‌شود که API Server در روی شبکه در دسترس باشد و تنظیمات Authorization نیز به کاربر system:anonymous یا گروه system:unauthenticated مجوزهای نامناسبی داده باشد.شدت این مشکل امنیتی به سطح مجوزها هم بستگی دارد چون فعال بودن Anonymous Authentication به معنی داشتن دسترسی دقیق به منابع Cluster نیست و می‌تواند از افشای محدود اطلاعاتی مانند نسخه جدید Kubernetes تا دسترسی غیرمجاز به منابع Cluster متغیر باشد.

حال که با ماهیت این آسیب‌پذیری آشنا شدیم در گام اول تحلیل می‌کنیم که آیا بدون Credential دسترسی به Endpointهای مربوط به API Server وجود دارد یا نه؟ از آنجا که API Server دارای تعدادی Endpoint داده‌های می باشد بنابراین Endpointهایی مانند api ، /version/ و apis/ از اولین مسیرهایی هستند که در مرحله شناسایی مورد تحلیل قرار می‌گیرند.البته در دسترس بودن هرکدام از این مسیرها به تنظیمات Authentication و Authorization کلاستر بستگی دارد با این‌ حال برای تست مستقیم Endpointها نیازی به استفاده از ابزار kubectl نیست و می‌توان درخواست‌ها را با هر ابزاری که قابلیت ارسال درخواست HTTP را داشته باشد ارسال کرد.در شکل‌های زیر برای انجام این تست از ابزارهای Curl و BurpSuite استفاده شده است.

همان‌طور که مشاهده می‌شود درخواست بدون Credential به مسیر version/ با موفقیت پردازش شده است و API Server شرحی مانند ویرایش Kubernetes و موارد دیگر را افشا می‌کند.برای مثال مقدار gitVersion ویرایش Kubernetes و مقدار goVersion ویرایش زبان Go استفاده‌شده برای Build این ادیشن از Kubernetes را بیانگر است.دسترسی به این مسیرها بدون Credential وابسته به تنظیمات Authentication و Authorization در روی سرور می باشد ابتدا در صورت فعال‌بودن Anonymous Authentication درخواست بدون Credential با نام کاربری system:anonymous و به عنوان عضو گروه system:unauthenticated شناسایی می‌شود سپس Authorization مرور می‌کند که آیا این کاربر یا گروه اجازه ارسال درخواست GET را به مسیر version/ را دارد یا نه.این برآیند به‌تنهایی دسترسی مدیریتی به Cluster را ثابت نمی‌کند و برای مشخص‌شدن سطح واقعی دسترسی Anonymous باید سایر مسیرها و منابع API نیز باید تحلیل شوند.تا اینجا با این شرایط API Server با تنظیمات ناامن در دسترس می‌باشد و در گام نخست این آسیب‌پذیری سطح بالا محسوب نمی‌شود.

در گام بعدی تست می‌کنیم که آیا ما با استفاده از Anonymous Authentication می‌توانیم منابع کلاستر را مدیریت کنیم مثلا Nodeها یا Podها را ببینم:

مطابق شکل‌های زیر دسترسی به مسیرهای مربوطه و دیدن لیست Podها و Nodeها بدون Credential وجود ندارد و ممکن است یک مسیر پاسخ 200 و مسیر دیگری پاسخ 401 یا 403 برگرداند.همانطور که مشاهده می‌شود برای خطای 403 یعنی کاربر Anonymous مجوز دسترسی به این مسیر را ندارد و خطای 401 بیانگر این است درخواست فاقد Credential معتبر بوده و فرایند Authentication با موفقیت انجام نشده است برای مثال ممکن است Anonymous Authentication غیرفعال باشد.پس در نهایت دریافت پاسخ 401 یا 403 حاکی از آن است که در زمان انجام تحلیل مشاهده منابع موردنظر بدون Credential قابلیت‌پذیر نبوده است.بااین‌حال برآیند هر مسیر باید جداگانه تحلیل شود زیرا مجوز دسترسی می‌تواند برای منابع و عملیات مختلف متفاوت باشد.

بنابراین مشاهده و دگرگونی‌ها در منابع Cluster نیازمند مجوزهای لازم و Authorization می‌باشد.اگر از طریق پیکربندی نادرست RBAC به کاربر system:anonymous یا گروه system:unauthenticated مجوزهای ناامنی داده شود مهاجم می‌تواند بدون ارائه Credential منابع مجاز Cluster را مشاهده کند.پس فعال‌بودن Anonymous Authentication به‌تنهایی به معنی آسیب‌پذیری مفصل نیست زیرا پس از شناسایی درخواست در لایه Authorization تحلیل می‌باشد که این هویت باید به کدام منابع و عملیات دسترسی داشته باشد.یه نکته ای دیگری که باید در نظر گرفت این است که API Server ممکن است دقیقا محافظت شده باشد اما مجوزهای کاربران یا ServiceAccountها بیش از حد نیاز تعریف شده باشد.برای مثال اگر یک ServiceAccount معمولی به Role Cluster-admin متصل شده باشد افشای Token آن می‌تواند دسترسی مدیریتی جامع به Cluster را ایجاد کند.و در نهایت زنجیره حمله زمانی مفصل می‌شود که Credential Leakage با RBAC Misconfiguration ترکیب شود یا اعطای مجوزهای بیش‌ازحد که منجر به بیشتر شدن سطح دسترسی و حتی تصاحب جامع Cluster خواهد شد.

حالا به آسیب‌پذیری دوم یعنی Exposed Kubelet API که یکی دیگر از Componentهای Kubernetes در بخش Worker Nodeها می‌باشد می‌پردازیم:

همانطور که شرح دادیم گفتیم که Kubelet یکی از Componentهای اصلی Kubernetes در هر Worker Node می باشد و روی هر Worker Node یک نمونه جداگانه از آن اجرا می‌شود.به عنوان مثال اگر Scheduler یکی از Componentهای Controle Plane تصمیم بگیرد یک Worker Node را برای اجرای یک Pod انتخاب کند این تصمیم‌گیری را از طریق API Server ثبت می‌کند سپس Kubelet اون Worker Node انتخاب‌شده مشخصات Pod اختصاص‌یافته را به آن Node از طریق API Server دریافت می‌کند و از طریق اینترفیس CRI از Container Runtime به عنوان مثال Containerd می‌خواهد Containerهای تعریف‌شده در آن Pod را ایجاد و اجرا کند.در ادامه Kubelet وضعیت همان Worker Node که شامل Podها و Containerها می‌باشد را به API Server گزارش می‌دهد.این Component به‌صورت پیش‌فرض روی پورت 10250 کار می‌کند.

معمولا اکثر سازمان‌ها کلاستر Kubernetes را در محیط‌های عملیاتی به‌صورت Multi-Node پیاده‌سازی و اجرا می‌کنند در این معماری باید پورت Componentها در شبکه در دسترس باشد تا Componentها و ابزارهای مدیریتی بتوانند از این طریق با همدیگر ارتباط برقرار کنند.حالا اگر این پورت 10250 مربوط به Kubelet یک یا چند Worker Node با تنظیمات ناامن و اشتباه Authentication و Authorization در شبکه سازمان یا اینترنت در دسترس باشد هکر می‌تواند گزارش‌ها مربوط به Podها و Nodeها و Containerهای همان Worker Node را مشاهده کند و در شرایطی که پیکربندی جامعا ناامن باشد علاوه بر مشاهده شرحات قابلیت دریافت لاگ Containerها و زدن دستورات مختلفی در داخل Containerهای آن worker Node خاص وجود دارد که می‌تواند منجر به حمله RCE شود.

برای مثال طبق شکل زیر اگر پورت Kubelet مربوط به Worker Node 1 به‌صورت ناامن در دسترس باشد دامنه دسترسی هکر در ابتدا به همان Worker Node 1 که شامل Podها و Containerهای اجراشده در آن می‌باشد محدود خواهد بود و به‌صورت مستقیم نمی‌تواند به منابع Worker Node 2 دسترسی پیدا کند پس در خروجی ناامن بودن Kubelet یک Worker Node در ابتدا همان Node را تحت‌تأثیر قرار می‌دهد و در صورتی که Credential افشاء شود یا پیکربندی بقیه قسمت‌ها به‌صورت ناامن انجام شده باشد دامنه حمله ممکن است به کل Cluster گسترش پیدا کند.

شاید این سوال مطرح شود که آیا بدون دسترسی به API Server می‌توان به‌صورت مستقیم به Worker Node‌ها دسترسی و ارتباط برقرار کرد و چه لزومی وجود دارد که پورت Kubelet در معرض دسترسی قرار بگیرد؟پاسخ به این سوال این است که بدون دسترسی به API Server توانایی مدیریت و ارسال درخواست به یک Worker Node که پورت Kubelet آن Expose شده و در دسترس می‌باشد وجود دارد.پس انجام یکسری کارهای عملیاتی روی یک Worker Node خاص نیاز به دسترسی مستقیم به API Server نمی‌باشد.البته برآیند این درخواست باز به تنظیمات Authentication و Authorization بستگی دارد.تبیین دادیم که Component‌ها برای اینکه بتوانند با یکدیگر ارتباط برقرار کنند باید Port آن‌ها در دسترس باشد وگرنه ارتباط مختل خواهد شد. این تنظیمات ناامن هستند که یک Component را مستعد آسیب‌پذیری می‌کند.پس می‌توان خروجی گرفت که API Server نقطه اصلی ورود به تمامی منابع کلاستر Kubernetes می‌باشد اما Kubelet مسئول اجرا Podها و مدیریت وضعیت Workloadهای مستقر روی همان Node می‌باشد.

در ادامه شرح بیشتری را ارزیابی می‌کنیم که Kubelet تحت چه تنظیماتی ناامن می‌شود و این پیکربندی‌های نادرست در مرحله نخست چه پیامدهای امنیتی می‌تواند به همراه داشته باشد.

معمولا پورت 10250 مربوط به Kubelet برای ارتباط با سایر Componentهای مجاز مانند API Server استفاده می‌شود.در برخی شرایط ممکن است یک ادمین شبکه به‌صورت موقت یا نداشتن دانش امنیتی این پورت را برای مانیتورینگ یا Debug کردن بدون تنظیمات امنیتی مناسب روی شبکه و اینترنت Expose و در دسترس قرار دهد.حالا اگر Kubelet با تنظیمات anonmouse-auth=true-- و با حالت authorization-mode=Webhook-- پیکربندی شده باشد نیاز به Authorization می‌باشد و مجوز درخواست از سمت API Server مرور می‌شود به عنوان مثال اگر با استفاده از RBAC به کاربر system:anonymous یا گروه system:unauthenticated مجوز خاصی داده شده باشد متناظر با همان مجوز می‌توان به یک Worker Node دسترسی داشت اما اگر Kubelet با حالت authorization-mode=AlwaysAllow-- پیکربندی شده باشد که خطرناک‌ترین حالت ممکن می‌باشد در این حالت ابتدا با هویت system:anonymous اکثر درخواست‌ها بدون Credential پذیرفته می‌شود و سپس حالت AlwaysAllow درخواست‌ها را بدون ارزیابی RBAC مجاز می‌کند و در خروجی کاربر Anonymous می‌تواند به Endpointهای فعال Kubelet API روی همان Worker Node دسترسی پیدا کند.در نسخه جدید‌های قدیمی Kubernetes پورت 10255 به Kubelet اختصاص داشت که به‌صورت ReadOnly بود و بدون Credential قابلیت مشاهده برخی از داده‌ها Podها و Nodeها وجود داشت این پورت در تنظیمات در زمان حاضری Kubernetes به‌صورت پیش‌فرض غیرفعال می‌باشد.

یک نکته‌ای دیگری که باید به آن اشاره کنیم این است که رفتار پیش‌فرض و مجوزهای Anonymous بین API Server و Kubelet یکسان نیست و هر کدام از این Compoetها تنظیمات مستقل به خود را دارند در واقع anonymous-auth یک تنظیم کلی برای کلاستر Kubernetese نیست و حتی در یک کلاستر Multi-Node هر Node باز پیکربندی مخصوص به خودش را دارد ممکن است anonymous-auth برای یک Node فعال باشد و برای دیگری غیرفعال باشد در ادامه در API Server دسترسی به مسیرها از طریق Authorization و معمولا مجوزهای RBAC تعیین می‌شود در حالی که برای Kubelet حاصل احراز هویت درخواست‌ها به حالت Webhook بستگی دارد.بنابراین، دسترسی ناامن به API Server می‌تواند منابع کل کلاستر را تحت‌تأثیر قرار دهد اما دسترسی مستقیم به یک Kubelet در ابتدا به قابلیت‌های آن و Workloadهای در حال اجرا روی همان Worker Node محدود می‌شود.

حالا با تبیینات داده‌شده تحلیل می‌کنیم که آیا می‌توان به Endpointهای یک Kubelet که پورت آن ٍExpose شده و در دسترس می‌باشد بدون Credential درخواست ارسال کرد؟همانطور که در شکل‌های زیر مشاهده می‌شود دسترسی به مسیرهای pods/ و spec/ بدون Credential و احرازهویت مناسب وجود دارد مسیر pods/ شرح مربوط به Podها و Containerهای در حال اجرا روی همان Worker Node را نمایش می‌دهد و مسیر spec/ داده‌ها سیستمی Nodeها و اینکه از چه Container Runtime استفاده‌شده و یا نسخه جدید Kubelet استفاده‌شده چند می‌باشد.بنابراین باز بودن پورت 10250 بدون احراز هویت مناسب باعث افشای شرح حیاتی و در برخی موارد باعث کنترل Containerها می‌شود.

در برخی موارد با وجود احرازهویت نامناسب Kubelet تمامی Endpointهای آن قابل‌دسترس نیست به عنوان مثال مطابق شکل زیر دسترسی به مسیر metrics/ وجود ندارد و با خطای 404 مواجه می‌شویم این پاسخ بیانگر این است که این مسیر وجود ندارد یا این Endpoint فعال نیست و به‌تنهایی بیانگر محدودیت‌های Authentication یا Authorization نیست.

حالا با گزارش‌های که از مرحله قبل در مورد Podها و Continerهایی که روی Worker Node خاصی که دسترسی به Kubelet آن فراهم می‌باشد به دست آوردیم تحلیل می‌کنیم آیا قابلیت دسترسی به Continerها و اجرا Command درون آن‌ها وجود دارد یا نه؟برای اینکه بتوانیم درون یک Container دستوری اجرا کنیم نیاز به دسترسی به Endpointهای run/ یا exec/ می‌باشد.برای مشخص کردن Container موردنظر جهت وارد کردن دستورات نیاز به سه پارامتر namespace و Pod و Container می‌باشد.مطابق شکل زیر namespace معادل default و Pod معادل nginx-7d8f9c6b5-x7k9m و Container معادل nginx می‌باشد.خروجی شکل زیر ثابت می‌کند که نه تنها مسیر run/ بدون Credential در دسترس می‌باشد بلکه قابلیت اجرای دستورات دلخواه بدون هیچ‌گونه احراز هویت مناسبی فراهم می‌باشد که منجر به حمله RCE در محدوده همان Container می‌شود این سطح از دسترسی یک آسیب‌پذیری بحرانی محسوب می‌شود زیرا هکر می‌تواند با بالاترین سطح دسترسی دستورات مخرب را درون Container اجرا کند.بااین‌حال دسترسی root داخل Container به معنی دسترسی root روی Worker Node نیست زیرا Container همچنان ممکن است توسط سازوکارهای ایزوله‌سازی محدود شده باشد.اگر Container دارای مجوزهای اضافی دسترسی به منابع Host یا پیکربندی privileged باشد این دسترسی می‌تواند منجر به تصاحب Worker Node مربوطه گردد یا باعث Lateral Movement به سایر بخش‌های دیگر Cluster شود.

امیدوارم که این پست برای کسانی که به این حوزه علاقمند هستند مفید واقع شده باشد در این پست سعی کردیم به صورت خلاصه و دقیق تهدیدات ناشی از در معرض دسترس قرارگرفتن Kubernetes API Server و Kubelet API مرور کنیم که با پیکربندی نادرست چه پیامدهایی می‌تواند به همراه داشته باشد و با اعمال کردن حداقل سطح دسترسی چطور می‌توان این خطرات را افت داد.



سوالات متداول

آخرین اطلاعات درباره kubernetes چیست؟

جدیدترین اطلاعات و تغییرات مربوط به kubernetes در این گزارش ارائه شده است.

چرا Exposed Kubernetes API Server and Kubelet API - ویرگول اهمیت دارد؟

این موضوع به دلیل اطلاعات و کاربردهای مرتبط، مورد توجه کاربران قرار گرفته است.

Exposed Kubernetes API Server and Kubelet API - ویرگول چیست؟

در این مطلب اطلاعات، جزئیات و نکات مرتبط با Exposed Kubernetes API Server and Kubelet API - ویرگول بررسی شده است.

نویسنده: محمد جواد عظیم تاریخ: جمعه 3 مهر 1405 ساعت: 12:22 برچسب:

صفحه بندی