پرش به محتوای اصلی

هویت بدون وظیفه: چرا اعتبارنامه‌های هر عامل همچنان بیش از حد مجاز می‌دهند

اعتبارنامه‌های محدود به وظیفه طول عمر توکن را اصلاح می‌کنند، نه دامنه توکن را. دامنه در پایین‌دست نحوه تجزیه کار توسط برنامه‌ریز قرار دارد، که تجزیه را به یک کنترل امنیتی تبدیل می‌کند.

نمای نزدیک از یک رک سرور با کابل‌های پچ و LEDهای وضعیت، که نمایانگر کنترل دسترسی لایه‌ای در یک سیستم عامل است

بهبود، و جایی که متوقف می‌شود

به یک عامل هوش مصنوعی اعتبارنامه‌ای بدهید که با پایان وظیفه‌اش منقضی شود، و یکی از قدیمی‌ترین مشکلات در مدیریت دسترسی را حذف کرده‌اید: توکن حامل طولانی‌مدت که در یک فایل پیکربندی نشسته، ماه‌ها معتبر است، و برای مهاجم مدت‌ها پس از ناپدید شدن فرآیند عامل مفید است. چارچوب‌بندی به سبک 1Password و پیشنهادهای گسترده‌تر IAM برای عامل‌ها هر دو در این جهت فشار می‌آورند. اعتبارنامه‌ها برای هر وظیفه صادر می‌شوند، به یک نشست متصل می‌شوند، و با بسته شدن وظیفه باطل می‌شوند. پنجره‌ای که در آن یک توکن لو رفته مفید است از ماه‌ها به دقیقه کاهش می‌یابد. این یک دستاورد واقعی است.

همچنین دستاوردی است که متعامد با سوالی است که بیشتر بازبینی‌های امنیتی واقعاً به آن اهمیت می‌دهند: این اعتبارنامه در حالی که زنده است به چه چیزی می‌تواند دسترسی پیدا کند؟ یک توکن محدود به وظیفه با طول عمر پنج دقیقه که s3:GetObject روی * دارد، هنوز یک پنجره پنج دقیقه‌ای به کل سبد است. طول عمر باریک است. دامنه نیست. و دامنه چیزی نیست که سیستم صادرکننده اعتبارنامه خودش درباره آن تصمیم بگیرد — از تصمیمی که پیش‌تر، توسط یک مؤلفه متفاوت، با واژگانی متفاوت گرفته شده، ارث می‌برد.

دامنه خروجی تجزیه است

دو دستور را در نظر بگیرید که یک هماهنگ‌کننده ممکن است به یک زیرعامل بدهد:

subtask: reconcile the account
subtask: read invoice 4417

اولی یک درخواست مشروع و رایج است. همچنین، از دیدگاه کنترل دسترسی، درخواستی برای دسترسی خواندن به دفتر کل صورتحساب، ارائه‌دهنده پرداخت، سابقه مشتری، و هر منطق تطبیقی که لمس می‌کند است. دومی درخواستی برای یک سند است. هر دو «وظیفه» هستند. هیچ‌کدام به‌عنوان توصیف قصد درست‌تر از دیگری نیست. اما آن‌ها اعتبارنامه‌هایی با گستردگی به‌شدت متفاوت تولید می‌کنند، و سیستم صادرکننده — همان که توکن کوتاه‌مدت را ضرب می‌زند — هیچ راهی ندارد که بداند اولی یک تجزیه تنبل بوده و دومی یک تجزیه دقیق. یک شناسه وظیفه و یک دامنه درخواستی می‌بیند، و اگر دامنه با وظیفه مطابقت داشته باشد، اعطا می‌کند.

High voltage power line and insulators against a clear blue sky

به عبارت دیگر، برنامه‌ریز کنترل دسترسی انجام می‌دهد، چه کسی آن را این‌طور در نظر بگیرد چه نگیرد. وقتی «رسیدگی به شکایت مشتری» را به «خواندن تیکت، خواندن سفارش، صدور بازپرداخت» تقسیم می‌کند، همین حالا تصمیم گرفته که ازدحام به چه اعتبارنامه‌هایی نیاز خواهد داشت. وقتی همان درخواست را به «خواندن تیکت، خواندن سفارش، خواندن تاریخچه پرداخت، خواندن سابقه حمل‌ونقل، خواندن یادداشت‌های حساب» تقسیم می‌کند، چیز گسترده‌تری تصمیم گرفته است. لایه IAM در پایین‌دست یک تشریفات است؛ تصمیم ماهوی در بالادست، در مؤلفه‌ای که بیشتر تیم‌ها هنوز آن را هماهنگ‌سازی می‌نامند، رخ داده است.

این بخشی است که مدل اعتبارنامه هر وظیفه به آن نمی‌پردازد. مشکل طول عمر را اصلاح می‌کند چون طول عمر خاصیتی است که صادرکننده کنترل می‌کند. مشکل دامنه را اصلاح نمی‌کند چون دامنه خاصیتی از تجزیه است، و تجزیه توسط یک مدل زبانی که درباره یک درخواست کاربر استدلال می‌کند تولید می‌شود، نه توسط یک موتور سیاست که درباره کمترین امتیاز استدلال می‌کند.

قابلیت حسابرسی چه چیزی را الزامی می‌کند

اگر دامنه در پایین‌دست تجزیه قرار دارد، پس حسابرسی دسترسی یعنی حسابرسی تجزیه. یک گزارش صدور توکن که ثبت می‌کند agent-7 requested scope X, granted scope X هیچ چیزی درباره اینکه آیا X توجیه‌شده بود به بازبین نمی‌گوید. گام صوری را ثبت می‌کند و گام ماهوی را حذف می‌کند.

قاعده طراحی که از این نتیجه می‌شود پیچیده نیست، هرچند از آنچه به نظر می‌رسد مداخله‌گرانه‌تر است. هر درخواست اعتبارنامه باید دو شناسه حمل کند: زیروظیفه‌ای که به آن تعلق دارد، و گره برنامه والد که آن زیروظیفه را تولید کرده است. اعطا باید رد شود اگر دامنه درخواستی از آنچه زیروظیفه اعلام‌شده به‌طور محتمل می‌تواند نیاز داشته باشد فراتر رود — و «محتمل» در اینجا به معنای سیاستی است که تجزیه ملزم به برآورده کردن آن است، نه قضاوتی که صادرکننده در لحظه انجام می‌دهد. اعطا، وقتی صادر می‌شود، باید در کنار تجزیه‌ای که آن را برانگیخته ثبت شود، تا بازبین بتواند استدلال را بازسازی کند: این توکن وجود دارد چون گره برنامه P زیروظیفه S را ایجاد کرده، و S به فاکتور 4417 محدود شده، و توکن می‌تواند فاکتور 4417 را بخواند.

{
  "plan_node": "P-118",
  "subtask": "S-118-3",
  "intent": "read invoice 4417",
  "requested_scope": ["billing:invoices:read:4417"],
  "granted_scope": ["billing:invoices:read:4417"],
  "parent_scope_ceiling": ["billing:invoices:read:*"]
}

فیلد parent_scope_ceiling مهم‌ترین است. این حداکثر دامنه‌ای است که گره برنامه مجاز است به فرزندانش توزیع کند، و زمانی تنظیم می‌شود که برنامه ایجاد می‌شود، نه زمانی که اعتبارنامه درخواست می‌شود. این به بازبین دو چیز برای بررسی می‌دهد: اینکه آیا زیروظیفه در سقف والدش باقی مانده، و اینکه آیا سقف والد خودش توسط درخواست اصلی توجیه شده بود. بررسی دوم همان است که برنامه‌ریزی را که بی‌صدا تصمیم گرفته «تطبیق حساب» یعنی![Close-up of rClose-up of rusty screws on a corroded metal surface showing decay

حالت شکستی که باید مراقب آن بود یک عامل مخرب نیست. یک عامل کمک‌کننده است. یک عامل به خطای مجوز برمی‌خورد — سعی کرد فاکتور 4417 را بخواند و دامنه billing:invoices:read:4417 بود اما فاکتور در سیستم دیگری زندگی می‌کند، یا تطبیق به سابقه پرداخت هم نیاز دارد — و دوباره تلاش می‌کند. اگر منطق تلاش مجدد اجازه داشته باشد دامنه را گسترده کند، عامل دامنه را گسترده خواهد کرد. این یک باگ در عامل نیست؛ این عامل است که کاری را می‌کند که عامل‌ها می‌کنند، یعنی دنبال کردن هدف. باگ در سیاست تلاش مجددی است که خطای مجوز را به‌عنوان درخواستی برای مجوز بیشتر در نظر می‌گیرد نه به‌عنوان سیگنالی که تجزیه اشتباه بوده است.

خزش دامنه در تلاش مجدد باید یک سیگنال حادثه درجه‌یک باشد، نه یک خط گزارش. به‌طور مشخص: تلاش مجددی که دامنه‌ای به‌طور اکید بزرگ‌تر از دامنه زیروظیفه اصلی درخواست می‌کند باید بسته شکست بخورد، رویدادی منتشر کند، و نیازمند تجزیه مجدد برنامه توسط مؤلفه‌ای غیر از عاملی باشد که به دیوار خورده است. تجزیه مجدد راه‌حل است. اعطای گسترده‌شده شکست است. اگر سیستم نتواند تفاوت بین این دو را تشخیص دهد، در نهایت دامنه گسترده‌شده را اعطا خواهد کرد چون این مسیر کمترین مقاومت برای یک عامل تحت ضرب‌الاجل است.

معامله صادقانه

هیچ‌کدام از این‌ها رایگان نیست. الزام هر درخواست اعتبارنامه به حمل یک شناسه زیروظیفه و یک سقف گره برنامه یعنی برنامه‌ریز باید تجزیه‌های ساختاریافته منتشر کند، نه توصیف‌های وظیفه با متن آزاد. یعنی لایه هماهنگ‌سازی باید یک گراف برنامه با حاشیه‌نویسی‌های دامنه نگه دارد، و آن گراف باید نسخه‌بندی و قابل حسابرسی باشد. یعنی برخی وظایف مشروع شکست خواهند خورد چون تجزیه بیش از حد درشت بوده و عامل نمی‌تواند در دامنه خودش خودتصحیح کند — و پاسخ درست به آن شکست یک برنامه‌ریزی مجدد کندتر و قابل‌مشاهده برای انسان است، نه یک توکن گسترده‌تر.

این معامله است: دامنه باریک‌تر به قیمت اصطکاک بیشتر وقتی تجزیه اشتباه است. جایگزین — اعتبارنامه‌های هر وظیفه با دامنه سطح وظیفه، که در آن «وظیفه» هر چیزی است که برنامه‌ریز اتفاقاً نوشته — ظاهر کمترین امتیاز و ماهیت هر چیزی که برنامه‌ریز حالش را داشته می‌دهد. اعتبارنامه‌های محدود به وظیفه یک بهبود هستند. آن‌ها راه‌حل مشکل دامنه نیستند، چون مشکل دامنه یک مشکل اعتبارنامه نیست. یک مشکل تجزیه است، و یک لایه بالاتر زندگی می‌کند.

چه چیزی بسازیم

  • برنامه‌ریز را به‌عنوان یک مؤلفه مرتبط با امنیت در نظر بگیرید. خروجی‌هایش تصمیمات کنترل دسترسی هستند.
  • شناسه‌های زیروظیفه و برنامه والد را روی هر درخواست اعتبارنامه الزامی کنید.
  • یک سقف دامنه والد را که در زمان ایجاد برنامه تنظیم شده اجرا کنید، نه در زمان صدور اعتبارنامه.
  • تجزیه را در کنار اعطا ثبت کنید، تا توجیه قابل بازسازی باشد.
  • در تلاش مجدد با دامنه گسترده‌تر بسته شکست بخورید، و شکست را به تجزیه مجدد هدایت کنید نه به یک اعطای گسترده‌تر.

اعتبارنامه تنها به اندازه وظیفه‌ای که آن را تولید کرده باریک است. اگر وظیفه در دانه‌بندی اشتباه بیان شود، اعتبارنامه هم همین‌طور خواهد بود.

اشتراک‌گذاریXLinkedInپیوند یکتا6 دقیقه مطالعه

خواندن مرتبط

پرسش‌هایی که این پاسخ می‌دهد

Does task-scoped credential issuance solve least privilege for agents?

It solves the lifetime half. A short-lived token limits how long a leak is useful, but the token can still reach whatever the task was scoped to, and that scope is set by the planner's decomposition, not by the issuer.

Why is the planner a security-relevant component?

Because the planner decides how work is split, and the split determines what credentials each subagent needs. A coarse decomposition produces coarse grants regardless of how short the token lifetime is.

What should a credential request carry?

The originating subtask identifier and its parent plan node, plus a scope ceiling set when the plan was created. Grants that exceed the declared subtask should be rejected, and the decomposition should be logged with the grant.

How should retry-with-broader-scope be handled?

As a first-class incident signal. A retry requesting a scope larger than the original subtask should fail closed and route to re-decomposition by a component other than the agent that hit the permission error.