در این مقاله قرار است چالش احراز هویت در سیستم های میکروسریس را بررسی کنیم و در پایان آن تمام دانشی که برای درک این چالش و معتبر ترین راه حل های برطرف کردن آن وجود دارد را بدست خواهید آورد.
احراز هویت (Authentication) عمل تایید هویت کاربران یا بخشی از برنامه خودمان یا برنامه ای دیگر است که به عنوان بخشی از یک سیستم کنترل دسترسی شناخته می شود. در واقع احراز هویت یعنی اینکه ما تشخصی بدهیم کسی که درحال ارتباط برقرار کردن با برنامه ی ما است همان کسی است که ادعا می کند. به عنوان مثال ما از کاربرمان می خواهیم با استفاده از Username و Password مشخص کنند چه کسی هستند و ما هم با ارزیابی این دو مقدار متوجه می شویم که او واقعا همان کسی که می گوید هست یا خیر.
حالا که فهمیدیم چه کسی با ما در ارتباط است، لازم است بدانیم که این فرد چه کارهایی را می تواند و چه کارهایی را نمی تواند انجام دهد. به این مکانیزم که بر اساس اطلاعاتی که از آن فرد داریم، تشخیص بدهیم چه کارهایی را می تواند انجام دهد و یا به چه اطلاعاتی می تواند دسترسی داشته باشد، کنترل مجوز (Authorization) گفته می شود. مثلا فردی که در دپارتمان A است اجازه دسترسی به اطلاعات دپارتمان B را ندارد.
یک برنامه میکروسرویس چندین سرویس مستقل دارد که هر کدام عملکرد از پیش تعریف شده خاصی را انجام می دهند. هدف اصلی ما این است که سرویس های مختلف برنامه، کاربران و دیگر سرویس ها بتوانند به راحتی با برنامه ی ما ارتباط برقرار کنند. در نتیجه در این مقاله، چالشهای اصلی احراز هویت در معماری میکروسرویسها، رویکردهایی که میتوانید استفاده کنید و تکنیکهای رایج مانند SSO و JWT را بررسی خواهیم کرد.
احراز هویت در میکروسرویس ها می تواند سه معنی داشته باشد: احراز هویت کاربران نهایی که به برنامه میکروسرویس دسترسی دارند، احراز هویت میکروسرویس هایی که به میکروسرویس های دیگر متصل می شوند، احراز هویت سرویسهای خارجی که از طریق API به میکروسرویسهای برنامه ما متصل میشوند.
احراز هویت Monolith در مقابل احراز هویت Microservices
برنامه یکپارچه (Monolith ) برنامه ای تقسیم ناپذیر است که معمولاً از یک رابط کاربری سمت سرویس گیرنده (Client)، یک برنامه سمت سرور و یک پایگاه داده (Database) تشکیل شده است که همه کاملاً یکپارچه شده اند تا همه ی عملکردهای برنامه را در یک برنامه ی واحد ارائه دهند. این نوع از برنامه ها، همه ی منابع مورد نیاز خود را دارند، بنابراین در برنامه های Monolith احراز هویت فقط باید زمانی انجام شود که کاربران نهایی نیاز به دسترسی به برنامه داشته باشند.
در مقابل، یک برنامه میکروسرویس دارای چندین بخش مستقل است که از طریق APIها به هم متصل و مرتبط شده اند. هر زمان که یک میکروسرویس با سایر میکروسرویس ها ارتباط برقرار می کند، باید از احراز هویت آن اطمینان حاصل کنید. احراز هویت تضمین می کند که فقط سرویس ها و کاربران قانونی به هر میکروسرویس دسترسی پیدا کنند. علاوه بر این، مانند یک برنامه یکپارچه، نیاز به احراز هویت کاربران نهایی هم وجود دارد.
احراز هویت (authentication) و مجوز دسترسی (authorization) از دارایی های ضروری یک برنامه میکروسرویس هستند. که به عنوان یک بررسی امنیتی اضافی برای همه منابع قابل دسترسی عمل می کند و از شکاف های امنیتی و نقاط کور جلوگیری می کند.
چالش های احراز هویت Microservices
در معماری میکروسرویس، هر میکروسرویس یک عملکرد خاص یا بخشی از منطق تجاری (business logic) را پیاده سازی می کند. هر درخواست دسترسی میکروسرویس باید احراز هویت و تأیید شود، که چندین چالش ایجاد می کند:
- وابستگی مرکزی - منطق احراز هویت و مجوز باید توسط هر میکروسرویس جداگانه انجام شود. شما می توانید از یک کد در همه میکروسرویس ها استفاده کنید، ولی برای این کار لازم است همه میکروسرویس ها از یک زبان یا فریم ورک خاص پشتیبانی کنند.
- نقض اصل مسئولیت واحد (Single Responsibility) - میکروسرویس ها تنها یک وظیفه را انجام می دهند. اگر منطق احراز هویت و مجوز سراسری را به میکروسرویس ها اضافه کنید، از آن به بعد کار دیگری را انجام می دهند که باعث می شود اعتماد به آنها کم شود و مدیریت شان دشوارتر شود.
- پیچیدگی - احراز هویت و مجوز دسترسی در میکروسرویس ها می تواند منجر به سناریوهای بسیار پیچیده شود. در نظر بگیرید که ممکن است کاربران، میکروسرویس های دیگر و سیستم های بیرونی به هر میکروسرویسی دسترسی داشته باشند. این پیچیدگی می تواند اجرا و نگهداری را دشوار کند.
3 روش احراز هویت Microservices
می توانید از یکی از استراتژی های زیر برای پیاده سازی احراز هویت در یک برنامه میکروسرویس استفاده کنید.
کنترل مجوز در ورودی برنامه (Edge-Level Authorization)
در یک سناریوی ساده، بررسی مجوز دسترسی فقط در ورودی برنامه اتفاق می افتد، معمولاً این کار را با استفاده از یک API Gateway* انجام می دهند. می توانید از API Gateway استفاده کنید تا احراز هویت و بررسی مجوز برای همه میکروسرویس هایی که در ادامه ی اجرای درخواست مورد استفاده قرار می گیرند را در یک نقطه متمرکز کنید. API Gateway احراز هویت و کنترل دسترسی را برای هر میکروسرویس اعمال میکند.
API Gateway یک ابزار مدیریت API است که بین کلاینت و مجموعه ای از سرویس های Backend قرار می گیرد. API Gateway به عنوان یک پروکسی معکوس عمل می کند تا همه ی تماس های API ها را بپذیرد، خدمات مختلف مورد نیاز برای انجام آنها را جمع آوری کند و نتیجه مناسب را برگرداند.
این استراتژی دارای معایب زیر است:
- امنیت کمتر - اگر مهاجمی از API Gateway عبور کند، می تواند آزادانه به هر میکروسرویسی دسترسی داشته باشد. یک API Gateway به عنوان یک نقطه دسترسی واحد، اصل "دفاع در عمق (defense in depth)*" را نقض می کند.
- مدیریت دشوارتر - اگر برنامه ی شما نقشها و قوانین کنترل دسترسی پیچیده ای داشته باشد، قرار دادن تمام تصمیم های کنترلی برای مجوز در یک API Gateway میتواند غیرقابل مدیریت شود.
- دسترسی محدود برای تیمهای توسعه - معمولاً تیمهای زیرساخت، API Gateway را راهاندازی میکنند، بنابراین تیم توسعه نمیتواند مستقیماً مجوزها را تغییر دهد. این موضوع می تواند باعث کند شدن کارها شود و سربار زیادی روی ارتباط بین تیم ها ایجاد کند.
Defense in Depth: دفاع در عمق (DiD) به یک رویکرد امنیت اطلاعات اشاره دارد که در آن یک سری مکانیزمها و کنترلهای امنیتی به طور مدبرانه در سراسر یک شبکه کامپیوتری لایهبندی میشوند تا از محرمانه بودن، یکپارچگی و در دسترس بودن شبکه و دادههای درون آن محافظت کنند. با این رویکرد در صورتی که یکی از مکانیزم ها شکست بخورد در لایه ی بعدی مکانیزم بعدی جلوی خطر را خواهد گرفت. این رویکرد به طور قابل توجهی امنیت شبکه را در برابر بسیاری از حمله ها تقویت می کند.
کنترل مجوز در سطح سرویس (Service-Level Authorization)
این استراتژی احراز هویت و کنترل مجوز مستقیم را برای هر میکروسرویس امکان پذیر می کند. در این روش هر میکروسرویس کنترل بیشتری برای اعمال سیاست های کنترل دسترسی خود دارد. معماری مجوز در سطح سرویس شامل موارد زیر است:
- مدیریت قوانین دسترسی - به مدیران برنامه اجازه می دهد قوانین دسترسی را ایجاد، مدیریت و آزمایش کنند.
- قبول یا رد درخواست - بررسی می کند که کدام سیاست (Policy) کنترل دسترسی برای درخواست فعلی اعمال شود و ارزیابی می کند که آیا درخواست دسترسی را قبول یا رد کند.
- اجرای سیاست - تصمیمات دسترسی را ارائه می دهد و سیاست دسترسی را برای درخواست های خاص اعمال می کند.
- اطلاعات سیاست - به بخش های مختلف برنامه اجازه می دهد تا اطلاعات مربوط به سیاست های اعمال شده را بررسی کنند و در صورت نیاز درمورد اتخاذ سیاستی خاص تصمیم گیری کنند.
انتشار هویت موجودیت خارجی (External Entity Identity Propagation)
با استفاده از این استراتژی می توان اجازه ی دسترسی یا انجام کاری را به کاربر براساس اطلاعاتی مثل شناسه کاربر، نقشها یا گروههای کاربر، مکان کاربر، زمان یا سایر پارامترها داد یا نداد.
برای انجام احراز هویت، باید اطلاعاتی در مورد کاربر نهایی دریافت کنید و آن را به میکروسرویس های بعدی که در مسیر درخواست کاربر مورد استفاده قرار میگیرند هم بدهید. یک راه ساده برای برای انجام این کار این است که یک Access Token در ورودی برنامه به درخواست بدهیم و آن را به همراه درخواست به میکروسرویسهای بعدی ارسال کنیم. این استراتژی بیشترین کنترل را بر احراز هویت میکروسرویس فراهم می کند. با این حال، دو اشکال اساسی دارد:
محتوای توکن با همه میکروسرویس ها به اشتراک گذاشته می شود و در نتیجه هکرها می توانند آن را جعل کنند. برای برطرف کردن این نگرانی، یک راه حل ممکن این است که توکن ها توسط یک منبع قابل اعتماد، اعتبارسنجی بشود.
برای پشتیبانی از چندین تکنیک احراز هویت، مانند JWT، OIDC یا کوکی ها، به میکروسرویس های داخلی نیاز دارد.
تکنیک های احراز هویت Microservices
هنگامی که در مورد رویکرد خود برای احراز هویت میکروسرویس تصمیم گرفتید، در اینجا چند روش فنی وجود دارد که می توانید برای پیاده سازی احراز هویت در میکروسرویس ها استفاده کنید.
Single Sign-On (SSO)
یکی از روش های پرطرفدار در احراز هویت استفاده از SSO است. با استفاده از این روش کاربر یکبار احراز هویت شده و می تواند از بخش های مختلفی از برنامه یا برنامه های مختلفی استفاده کند. برای مثال وقتی شما با اکانت گوگل خودتان لاگین کنید، می توانید به Google Calendar ، Gmail ،Google Docs و بقیه ی برنامه های گوگل دسترسی داشته باشید.
در این روش وقتی شما درخواست مجوز دسترسی به یک سرویس را می دهید، آن سرویس شما را به یک Identity Provider مرکزی معرفی می کند و آنجا با روش های مختلفی اعم از نام کاربری و رمز عبور یا روش های دیگر شما را احراز هویت می کند و در نتیجه وقتی مطمئن شد شما همان کسی هستید که ادعا می کنید، شما را به سرویسی که درخواست داده اید منتقل میکند.
این سرویس Identity Provider می تواند یک سرویس خارجی یا یکی از سرویس های داخلی برنامه ی شما باشد. برای مثال گوگل سرویس OpenID Connect را ارائه کرده است. OpenID Connect استانداری است که بر اساس یک پیاده سازی خاص از OAuth 2 پیاده سازی شده است. ولی برای خیلی از شرکت ها و سازمان ها مهم است که این سرویس داخل برنامه ی خودشان باشد. این سرویس می تواند مواردی مثل Lightweight Directory Access Protocol (LDAP) یا Active Directory باشد.
SSO ها مشخص می کنند که کاربری که درخواست استفاده از سیستم را داده است چه کسی است ولی اینکه او در سرویس ما چه کارهایی را میتواند یا نمی تواند انجام دهد، دیگر به SSO مربوط نمی شود و باید توسط خود سرویس مورد ارزیابی قرار بگیرد.
در زمینه معماری میکروسرویس، SSO می تواند دو معنی داشته باشد:
احراز هویت کاربران نهایی؛ قطعا کاربر نهایی ترجیح می دهد یک بار احرازهویت شود و بتواند با همان مجوزی که گرفته است از تمام سرویس های مورد نیاز خود استفاده کند. برای این کار میتوانید از راهحلهای مدیریت هویت و دسترسی (IAM: identity and access management) برای راهاندازی دیتابیس کاربر و تعریف مجوزها برای میکروسرویسهای مورد نیاز خود استفاده کنید.
میکروسرویس ها می توانند کاربران را برای احراز هویت به سیستم IAM هدایت کنند، یک کلید رمزگذاری شده SSO دریافت کنند و سپس از آن برای اجازه ی ورود کاربران به میکروسرویس های مختلف استفاده کنند. میکروسرویس ها همچنین می توانند از سیستم IAM برای مجوز استفاده کنند و رمز SSO می تواند مشخص کند که کاربر به کدام منابع اجازه دسترسی دارد.
احراز هویت میکروسرویسها؛ همچنین می توان از SSO برای احرازهویت و کنترل دسترسی برای میکروسرویس های دیگر برنامه مان یا سرویس های خارجی که می خواهند با برنامه ی ما ارتباط برقرار کنند هم استفاده کنیم. در این حالت شما قرار است به جای اعطای مجوز به یک کاربر انسانی، مجوز را به یک سرویس دیگر بدهید. برای این کارهم یکی از بهترین راه حل ها همان سرویس IAM است که سرویس بیرونی یا میکروسرویس داخلی را به آن هدایت می کنیم و می تواند یک کلید SSO دریافت کند در تمامی تماس های بعدی هم از همان استفاده کند.
JSON Web Tokens
JSON Web Token (JWT) مکانیزمی را فراهم می کند تا با استفاده از آن به توانیم به صورت رمزگذاری شده و ایمن مجموعه ای از اطلاعات و ویژگی های کاربر را با بخش های مختلف برنامه (برای مثال میکروسرویس ها) به اشتراک بگذاریم. JWT ها همچنین می توانند ارتباط بین میکروسرویس های داخلی یا سرویس های بیرونی با میکروسرویس های برنامه ما را را ایمن کنند و داده های کاربر نهایی را بین میکروسرویس ها رد و بدل کنند.
برای مثال، میتوانید از یک توکن JWT برای ارسال اطلاعات میکروسرویس، کاربر نهایی یا سیستم خارجی که درخواست را ارسال کرده است استفاده کنید. همچنین می توانید ویژگی های مجوز و احراز هویت را در یک توکن JWT ذخیره کنید و آنها را بین چندین میکروسرویس به اشتراک بگذارید.
OAuth API Authentication
OAuth 2.0 یک پروتکل استاندارد برای مجوز دادن به کاربران در سیستم های توزیع شده را ارائه می دهد. در میکروسرویس ها، می توانیم از OAuth 2.0 برای ارتباط امن سرویس ها با یکدیگر و بین کاربران و میکروسرویس ها استفاده کنیم. استفاده از چارچوب OAuth باعث می شود توسعه دهندگان نیاز نباشد مکانیسم احراز هویت را خودشان در هر میکروسرویس ایجاد کنند.
درواقع OpenID Connect (OIDC)، چهارچوب OAuth را برای افزودن هویتهای متحد و یکپارچه گسترش داده است و امکان تنظیم مجوز داده شده را فراهم میکند. این دو لایه با هم به توسعه دهندگان اجازه می دهد تا سیستم هایی بسازند که با چندین ارائه دهنده هویت تعامل دارند.
پیشنهاد می کنم بخش های 1، 2، 3 و 5 از دوره ی آموزش OAuth و Laravel Passport را برای درک بهتر OAuth مطالعه کنید.
بهترین روش Authentication و Authorization در Microservice
حالا که با همه ی این مفاهیم و روش ها و تکنیک ها آشنا شدیم، بیایید در انتها هم یک روش رایج برای احراز هویت و اعطای دسترسی های لازم به کاربر و همچنین انتقال اطلاعات کاربر بین میکروسرویس های مختلف را با هم بررسی کنیم.
در این معماری، کاربر ما وارد برنامه شده و یک بار شناسه (Token) ای را برای او تولید می کنیم که بیان کننده ی هویت اوست و در سیستم خودش ذخیره می شود. این شناسه بهتر است OAuth Token باشد. حالا هر درخواستی که کاربر به برنامه ی ما بدهد از SSO Gateway عبور خواهد کرد و به ازای هر درخواست یک JWT برای او تولید می کنیم. این JWT به تمام میکروسرویس هایی که در مسیر پاسخ دهی به درخواست اجرا می شوند ارسال خواهد شد. حالا میکروسرویس های با باز کردن JWT و خواندن اطلاعات داخل آن متوجه می شوند این درخواست از طرف کدام کاربر آمده است و چه مجوزهایی را باید به او داد.
نوع دیگری از پیاده سازی این معماری به گونه ای است که بعد از ورود کاربر در سیستم یک JWT برای او ساخته می شود و در سیستم کاربر ذخیره می شود. البته باید دقت شود که این JWT برای مدت زیادی روی سیستم کاربر ذخیره نشود. چون یکی از اهداف ما این است که با کوتاه کردن طول عمر این JWT ها، احتمال سوءاستفاده از آنها را کم کنیم.
ولی بهترین روش استفاده از JWT تولید آن در SSO Gateway به ازای هر درخواست است. با این روش امنیت بالاتری را تجربه خواهیم کرد.
منابع:
- بخش 11 کتاب Building Microservices, 2nd Edition-Sam Newman-O'Reilly
- مقاله https://frontegg.com/blog/authentication-in-microservices
- چندین مقاله از سایت https://www.redhat.com