OpenZiti؛ شبکهٔ پوششی متنباز برای دسترسی بدون اعتماد به سرویسها
چرا OpenZiti را باید «شبکهٔ سرویسمحور» دانست؟
OpenZiti یک سکوی متنباز برای ساختن شبکهٔ پوششی Zero Trust است؛ یعنی شبکهای که روی زیرساخت IP، ابر، مرکز داده یا اینترنت موجود قرار میگیرد، اما تصمیم دسترسی را از نشانی IP و موقعیت شبکه جدا میکند. هدف آن این نیست که فقط یک مسیر رمزگذاریشده میان دو زیرشبکه بسازد. در مدل OpenZiti، هر کاربر، دستگاه، workload و برنامه یک هویت رمزنگاریشده دارد، هر سرویس جداگانه تعریف میشود و هر اتصال باید احراز هویت، با سیاست مجاز و در مسیر رمزگذاریشده برقرار شود. نتیجه برای کاربر نهایی میتواند شبیه دسترسی به یک برنامهٔ خصوصی باشد، نه ورود کلی به یک شبکهٔ داخلی.
این تفاوت، ارزش اصلی پروژه را روشن میکند. مخزن رسمی، OpenZiti را شبکهای programmable و کاملاً Zero Trust معرفی میکند که سرویسها را برای افراد غیرمجاز نامرئی میسازد و هم برای برنامههای قدیمی از طریق tunneler و هم برای برنامههای جدید از طریق SDK قابل استفاده است. بنابراین «overlay» به معنای حذف شبکهٔ زیرین نیست؛ روترها همچنان بستهها را از روی ارتباطات موجود عبور میدهند، اما کنترل هویت، کشف سرویس، سیاست و رمزنگاری به یک لایهٔ اختصاصی منتقل میشود.
اجزای اصلی: کنترل، مسیر و نقطهٔ پایان
معماری رسمی چهار لایهٔ Fabric، Edge، SDK و Clients دارد. Fabric هستهٔ مش روترها و مدارهاست؛ بهتنهایی قابلیتهای سطح پایینتری دارد و هنوز مدل هویت و دسترسی Edge را در اختیار ندارد. Edge روی Fabric، هویتهای endpoint، نشست API، کنترل نشست و APIهای مدیریتی و کاربری را اضافه میکند. این تفکیک برای طراحی دفاعی مهم است، چون «روتر» با «کنترلکننده» و هر دو با «برنامه» یک نقش ندارند.
Controller صفحهٔ مدیریت و هماهنگی است: پیکربندی، هویت، احراز هویت، مجوزها، وضعیت روترها و توپولوژی را نگه میدارد و API ارائه میکند. این جزء را نباید با گذرگاه دادهٔ برنامه اشتباه گرفت؛ دادهٔ سرویس از مسیر Fabric عبور میکند، در حالی که Controller تصمیمها و وضعیت مورد نیاز را توزیع میکند. Edge Router صفحهٔ داده و بخشی از مش است. روترها با Controller از طریق control connection هماهنگ میشوند و میان خود link connection میسازند؛ مسیریابی OpenZiti مسیر مناسب و در صورت نیاز مسیر جایگزین را انتخاب میکند.
در سمت endpoint دو انتخاب وجود دارد. Tunneler برای نرمافزار تغییریافتهنشده مناسب است: هویت OpenZiti را حمل میکند و ترافیک برنامه را بهصورت شفاف intercept میکند. SDK انتخاب برنامهمحور است: برنامه مستقیماً enroll و authenticate میشود، سرویسهای مجاز را میبیند و روی Edge Router اتصال میسازد. مستندات رسمی SDKهای Go، Python، C، Java، JavaScript/Node.js، C# و Swift و نیز Tunneler SDK مبتنی بر C را فهرست میکند؛ اما پشتیبانی زبان را باید در نسخه و مخزن همان SDK بررسی کرد، نه با فرض اینکه همهٔ قابلیتها یکساناند.
Identity، سرویس و سه سیاستی که اغلب فراموش میشوند
در OpenZiti هویت معادل حساب دسترسی ساده نیست؛ یک موجودیت منطقی در Controller است که به گواهی X.509 نگاشت میشود. دو طرف اتصال با mTLS احراز هویت میشوند. هویت میتواند برای User، Device یا Service ساخته شود؛ این سه نوع از نظر قابلیتها همارزند و نوع انتخابشده قابل تغییر نیست. PKI داخلی میتواند گواهی را صادر کند، یا سازمان CA شخص ثالث خود را به Controller معرفی کند. برای استقرار گستردهٔ دستگاهها، auto-enrollment با CA شخص ثالث نیز وجود دارد، ولی این فقط هویت را برای احراز هویت میسازد و مجوز سرویس باید جداگانه اعمال شود.
مسیر معمول آزمایش با One-Time Token یا OTT است. Controller هنگام ساخت هویت یک JWT صادر میکند؛ مستندات میگوید این token یکبارمصرف است و ۲۴ ساعت پس از ساخت هویت منقضی میشود. پس از enroll، خروجی CLI یک فایل پیکربندی دائمی است که کلید خصوصی دارد؛ این فایل را نباید مانند یک فایل عادی جابهجا یا در سامانهٔ کنترل نسخه ذخیره کرد. برای نمونهٔ مفهومی:
ziti edge create identity "app-client" -o app-client.jwt
ziti edge enroll --jwt app-client.jwt --out app-client.json
این دو دستور بهتنهایی دسترسی نمیدهند. OpenZiti دستکم سه رابطهٔ سیاستی را بررسی میکند. Service Policy از نوع Dial مشخص میکند کدام هویت سرویس را مصرف کند و از نوع Bind مشخص میکند کدام هویت سرویس را ارائه دهد. Edge Router Policy تعیین میکند هویت از کدام روترها وارد Fabric شود. Service Edge Router Policy مشخص میکند خود سرویس از کدام روترها قابل استفاده یا ارائه باشد. برای برطرف کردن خطا، داشتن هویت و سرویس کافی نیست: هویت و سرویس باید دستکم یک Edge Router آنلاین و مشترک داشته باشند. Policy Advisor رسمی دقیقاً برای دیدن همین وضعیت، از جمله نبود Dial یا Bind و نبود روتر مشترک، به کار میرود.
برای گروهبندی، نقشها و role attributeها با # و شناسههای صریح با @ در سیاستها استفاده میشوند. معنای allOf و anyOf باید در طراحی ثبت شود؛ اشتباه در آن میتواند گروه بزرگتری از کاربران را مجاز کند. #all برای شروع آزمایشی مفید است، اما در محیط سازمانی بهتر است دامنهٔ آن با گروه، سرویس و ناحیهٔ مشخص محدود شود. اینجا همان جایی است که Zero Trust از شعار به کنترل قابل آزمون تبدیل میشود: سؤال باید «این هویت دقیقاً کدام سرویس را، از کدام مسیر و با کدام نقش میبیند؟» باشد، نه «آیا به شبکه وصل است؟».
Service intercept و سه شیوهٔ پایاندهی
در OpenZiti، Service تعریف دسترسی به یک resource است، نه خود نرمافزار. نام سرویس در namespace همان شبکه یکتا است و لازم نیست برای آن DNS عمومی ثبت شود. برای دسترسی کاربر به یک برنامهٔ قدیمی، Tunneler میتواند نام یا آدرس intercept را به سرویس نگاشت کند، اتصال برنامه را بگیرد و آن را به مسیر OpenZiti بفرستد. این فرایند با VPN فرق دارد: بهجای اینکه سیستمعامل کاربر را عضو یک subnet گسترده کند، فقط جریان مورد نیاز برای سرویس تعریفشده وارد overlay میشود. جزئیات نامگذاری، پورت و پیکربندی intercept باید با مستندات tunneler و نوع endpoint همان نسخه آزمایش شود؛ نباید یک نمونهٔ لینوکس را بیبررسی به موبایل یا دسکتاپ تعمیم داد.
راه اول، SDK-embedded است. برنامهٔ سرور نیز SDK دارد، identity میگیرد و بهجای listen عمومی، اتصال خروجی امن به یک یا چند Edge Router برقرار میکند. این حالت هم Zero Trust دوسویه و هم رمزنگاری end-to-end ارائهشده توسط Ziti میان دو برنامهٔ SDK را ممکن میکند و سرور میتواند کاملاً dark باشد. هزینهاش تغییر کد، چرخهٔ عمر گواهی و نگهداری SDK است.
راه دوم proxy یا sidecar مبتنی بر SDK است. برای برنامهٔ قدیمی، proxy در کنار سرویس قرار میگیرد و فقط به آن متصل میشود. از دید سازمان این گزینه سریعتر است، اما برنامه هنوز باید از proxy اتصال بگیرد و بخش proxy تا برنامه تحت رمزنگاری end-to-end خود Ziti نیست؛ اگر TLS برنامه لازم است باید جداگانه برقرار شود. راه سوم پایاندهی در Router است: روتر به tcp:host:port یا مقصد UDP وصل میشود. این راه برای یک سرویس موجود ساده است، اما برنامه کاملاً dark نیست و مستندات تصریح میکند جلسهای که در Router پایان مییابد، end-to-end encryption فراهمشده توسط Ziti میان دو SDK ندارد.
پس «dark service» را نباید با «سرویس جادویی بدون نیاز به backend» یکی دانست. سرویس واقعی همچنان وجود دارد و باید به مقصد دسترسی داشته باشد؛ فقط برای هویت غیرمجاز در اینترنت یا شبکهٔ ورودی، listening port عمومی و اطلاعات سرویس آشکار نمیشود. این مرزبندی در ارزیابی مهم است: پنهانشدن سطح حمله جایگزین وصلهکردن برنامه، کنترل دسترسی داخلی، ثبت رویداد و حفاظت از endpoint نیست.
رمزنگاری و تفاوت واقعی با VPN
مستندات Connection Security پنج نوع مسیر را تفکیک میکند: control میان Controller و Router، link میان روترها، edge چندگانه میان SDK و Edge Router، APIهای Controller، و service که داخل edge حمل میشود. control و link با mTLS 1.2 یا بالاتر حفاظت میشوند؛ edge نیز mTLS دارد. برای service، مستندات رمزنگاری دادهٔ برنامه را با رمزنگاری کلیدعمومی/خصوصی مبتنی بر libsodium توضیح میدهد. نشست API و token سرویس نیز فقط یک بار در زمان اتصال بررسی نمیشوند؛ روتر token نشست را اعتبارسنجی میکند و اگر نشست بیاعتبار شود، اتصالهای ساختهشده با آن خاتمه مییابد.
VPN معمولاً یک تونل شبکهای یا دسترسی به محدودهای از آدرسها عرضه میکند و پس از ورود، سطح دسترسی ممکن است بیشتر از یک برنامهٔ واحد باشد. OpenZiti بهجای اعتماد ضمنی به subnet، service را واحد سیاست قرار میدهد و میتواند برای هر هویت، سرویس و Edge Router مجوز جدا صادر کند. در نتیجه، مزیت اصلی آن «VPN سریعتر» نیست؛ segmentation، identity و dark بودن سرویس است. با این حال OpenZiti معادل همهٔ تواناییهای VPN نیست: اگر سازمان به دسترسی عمومی لایهٔ سه، broadcast، پروتکل خاص یا نرمافزاری نیاز دارد که با سرویسمحوری سازگار نیست، باید آن را جداگانه ارزیابی کند. همچنین Tunneler یک عامل جدید و SDK یک وابستگی توسعهای است؛ حذف VPN client به معنای حذف عملیات endpoint نیست.
استقرار: از آزمایش محلی تا محیط سازمانی
برای آزمایش، Quickstart رسمی زنجیرهٔ روشنی دارد: دریافت binary، ساخت PKI، ساخت و مقداردهی Controller، روشنکردن آن، ساخت پیکربندی Router، ساخت موجودیت Router در Controller، enroll کردن Router با OTT و ایجاد policyهای پیشفرض. در quickstart، PKI شامل root CA و intermediate CAهای مربوط به بخشهای مختلف است. برای محیط واقعی، این اسکریپت را تولیدی فرض نکنید؛ DNS، SAN گواهی، پشتیبانگیری، نگهداری کلیدها، مانیتورینگ و مدل HA باید پیش از انتشار سرویس طراحی شوند.
در استقرار Linux، راهنمای رسمی Controller به نصب package، اجرای bootstrap، تعیین نام دائمی بیرونی، نام یکتا، trust domain، پورت، رمز مدیر و در صورت نیاز Console اشاره میکند. برای پیوستن Controller جدید به cluster، PKI لازم است و node name نباید تکراری باشد. راهنمای Router نیز آدرس دائمی، پورت و enrollment token صادرشده از Controller را میخواهد. فایروال را بر اساس listenerهای واقعاً لازم باز کنید، نه بر اساس عادتهای یک VPN قدیمی؛ در شبکهٔ خصوصی میتوان Router را طوری قرار داد که اتصال خروجی بسازد و inbound عمومی نداشته باشد.
یک سناریوی سازمانی نمونه چنین است: شرکت، CRM قدیمی را در شبکهٔ خصوصی و API جدید را در ابر دارد. برای CRM، یک Router نزدیک backend و یک Tunneler روی میز کاربران یا سرور jump نصب میشود. برای API، SDK در کلاینت و سرور embed میشود. تیم IAM برای کارکنان گروه #sales-eu هویت صادر میکند، Service Policy فقط Dial به #crm میدهد، Bind فقط به identity سرویس backend تعلق میگیرد و Service Edge Router Policy دسترسی را به Routerهای منطقهٔ اروپا محدود میکند. کاربران همان نام سرویس را میبینند، اما به subnet کامل، پورتهای دیگر یا سرویس توسعه دسترسی ندارند. برای حذف فوری دسترسی، identity یا policy لغو میشود و اعتبار نشستهای مرتبط باید در آزمون قطع اتصال مشاهده شود.
روش ارزیابی و محدودیتها
ارزیابی را با ادعاهای قابل اندازهگیری انجام دهید. نخست، ماتریس مجوز بسازید: هویت مجاز، سرویس، نوع Dial یا Bind، Router مجاز و وضعیت مورد انتظار. سپس با یک هویت مجاز و یک هویت بیمجوز تست کنید؛ انتظار فقط خطای اتصال نیست، بلکه نام سرویس و پورت آن نیز نباید برای هویت بیمجوز قابل کشف باشد. قطع Controller، قطع یک Router و قطع مسیر زیرین را جداگانه آزمایش کنید تا معلوم شود کدام اتصالهای موجود ادامه مییابند و کدام به سیاست و وضعیت تازه نیاز دارند. latency، throughput، reconnect، مصرف CPU/RAM، تعداد نشست همزمان و رفتار UDP را با بار واقعی اندازه بگیرید؛ مستندات عدد عملکردی عمومی ارائه نمیکند، پس عدد آزمایش را بهعنوان ویژگی ذاتی OpenZiti منتشر نکنید.
محدودیتهای مهم عبارتاند از: Controller و PKI نقاط عملیاتی حساساند؛ فایل identity حاوی کلید خصوصی است؛ سیاست اشتباه میتواند دسترسی ناخواسته بدهد؛ Router-terminated و proxy-terminated به اندازهٔ SDK-to-SDK dark و end-to-end نیستند؛ برنامهٔ قدیمی هنوز ممکن است روی localhost یا شبکهٔ محلی آسیبپذیر باشد؛ و مسیر overlay هزینهٔ latency و پیچیدگی مشاهدهپذیری دارد. خود OpenZiti سرویس برنامه را ارائه نمیکند، بنابراین availability واقعی backend، database و DNS داخلی همچنان مسئولیت سازمان است. برای مقیاس، مستندات Service از چند Router و چند terminator، failover و horizontal scale و strategyهایی مانند smartrouting، weighted و random صحبت میکند؛ اینها جایگزین طراحی ظرفیت و آزمون خرابی نیستند.
چکلیست اجرایی IROSG
- هدف را به سرویسهای منفرد و جریانهای مجاز تبدیل کنید، نه subnetهای کلی.
- مدل termination را برای هر سرویس ثبت کنید: SDK، proxy، Tunneler یا Router؛ سطح dark و end-to-end را صریح بنویسید.
- Controller، Router و endpoint را جداگانه inventory کنید و برای هرکدام مالک عملیاتی تعیین کنید.
- PKI، CA شخص ثالث، عمر گواهی، OTT، محل فایلهای identity و فرایند revoke و rotation را مستند کنید.
- سه policy را جداگانه بازبینی کنید و از
#allدر تولید فقط با توجیه مکتوب استفاده کنید. - برای هر هویت، آزمون مثبت، آزمون منفی و آزمون قطع نشست اجرا کنید؛ Policy Advisor را در عیبیابی بهکار ببرید.
- listenerها و فایروال را با معماری outbound و dark router تطبیق دهید و پورت عمومی غیرلازم را حذف کنید.
- لاگ Controller، Router، Tunneler و برنامه را همبسته کنید، بدون اینکه کلید خصوصی یا token را ثبت کنید.
- failover، انتخاب مسیر، ظرفیت، latency، UDP و رفتار هنگام از دسترفتن Controller را قبل از بهرهبرداری بسنجید.
- مستندات نسخهٔ پایدار را برای تولید با latest جدا کنید؛ ادعای نسخه، کارایی، CVE یا CVSS را فقط با مدرک همان نسخه منتشر کنید.
OpenZiti زمانی بیشترین ارزش دفاعی را دارد که بهعنوان لایهٔ دسترسی سرویسمحور و قابل آزمون به کار رود، نه یک برچسب تازه برای همان شبکهٔ مسطح قبلی. هویتهای کوچک و قابل لغو، سیاستهای محدود، سرویسهای dark، رمزنگاری مسیر و آزمون مداوم باید کنار هم قرار بگیرند. در چنین طراحیای، VPN تنها رقیب مفهومی نیست؛ مسئلهٔ اصلی، جایگزینکردن اعتماد ضمنی به مکان شبکه با اعتماد صریح به هویت، سرویس، سیاست و وضعیت واقعی اتصال است.