کنترلهای بخش ۱۴ از 21-compliance.md که حسابرس با نام درخواست میکند. این صفحه روند کار و رکوردهایی است که شواهد را میسازند.
کلیدها
هر اعتبارنامهٔ ذخیرهشده با کلید رمزگذاری دادهٔ تازهای (DEK) مهر و موم میشود. کلید اصلی (KEK) روی DEK پوشش میگذارد و ارجاع کلید اصلی کنارش ذخیره میشود (key_ref یا ارجاع درون مقدار بستهبندیشده). چرخاندن کلید اصلی پوشش DEKها را عوض میکند؛ اعتبارنامه را رمزگشایی یا دوباره رمزگذاری نمیکند.
| تنظیم | معنا |
|---|---|
QUIRE_MASTER_KEY |
کلید اصلی کنونی: ۳۲ بایت، base64. هر راز تازه با آن پوشانده میشود |
QUIRE_MASTER_KEY_VERSION |
برچسب نسخهٔ آن؛ اگر تنظیم نشود v1. هر بار تغییر کلید آن را بالا ببرید |
QUIRE_MASTER_KEY_RETIRED |
کلیدهای پیشین که شاید رازها هنوز زیر آنها باشند، بهشکل v1=<base64>,v0=<base64>. برای خواندن است، نه نوشتن |
توی web tier، worker و فرمان bun run kek:rotate هر سه تنظیم یکسان را میخوانند. مقدارهایشان باید یکسان باشد وگرنه یکی نمیتواند چیزی را که دیگری مهر و موم کرده باز کند.
اگر QUIRE_MASTER_KEY نباشد، هر زیرسامانه کلیدی را نگه میدارد که از QUIRE_SECRET_KEY بهدست میآورد. این روش کار میکند، صفحهٔ سلامت سامانه وضعیتش را تنزلیافته نشان میدهد و پس از تنظیم کلید اصلی هم خواندنی میماند؛ نخستین چرخش همهچیز را از آن کلید بیرون میبرد. هرکس بتواند محیط فرایند را بخواند میتواند همهٔ اعتبارنامههای ذخیرهشده را رمزگشایی کند؛ پس نصب عملیاتی باید کلید اصلی داشته باشد، آن را در مخزن راز نگه دارد و در پشتیبان همان پایگاه داده نگذارد.
چرخاندن
سن کلید در کنسول پلتفرم، Security، Master key و با سنجهٔ quire.secrets.master_key.age (روز) نشان داده میشود. زمانبندی روزانهٔ platform.key_age (ساعت 03:41 UTC) وقتی سن کلید به ۳۶۵ روز برسد و سپس هر ۳۰ روز تا زمان چرخش، یادآوری را در زنجیرهٔ حسابرسی پلتفرم مینویسد. با دیدن یادآوری و هر زمان احتمال افشای کلید هست، آن را بچرخانید.
- کلید تازه بسازید:
openssl rand -base64 32. QUIRE_MASTER_KEYرا روی آن بگذارید وQUIRE_MASTER_KEY_VERSIONرا به برچسب بعدی (v2) ببرید. کلید قبلی را بهQUIRE_MASTER_KEY_RETIREDو با قالبv1=<old base64>منتقل کنید. از هر دو کلید نسخهای بیرون از این میزبان نگه دارید.- web tier و worker را با تنظیمهای تازه منتشر کنید. از این پس رازهای تازه با
env:QUIRE_MASTER_KEY:v2پوشانده میشوند؛ رازهای قدیمی همچنان با کلید بازنشسته باز میشوند. - چرخش را همراه دلیلی که در زنجیرهٔ حسابرسی میماند درخواست کنید:
- در کنسول: Security، Master key، Rotate the master key؛ یا
- در shell با همان محیط:
bun run kek:rotate request --reason "Annual rotation, ticket SEC-114".
- worker در هر دقیقه بخشی را دوباره میپوشاند (
platform.key_rotationزمانبندی scheduler) و پس از راهاندازی دوباره ادامه میدهد. برای پایان یکباره اجرا کنید:bun run kek:rotate run. باbun run kek:rotate statusوضعیت را ببینید. - وقتی رکورد نشان داد چرخش تمام شده و unresolved و failed هر دو صفرند، کلید بازنشسته را از
QUIRE_MASTER_KEY_RETIREDبردارید و دوباره منتشر کنید. تا آن موقع نگهش دارید؛ مقداری که نتوانسته جابهجا کند هنوز زیر کلید کهنه پوشیده است.
این کار چه چیزهایی را میگردد
هر مخزنی که DEK پوشیدهشده نگه دارد: موردهای SEALED_STORES در apps/worker/src/key-rotation.ts. مخزنهای پایگاه دادهٔ کنترل در همان پایگاه پیمایش میشوند؛ مخزنهای سازمانی زیر امنیت سطح سطر، هر سازمان جداگانه و در پایگاه دادهای که سازمان در آن است بررسی میشوند. بنابراین tenantای که به پایگاه اختصاصی سنجاق شده، در همان پایگاه میچرخد. اگر شِما ستونی با کلید پوشیدهشده بیفزاید و فهرست نامش را نیاورد، یک آزمون شکست میخورد؛ آزمون دیگری هم وقتی بازبینی اعتبارنامه ستونی مهرومومشده را شناسایی کند که فهرست جا انداخته باشد شکست میخورد.
رکوردها
ops.key_rotation: یک ردیف برای هر چرخش با دلیل، درخواستدهنده، وضعیت و جمعها (دوبارهپوشاندهشده، از پیش بهروز، حلنشده، ناموفق).ops.key_rotation_progress: برای هر مخزن و دامنه، پس از پیمایش یک ردیف با ارجاع کلیدهایی که نتوانسته بخواند و شمار مقدارهای زیر هرکدام. چرخش ازسرگرفتهشده اینها را رد میکند.- زنجیرهٔ حسابرسی پلتفرم:
platform/key_rotation_request(همراه دلیل)، برای هر مخزن یکplatform/key_rotation_storeبا شمارها وplatform/key_rotation_completeیاplatform/key_rotation_fail؛ برای یادآوریplatform/key_age_reminder. - سنجهها:
quire.secrets.master_key.ageوquire.secrets.rewrap.outstanding(مقادیر چرخش قبلی که نتوانست جابهجا کند).
وقتی مقداری حلنشده میماند
مقدار حلنشده زیر ارجاع کلیدی پوشیده شده که این نصب در اختیار ندارد یا قالبی ندارد که ستونش وعده میدهد. رکورد پیشرفت ارجاع را نام میبرد (برای نمونه env:QUIRE_MASTER_KEY:v0 (unreadable)). آن کلید را دوباره به QUIRE_MASTER_KEY_RETIRED برگردانید و چرخش دیگری اجرا کنید؛ یا اگر کلید برای همیشه گم شده، از مدیر سازمان بخواهید اعتبارنامه را دوباره وارد کند تا با کلید کنونی مهر و موم شود. چرخش ناموفق خطایش را در رکورد نشان میدهد؛ علت را برطرف و دوباره درخواست کنید.
کلیدهای امضا
جدا از کلید اصلی، هر سازمان tokenهای OpenID Connect و پیامهای LTI را با کلید RSA خودش امضا میکند که در /.well-known/jwks.json منتشر میشود. برای این کار اپراتور دخالتی ندارد. زمانبندی ساعتی platform.signing_keys جانشین را هفت روز پیش از پایان عمر ۹۰روزهٔ کلید کنونی منتشر میکند؛ یک هفته بعد جانشین امضا را آغاز و کلید پیشین در حال بازنشستگی میشود؛ نود روز بعد کلید پیشین حذف و از مجموعهٔ کلیدها برداشته میشود. هر گام در زنجیرهٔ حسابرسی پلتفرم بهشکل platform/signing_key_advance ثبت میشود.
برای زودتر جایگزین کردن کلید سازمان، برای نمونه پس از افشا:
- در کنسول: Security، Master key، Publish a new signing key (به
platform/keys_manageنیاز دارد)؛ یا - در shell با محیط worker:
bun run kek:rotate signing-keys rotate --tenant <slug or id> --reason "Key exposed, INC-3310".bun run kek:rotate signing-keys statusکلیدهای هر سازمان را بر پایهٔ مرحله فهرست میکند.
کلید تازه همان لحظه منتشر میشود و پس از هفت روز، وقتی کنونی بازنشسته شد، امضا را آغاز میکند. این یک هفته عمدی است: طرفهای متکی به کلید مجموعهٔ کلیدها را cache میکنند و همپوشانی کوتاهتر، کار همهٔ ابزارها را یکباره خراب میکند. کلید در حال بازنشستگی نود روز دیگر در مجموعه میماند تا tokenهایی که پیشتر امضا کرده همچنان تأیید شوند. اگر افشا یعنی باید زودتر از این دیگر به آن اعتماد نشود، حذف ردیفش با دسترسی پایگاه دادهٔ خود اپراتور و زیر رکورد تغییر انجام میشود (دسترسی اضطراری فقط خواندنی است) و آنگاه تأیید tokenهای امضاشده با آن شکست میخورد. چرخش اجباری با دلیل در زنجیرهٔ حسابرسی platform/signing_key_rotate است. برای پوشاندن کلید تازه، worker باید همان تنظیمهای QUIRE_MASTER_KEY مربوط به web tier را داشته باشد؛ چرخش کلید اصلی با bun run kek:rotate کلیدهای امضا را هم با بقیه بازپوشانی میکند (oauth_signing_key در SEALED_STORES است).
دسترسی اضطراری به محیط عملیاتی
هیچکس دسترسی همیشگی به محیط عملیاتی ندارد. وقتی کاری نمیتواند منتظر بماند، مالک از کنسول پلتفرم، Security، Break-glass access مجوز اضطراری صادر میکند.
- مجوز دامنه دارد (یک سازمان یا فهرست پلتفرم)، دلیلی دستکم ۲۰ نویسهای که رخداد یا ticket را نام ببرد و بازهای از ۵ تا ۲۴۰ دقیقه. خودبهخود منقضی میشود و در هر statement با ساعت سنجیده میشود.
- میتوان آن را برای صادرکننده یا مالک دیگری صادر کرد (حالت دو نفره). فقط همان شخصی که مجوز به او داده شده میتواند استفادهاش کند. صدور به
platform/break_glass_issueو استفاده بهplatform/break_glass_useنیاز دارد؛ بهطور پیشفرض هر دو فقط برای مالکاند. - statementها از gateway عبور میکنند، نه ورود مستقیم به پایگاه داده: فقط خواندنی، یکییکی، محدود به سازمان یا فهرست کنترل، با مهلت پنج ثانیه و حداکثر ۵۰۰ ردیف. مقدار دودویی با اندازهاش نشان داده میشود.
- زنجیرهٔ حسابرسی پلتفرم صدور را همراه دلیل، لغو، هر statement را پیش از اجرا (
platform/break_glass_statement، موردهای ردشده با نتیجهٔdenied) و هر نتیجه را (platform/break_glass_result) ثبت میکند.ops.break_glass_statementشناسههای ورودی حسابرسی را نگه میدارد تا رکورد صدور به ورودیهای حسابرسی پیوند بخورد. - نوشتن ارائه نمیشود. تغییری که نمیتواند تا انتشار بعدی منتظر بماند با دسترسی پایگاه دادهٔ خود اپراتور، زیر رکورد تغییر جداگانه و بیرون از این محصول انجام میشود؛ رکورد باید به شناسهٔ رخدادی که اینجا استفاده شد ارجاع دهد.
چرا اعتبارنامهٔ پایگاه داده صادر نمیکنیم؟ ورود Postgres پس از پایان نشستِ درخواستکننده هم زنده میماند، امنیت سطح سطریای را که برنامه به آن تکیه دارد دور میزند و نمیتواند در زنجیرهٔ حسابرسی این محصول بنویسد؛ بنابراین statementهایش فقط تا جایی حسابرسی میشوند که کسی گزارش سرور را تحویل دهد. Gateway باعث میشود رد حسابرسی ویژگی خود دسترسی باشد، نه روالی پیرامون آن.
برای پاسخ به حسابرسی، مجوزهای بازه را در Break-glass access فهرست کنید، تاریخچهٔ مجوز را برای statementها و شناسههای ورودی حسابرسی باز کنید و آن ورودیها را در زنجیرهٔ حسابرسی پلتفرم بخوانید (bun run audit:verify --platform یکپارچگی زنجیره را ثابت میکند).