Multi-Tenant SaaS: এক product-এ tenant data isolation
Multi-Tenant SaaS and Data Isolation
এই পাঠের সূচিপত্র
এই পাঠে যা শিখবেন
- Tenant boundary ও authorization আলাদা করুন
- Shared schema এবং database-per-tenant তুলনা করুন
- প্রতিটি query-তে isolation বজায় রাখুন
সমস্যা দিয়ে শুরু
এক SaaS invoice application-এ দুই প্রতিষ্ঠান account খুলেছে। Developer invoice ID দিয়ে query করায় অন্য প্রতিষ্ঠানের URL guess করে invoice দেখা যাচ্ছে। Login আছে, কিন্তু data isolation নেই। Tenant identity client input বিশ্বাস করে নিলে সমস্যাটি আরও বাড়ে।
সহজ করে বুঝি
Multi-tenancy এক product-এর infrastructure একাধিক প্রতিষ্ঠানকে দেয়, প্রত্যেকের data ও policy আলাদা রাখে। Shared schema-এ tenant_id filtering, schema-per-tenant অথবা database-per-tenant ব্যবহার করা যায়। Tenant resolve করা authentication-এর পরে membership ও authorization দিয়ে যাচাই করতে হয়; subdomain একা permission নয়।
পরিচিত একটি উপমা
এক ভবনে অনেক অফিসের আলাদা কক্ষ। Reception-এ পরিচয় জানলেই সব অফিসের আলমারি খোলার অধিকার মেলে না। Shared building খরচ কমায়, কিন্তু key, visitor policy ও resource limit আলাদা রাখতে হয়।
নকশাটি দেখুন
Diagram লোড হচ্ছে…
Diagram-এর text flow দেখুন
flowchart LR U[Authenticated User] --> M[Verify Tenant Membership] M --> A[Laravel Policy] A --> Q[Tenant Scoped Query] Q --> D[(Invoices with tenant_id)] X[Other Tenant] -.->|Denied| A
User-এর session থেকে identity আসে। Selected tenant-এ membership যাচাই হয়। Policy invoice action অনুমোদন করে। Query একই tenant_id দিয়ে record আনে। অন্য tenant-এর numeric ID জানা থাকলেও query সেটি ফেরায় না; response policy তথ্য leakage কমায়।
PHP ও Laravel-এ প্রয়োগ
Laravel route/controller fragment-এ $tenant middleware দ্বারা resolved ও membership-verified। Invoice model tenant_id column এবং composite tenant_id,id index আছে। Global scope থাকলেও explicit sensitive query ও Policy defense-in-depth দেয়; unscoped admin path আলাদা audit চাই।
use App\Models\Invoice;
use Illuminate\Support\Facades\Gate;
$invoice = Invoice::query()
->where('tenant_id', $tenant->id)
->whereKey($invoiceId)
->firstOrFail();
Gate::authorize('view', $invoice);
return response()->json([
'id' => $invoice->id,
'number' => $invoice->number,
'total_minor' => $invoice->total_minor,
]);
// Do not take tenant_id directly from the request body.
// Policy verifies role and membership for this exact tenant.এটি PHP 8.3+ ও Laravel 12-এর শিক্ষামূলক fragment; সম্পূর্ণ application নয়। সংশ্লিষ্ট route-এ authentication ও resource authorization প্রয়োগ করতে হবে। নিচের অনুশীলনে failure ইচ্ছা করে তৈরি করুন; শুধু সফল response দেখে correctness ধরে নেবেন না।
সুবিধা, সীমাবদ্ধতা ও trade-off
Shared schema কম খরচ ও সহজ upgrades দেয়, কিন্তু query mistake-এর blast radius বড়। Separate database isolation ও tenant-specific restore সহজ করতে পারে, তবে connection management, migrations ও operations বাড়ে। Regulatory ও scale প্রয়োজন অনুযায়ী tiered model সম্ভব।
সাধারণ ভুল
- Authenticated মানেই সব tenant data authorized ধরা।
- Cache key-তে tenant বাদ দিয়ে database filter ঠিক আছে ভাবা।
- Admin background job-এ global tenant context ভুলে যাওয়া।
আরও একটু গভীরে
Row-level security database স্তরে অতিরিক্ত সুরক্ষা দিতে পারে, কিন্তু connection pool-এ tenant context reset দরকার। Composite unique constraint-এ tenant অন্তর্ভুক্ত করলে দুই প্রতিষ্ঠানের একই invoice number বৈধ থাকে। Cross-tenant reporting আলাদা privileged pipeline হওয়া ভালো।
দুটি tenant ও দুই user seed করুন। User A-কে tenant B invoice ID দিন: data ফেরত আসবে না। একই invoice number দুই tenant-এ চলবে, একই tenant-এ duplicate reject হবে। API, export, search এবং queued notification-এও একই isolation test চালান।
মনে রাখুন
- Tenant identity trusted context থেকে নিন।
- Authentication isolation নয়।
- সব storage path tenant-aware করুন।
নিজে চেষ্টা করুন
Shared-schema invoice app-এর constraints লিখুন। User দুই tenant-এর member হলে switching ও permission কীভাবে কাজ করবে design করুন।
নিজের বোঝা যাচাই করুন
1. Subdomain permission?
না। এটি tenant lookup hint হতে পারে; authenticated membership আলাদা যাচাই করতে হবে।
2. Global scope যথেষ্ট?
সাহায্য করে, কিন্তু bypass, raw query, cache ও jobs আলাদা review চাই।
3. Database-per-tenant সবসময়?
Isolation বেশি হলেও operational cost বাড়ে; requirement অনুযায়ী নির্বাচন করুন।
4. Unique invoice number?
Shared schema-এ tenant_id এবং number-এর composite uniqueness tenant-এর ভিতরে invariant রাখে।
5. Admin কীভাবে?
Explicit privileged path, narrow authorization ও audit রাখুন; accidental scope disable বিপজ্জনক।
আরও পড়ুন
এই পাঠের কুইজ
এই পাঠ থেকে ২টি প্রশ্ন। উত্তর দিয়ে ব্যাখ্যা দেখুন; অধ্যায়ের কুইজ আলাদাভাবে দিতে হবে।
এই পাঠের ২টি প্রশ্নের উত্তর দিন। পাস করতে দুটিই সঠিক হতে হবে।
জমা দেওয়ার পর সঠিক উত্তর ও ব্যাখ্যা দেখবেন। ফলাফল এই ব্রাউজারে সংরক্ষিত থাকবে। অনুশীলনের ফল অধ্যায় সম্পন্নের হিসাবে যোগ হয় না।
অগ্রগতি এই ব্রাউজারে সংরক্ষিত থাকে। শুধু পাঠ খুললে সম্পন্ন হয় না।