NET_ADMIN در یک کانتینر VPN: چه چیزی را و کجا میتواند تغییر دهد
این قابلیت تغییر رابطها، مسیرها و فایروال را درون یک فضای نام شبکه مجاز میکند. با شبکه میزبان، آن فضا همان پشته خود میزبان است.
NET_ADMIN قابلیت لینوکس است که به یک فرایند اجازه میدهد مدیریت شبکه انجام دهد، و در یک کانتینر دقیقاً همین کار را درون همان فضای نام شبکهای انجام میدهد که فرایند در آن اجرا میشود. این مجوز باز کردن سوکت نیست، و جانشین یک دستگاه یا مسیر هم نیست. پرسش جالب هرگز این نیست که آیا قابلیت داده شده است، بلکه این است که کدام فضای نام تغییر را دریافت میکند.
قابلیت چه چیزهایی را پوشش میدهد
درون فضای نام خود، فرایندی که NET_ADMIN دارد میتواند رابطها را بالا و پایین ببرد، نشانیها را تخصیص دهد، مسیرها را اضافه و حذف کند و قواعد فایروال بنویسد، که همان گروه عملیاتی است که capabilities(7) زیر این قابلیت جمع میکند. همچنین میتواند تنظیمات سطح رابط را تغییر دهد که کنترل میکند هسته چگونه ترافیک را در صف میگذارد و فیلتر میکند. یک کلاینت VPN معمولاً هنگام راهاندازی به چند مورد از آنها نیاز دارد و بعد از آن به هیچ چیز دیگری. به همین دلیل بیشتر ایمیجها دسترسی بیشتری از آنچه استفاده میکنند درخواست میکنند.
عملیات بیرون از آن فضای نام پوشش داده نمیشود، و امتیازهای مجاور جداگانهاند. خواندن و نوشتن بستههای خام متعلق به NET_RAW است، و ساختن دستگاه tun هم به قابلیت و هم به دسترسی به گره دستگاه نیاز دارد. فرایندی که دستگاه را ندارد خطای مجوزی میگیرد که شبیه مشکل شبکه است و چنین مشکلی نیست.
فضای نام شعاع آسیب را تعیین میکند
کانتینری روی شبکه پل خودش به loopback خود، رابطهای خود و جدول مسیریابی خود دسترسی دارد. دادن NET_ADMIN در آنجا به کلاینت VPN اجازه میدهد بدون دست زدن به تصمیمهای مسیریابی میزبان تونل بسازد، که همان ترتیبی است بیشتر ایمیجهای کانتینر فرض میکنند.
آن کانتینر را به شبکه میزبان تغییر دهید و همان اجازه اکنون مسیرهای میزبان و فایروال میزبان را ویرایش میکند، چون فضای نام جداگانهای باقی نمانده است. کلاینتی که قرار بود یک تونل را مدیریت کند آنگاه میتواند ترافیک کل دستگاه را تغییر مسیر دهد، و خطایی در اسکریپت برچیدنش قواعدی روی میزبان باقی میگذارد که هیچکس ننوشته است. در خود قابلیت چیزی تغییر نکرد؛ زمینه تغییر کرد. به همین دلیل همان فایل compose روی دو میزبان رفتار متفاوتی دارد.
سه پیشنیاز که در یکی ادغام میشوند
خطاهای راهاندازی در کانتینرهای VPN معمولاً یکی از سه چیز جداگانه را درگیر میکند: قابلیت، دستگاه تونل، و پشتیبانی هسته از پروتکل. دادن هر سه با هم کار میکند، و همچنین خطای بعدی را غیرقابل انتساب میکند. یک قطعه compose حداقلی قابلیت را میدهد و گره دستگاه را صریحاً عبور میدهد:
services:
vpn:
image: example/vpn-client:latest
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun
sysctls:
- net.ipv4.conf.all.src_valid_mark=1مستندات خود ایمیج را بخوانید تا بدانید به کدام sysctl نیاز دارد، زیرا یک sysctl درون کانتینر ممکن است به امتیاز اضافی یا تنظیمی در سطح میزبان نیاز داشته باشد. جایی که ایمیج تنها حالت فضای کاربر را پشتیبانی میکند، اصلاً به دستگاهی نیاز نیست و فهرست قابلیتها به همان نسبت کوچک میشود.
عملیات محدود را بدهید، نه حالت را
حالت ممتاز همه قابلیتها را واگذار میکند و همزمان دسترسی به دستگاه را گسترش میدهد، پس پنهان میکند که کدام یک از سه پیشنیاز کم بود. همچنین حالتهای خرابی کانتینر را از تغییرات میزبان غیرقابل تفکیک میکند. حتی وقتی نوشتنش طولانیتر است، فهرست صریح را ترجیح دهید.
استقرارهای بدون root و در فضای نام کاربر تغییر میدهند که یک قابلیت در عمل چه معنایی دارد، چون فرایند ممکن است آن را فقط درون یک فضای نام نگاشتشده نگه دارد. کپی کردن فهرست قابلیتها از یک نمونه rootful به محیط اجرای بدون root و انتظار همان دسترسی، راه رایجی برای از دست دادن یک بعدازظهر است.
اسرار به تصمیم جداگانهای تعلق دارند. داشتن NET_ADMIN هیچ چیزی درباره اینکه کلاینت کدام هویت همتا را ارائه میدهد، کدام اعتبارنامهها را بارگذاری میکند یا چگونه چرخانده میشوند نمیگوید. مدیریت شبکه اعتماد فراهم نمیکند.
تغییر را بررسی کنید و ثبت کنید که چرا این اجازه وجود دارد
پیش از اشکالزدایی تونل تأیید کنید کانتینر واقعاً چه دریافت کرده است. بررسی زیر قابلیتهای افزوده و حالت شبکه را گزارش میکند و سپس نشان میدهد فهرست رابطها از درون چگونه به نظر میرسد:
docker inspect --format '{{.HostConfig.CapAdd}} {{.HostConfig.NetworkMode}} {{.HostConfig.Privileged}}' vpn
docker exec vpn sh -c 'grep CapEff /proc/self/status'
docker exec vpn ip -br addr
docker exec vpn ip routeاگر قابلیت وجود دارد و فهرست رابطها هنوز خالی است، کلاینت پیش از آنکه بتواند چیزی بسازد شکست خورده است، و گزارشهای کانتینر جای بعدی برای نگاه کردن است. اگر تونل وجود دارد اما ترافیک جریان ندارد، جدول مسیریابی درون کانتینر به پرسش بعدی پاسخ میدهد.
مسیر برچیدن را هم آزمایش کنید، چون کلاینتی که قواعد فایروال مینویسد میتواند آنها را جا بگذارد. کانتینر را متوقف کنید و اگر شبکه میزبان استفاده میشود مجموعه قواعد میزبان را دوباره بررسی کنید. اجازهای که فقط دو ثانیه در راهاندازی لازم است نباید در فایل compose بهعنوان الزامی دائمی توصیف شود، بدون یادداشتی که این را توضیح دهد.
دلیل را کنار هر قابلیت بنویسید: کدام عملیات به آن نیاز داشت و بدون آن چه چیزی شکست میخورد. آن یادداشت از بهروزرسانی ایمیج جان سالم به در میبرد، و همان تفاوت میان فهرست امتیازهای بازبینیشده و فهرستی است که با کپی و چسباندن رشد کرده است.