رمز دیتابیس، API token، کلید خصوصی و credential رجیستری فقط «متغیر تنظیمات» نیستند؛ افشای آنها میتواند دسترسی مستقیم بسازد. قرار دادن secret در Dockerfile، repository یا image و حذف آن در لایه بعدی مشکل را حل نمیکند. مدیریت درست یعنی secret از زمان ایجاد تا تزریق، مصرف، چرخش و ابطال، مالک و مسیر قابلکنترل داشته باشد.
پاسخ سریع: secret را در source، Dockerfile، image و log نگه ندارید. برای build از BuildKit secret/SSH mount و برای runtime از secret manager یا فایل محدودشده استفاده کنید. هر سرویس فقط secret لازم را دریافت کند؛ برنامه فایل را بخواند، خطا را بدون چاپ مقدار گزارش کند و rotation را بدون وابستگی به image جدید پشتیبانی کند.
اول inventory بسازید
قبل از انتخاب ابزار، فهرست کنید چه secretهایی وجود دارد، مالک کسبوکاری و فنی آنها کیست، کدام سرویس مصرفشان میکند و در صورت افشا چه دامنهای آسیب میبیند. credential مشترک میان چند محیط یا چند برنامه، تشخیص و ابطال را دشوار میکند. برای development، staging و production مقدار و حساب جدا داشته باشید تا دسترسی لپتاپ به سیستم زنده منتقل نشود.
Secret زمان Build با Secret زمان Runtime فرق دارد
token دریافت package خصوصی ممکن است فقط در build لازم باشد؛ password دیتابیس در زمان اجرای container مصرف میشود. انتقال هر دو با یک روش خطرناک است. build secret باید فقط در همان دستور build در دسترس باشد و داخل artifact نرود. runtime secret باید هنگام اجرای سرویس داده شود و تغییر آن نیازمند rebuild image نباشد. هر دو مسیر را جدا در threat model و CI ثبت کنید.
چرا ARG و ENV برای Build Secret مناسب نیستند؟
آرگومان و متغیر build میتوانند در metadata، history، cache یا log باقی بمانند. پاککردن فایل یا unset در یک دستور بعدی، لایه قبلی را از بین نمیبرد. مستندات Docker برای credential زمان build از secret mount یا SSH mount استفاده میکنند. چکلیست Dockerfile production مرز build و runtime را با جزئیات بیشتری توضیح میدهد.
BuildKit Secret چگونه مصرف میشود؟
# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=npm_token,required=true NPM_TOKEN="$(cat /run/secrets/npm_token)" npm ci
این فقط الگو است: ابزار package شما ممکن است فایل config ویژه بخواهد و نباید token را در خروجی verbose چاپ کند. secret هنگام آن دستور mount میشود و هدف این است که در لایه نهایی نماند. پس از build، image و log را برای رد credential بررسی کنید. اگر command فایل credential را در cache یا home کپی کند، استفاده از mount بهتنهایی مانع افشا نیست.
SSH mount را چه زمانی استفاده کنیم؟
برای clone منبع خصوصی از SSH forwarding استفاده میشود تا کلید داخل image کپی نشود. host key verification را حذف نکنید؛ اتصال به میزبان ناشناس میتواند credential یا source را در معرض حمله قرار دهد. deploy key با دسترسی read-only و محدود به همان repository بهتر از کلید شخصی گسترده است. اگر source را بیرون build دریافت میکنید، provenance artifact را نیز ثبت کنید.
Secret در Docker Compose
Compose secret در سطح بالا تعریف میشود و سپس فقط به سرویس مصرفکننده اختصاص مییابد. در Linux معمولاً فایل آن زیر /run/secrets/<name> دیده میشود. این مدل از environment variable کمافشاتر است و کنترل دسترسی سرویسبهسرویس میدهد؛ بااینحال فایل منبع روی host همچنان باید با permission، backup و دسترسی مناسب محافظت شود. Compose عادی را با secret encrypted در Swarm یا secret manager ابری یکسان فرض نکنید.
services:
app:
image: registry.example/app@sha256:...
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password
این نمونه مقدار را داخل YAML نمیگذارد، اما مسیر روی host را امن نمیکند. پوشه secret نباید وارد repository یا build context شود. نام image و digest نمونهاند و باید با artifact واقعی جایگزین شوند.
قرارداد _FILE عمومی نیست
برخی imageهای رسمی متغیرهایی مانند POSTGRES_PASSWORD_FILE را میپذیرند و محتوا را از فایل میخوانند. این یک قرارداد پیادهسازی image است، نه قابلیتی که هر برنامه خودکار پشتیبانی کند. مستندات image دقیق را بخوانید. برای برنامه خودتان میتوانید مسیر فایل secret را config کنید؛ مقدار را فقط در حافظه لازم نگه دارید و هرگز در صفحه خطا یا endpoint تشخیصی چاپ نکنید.
Environment Variable چه ریسکی دارد؟
متغیر محیطی ممکن است در inspect، crash report، debug dump یا log ابزارها دیده شود و برای همه processهای مرتبط قابلدسترسی باشد. گاهی پلتفرم فقط همین روش را ارائه میدهد؛ در آن صورت scope credential، دسترسی به Docker daemon، log redaction و rotation را سختگیرانهتر کنید. تبدیل environment به فایل موقت توسط entrypoint نیز باید permission و حذف درست داشته باشد و مقدار را echo نکند.
Private Key و گواهی TLS
private key را مانند password با اثر بالا مدیریت کنید. فقط reverse proxy لازم است آن را بخواند؛ appهای پشت proxy نباید key عمومی سایت را دریافت کنند. mount فقطخواندنی، user محدود و چرخه تمدید/reload لازم است. راهنمای TLS سرویسهای Docker نشان میدهد چرا فایل تازه بدون reload و آزمون بیرونی کافی نیست.
Least Privilege در سه سطح
- credential فقط مجوز عملیات لازم را داشته باشد؛ مثلاً read-only به یک bucket مشخص.
- Secret فقط به container و process مصرفکننده داده شود.
- انسانها و pipelineها فقط در زمان و محیط لازم حق دسترسی داشته باشند.
یک token مدیرکل برای همه سرویسها rotation و attribution را خراب میکند. حساب سرویس مستقل، scope محدود و تاریخ انقضا اثر رخداد را کم میکند. دسترسی Docker socket عملاً میتواند راهی برای خواندن secretهای containerهای دیگر باشد؛ آن را به agentها و ابزارهای غیرضروری mount نکنید.
Rotation را پیش از بحران طراحی کنید
Secret جدید را بسازید، مصرفکننده را طوری تغییر دهید که مقدار تازه را بگیرد، سلامت را تأیید کنید و سپس مقدار قبلی را revoke کنید. برای credentialهایی که امکان همزیستی دو کلید دارند، این ترتیب downtime را کم میکند. اگر برنامه فقط در startup فایل را میخواند، تغییر فایل بهتنهایی کافی نیست و recreate/reload کنترلشده لازم است. نام نسخهدار یا reference پایدار را متناسب با secret manager انتخاب کنید.
اگر Secret افشا شد چه کنیم؟
- دامنه اثر و سیستمهای مصرفکننده را مشخص کنید.
- credential را revoke یا rotate کنید؛ صرف حذف از Git کافی نیست.
- log دسترسی و استفاده غیرعادی را در بازه افشا بررسی کنید.
- نسخههای image، cache CI، artifact و backup دارای مقدار را شناسایی کنید.
- علت ورود secret به مسیر اشتباه را اصلاح و guard خودکار اضافه کنید.
بازنویسی تاریخ repository ممکن است انتشار بعدی را کم کند، ولی نسخههای cloneشده را پس نمیگیرد. ابتدا اعتبار credential را از بین ببرید. جزئیات incident را بدون بازنشر خود secret مستند کنید.
Detection و Audit
secret scanning در commit و CI مفید است اما false positive و blind spot دارد. pattern شناختهشده، entropy و فهرست providerها را با review انسانی ترکیب کنید. دسترسی secret manager، تغییر policy، شکست مکرر authentication و استفاده از مبدأ جدید را مانیتور کنید. audit log خودش ممکن است identifier حساس داشته باشد و retention و دسترسی میخواهد.
اشتباههای رایج
- قرار دادن secret در
.envو فرض امن بودن چون Git آن را ignore کرده است - کپی secret در Dockerfile و حذف آن در لایه بعدی
- چاپ config کامل در log برای عیبیابی
- اشتراک یک credential میان همه محیطها
- mount کردن secret برای سرویسهایی که مصرفش نمیکنند
- rotation فایل بدون reload برنامه
- نگهداری کلید بلندمدت در runner عمومی CI
چکلیست عملی
برای هر secret، منبع، مصرفکننده، scope، تاریخ انقضا، روش تزریق، رفتار rotation و owner را ثبت کنید. repository، Dockerfile، Compose نهایی، image history و log pipeline را بازبینی کنید. یک rotation آزمایشی در staging انجام دهید و failure حالت نبودن secret را نیز تست کنید؛ برنامه باید fail closed و پیام بدون مقدار حساس بدهد.
چه زمانی کمک تخصصی لازم است؟
اگر secretها میان CI، registry، چند سرویس و چند سرور پخش شدهاند، جابهجایی یکباره ممکن است قطعی یا lockout بسازد. داکرایز اپلیکیشن میتواند مسیر build و runtime، سطح دسترسی و rotation را مرحلهای بازطراحی کند.
پرسشهای متداول
آیا فایل .env یک secret manager است؟
خیر؛ فقط ورودی config است و حفاظت آن به filesystem، فرایند و دسترسی میزبان وابسته است.
آیا Compose Secret رمزگذاریشده ذخیره میشود؟
رفتار Compose عادی را با Swarm یکسان ندانید؛ فایل منبع host و مدل پلتفرم را بررسی کنید.
آیا میتوان secret را داخل image گذاشت چون registry خصوصی است؟
خیر؛ image ممکن است cache، export یا به محیط دیگر منتقل شود و rotation آن به rebuild همه نسخهها وابسته میشود.
پس از تغییر secret باید container restart شود؟
به برنامه بستگی دارد؛ اگر فقط هنگام startup میخواند، recreate یا reload لازم است. این رفتار را مستند و آزمون کنید.