رمزها جایشون تو فایل کانفیگ نیست
خلاصهٔ کاملتر
حرف اصلی این مقاله یه جملهست: برنامه نباید برای گرفتن رمز، توکن یا کلید API به فایل پیکربندی وابسته باشه. نویسنده تفکیک رو اینطوری توضیح میده که کانفیگ رفتار رو توصیف میکنه و جاش تو گیت، کد ریویو، گزارش باگ و ماشین توسعهدهندهست؛ ولی راز اختیار میده و به دسترسی محدود و چرخش مستقل نیاز داره. وقتی این دوتا تو یک فایل میشینن، دو چرخهٔ عمر و دو مخاطب متفاوت به هم گره میخورن.
معیار عملیاش هم سادهست: اگه برای عوض کردن یه رمز مجبور باشی کل پیکربندی برنامه رو دوباره تولید کنی، یعنی رابط، این دوتا رو زیادی به هم چسبونده.
برای اینکه نشون بده مسئله واقعیه، تیم تمام ۴۴۵ ماژول NixOS که با راز واقعی سروکار دارن رو روی یه کامیت مشخص ممیزی کرده و هرکدوم رو بر اساس مقصد نهایی مقدارِ راز دستهبندی کرده: ۳۶٪ بهصورت متغیر محیطی تحویل میدن، ۲۵٪ موقع اجرا داخل یه فایل کانفیگ ادغام میکنن، ۱۳٪ فایل اختصاصی دارن، ۱۲٪ از credentials سیستمدی استفاده میکنن و ۴٪ راز رو بهعنوان آرگومان خط فرمان پاس میدن.
عدد جالب همون ۱۱۰ ماژول (۲۵٪) ـه: اینها راز رو کاملاً امن به دست میآرن، اما چون تنها رابطی که برنامه قبول میکنه فایل کانفیگه، مجبورن با ابزارهایی مثل envsubst، replace-secret، jq، yq یا sed سر بوت یه فایل محدودشده سرهم کنن. نتیجه ممکنه امن باشه، ولی حالا هر ماژول یه تکه چسبِ حساسبهامنیتِ مخصوص همون اپلیکیشن رو نگهداری میکنه. به گفتهٔ نویسنده این مشکل مخصوص NixOS هم نیست و همون الگو تو اسکریپت entrypoint، تمپلیت Helm، init container یا مرحلهٔ جایگذاری تو CI تکرار میشه.
در کنارش ۴۲ ماژول میتونن راز رو داخل /nix/store که برای همه خوندنیه اینلاین کنن؛ اون یه مشکل امنیتی مستقیمه که تو ایشوی جداگانهای دنبال میشه. نکتهٔ اصلی اما همون ۱۱۰ موردیه که حتی وقتی نشتی رخ نمیده، نبودِ تفکیک باز هم کار اضافه میسازه.
پیشنهاد نویسنده اینه که برنامهها یه کانال زماناجرای اختصاصی برای راز بپذیرن: تنظیمی مثل password_file یا token_file، credential سیستمدی، یه متغیر محیطی با دامنهٔ محدود، یا یه ارائهدهندهٔ بیرونی راز. خودش هم صادقانه میگه این مکانیزمها همارز نیستن — متغیر محیطی ارث میرسه، آرگومان تو لیست پروسهها دیده میشه و فایل هم باید دسترسی درست داشته باشه — ولی چیزی که تفکیک تضمین میکنه اینه که دیگه لازم نباشه یه نسخهٔ دوم و رازدارِ کانفیگ ساخته بشه.
نویسنده یه اشتباه خودش رو هم مثال میزنه: Cachix سالها توکن احراز هویت و کلیدهای امضا رو کنار اسم کشها تو یک فایل نگه میداشت، پس کل فایل باید مثل راز باهاش رفتار میشد و اشتراکگذاری پیکربندی بدون لو دادن اعتبارنامهها ممکن نبود. حالا devenv نسخهٔ ۲.۲ توکن رو از طریق SecretSpec جدا میکنه و یه PR باز هم داره همین مرز رو به خود کلاینت Cachix میآره.
خود SecretSpec دقیقاً روی همین ایده بنا شده: فایل secretspec.toml فقط اعلام میکنه برنامه به چه رازهایی نیاز داره، بدون اینکه مقداری رو ذخیره کنه؛ بعد ارائهدهندهها تصمیم میگیرن مقدار کجا زندگی کنه — کیرینگ سیستم روی لپتاپ، متغیر محیطی تو CI، و 1Password یا Vault تو پروداکشن — بدون اینکه اعلام تغییر کنه. SDKهاش هم برای Rust، Python، Go، Ruby، Node.js/TypeScript، Haskell، PHP و C# موجوده و همه از یه resolver مشترک استفاده میکنن.
نکات کلیدی:
- کانفیگ رفتار رو توصیف میکنه و اشتراکیـه؛ راز اختیار میده و باید مستقل بچرخه
- اگه چرخش یه رمز نیازمند تولید دوبارهٔ کل کانفیگ باشه، رابط اشتباه طراحی شده
- از ۴۴۵ ماژول NixOS، ۱۱۰ تا راز امنگرفتهشده رو موقع اجرا با ابزارهایی مثل envsubst و jq داخل کانفیگ ادغام میکنن
- ۴۲ ماژول هم میتونن راز رو داخل /nix/store که همهخواندنیه اینلاین کنن
- راهحل: کانال جدا برای راز — فایل توکن، credential سیستمدی، متغیر محیطی محدود یا ارائهدهندهٔ بیرونی
- SecretSpec نیاز رو اعلام میکنه و محل نگهداری مقدار رو به محیط میسپاره؛ SDK برای هشت زبان داره




