
خیلی از پروژهها با یک اشتباه کوچک شروع میکنند:
env: - name: DATABASE_PASSWORD value: "P@ssw0rd-Production"
این manifest شاید در محیط آزمایشی سریع جواب بدهد، اما اگر وارد Git، لاگ CI/CD یا registry شود، رمز عبور دیگر secret نیست؛ فقط یک رشتهٔ قابلکپی است که ممکن است مدتها در تاریخچهٔ سیستم باقی بماند.
در Kubernetes، مدیریت Secret فقط به این سؤال محدود نمیشود که «رمز را کجا بنویسیم؟». باید بدانیم چه کسی آن را میخواند، چگونه به Pod میرسد، کجا log میشود، چه زمانی rotate میشود و بعد از افشا چگونه سریع بیاعتبارش کنیم.
کوبر resourceای به نام Secret دارد که برای نگهداری دادههایی مثل این موارد استفاده میشود:
رمز عبور database
token سرویسهای بیرونی
credential مربوط به registry
کلید خصوصی TLS
API key
credential اتصال به message broker
نمونهٔ ساده:
apiVersion: v1 kind: Secret meta "list", "watch"]
اگر این Role به Service Account یک application داده شود، application میتواند Secretهای زیادی را بخواند. تا جای ممکن باید دسترسی به Secretها در سطح معماری محدود شود؛ نه اینکه صرفاً به همهٔ Podهای namespace اعتماد کنیم.
همچنین permissionهای list و watch را با دقت بررسی کنید. یک application ممکن است فقط به خواندن یک مقدار مشخص نیاز داشته باشد، اما list کردن میتواند نام و metadata تمام Secretها را در اختیارش قرار دهد.
اگر application واقعاً نیازی به Kubernetes API ندارد، automountServiceAccountToken: false را فعال کنید:
spec: automountServiceAccountToken: false
کم کردن credentialهای غیرضروری یکی از سادهترین راههای کاهش دامنهٔ حمله است.
Secretهای Kubernetes در نهایت در etcd نگهداری میشوند. اگر encryption at rest فعال نباشد، دسترسی مستقیم یا backup نامناسب etcd میتواند مقدار Secretها را در معرض خطر قرار دهد.
چند اقدام مهم:
encryption at rest را فعال کنید.
کلید encryption را در محل امن نگهداری کنید.
دسترسی مستقیم به etcd را محدود کنید.
backupها را رمزنگاری و دسترسی آنها را audit کنید.
restore backup را آزمایش کنید.
فعال کردن encryption at rest به این معنی نیست که administrator دارای دسترسی API دیگر نمیتواند Secret را بخواند. این کنترل بیشتر برای حفاظت از دادهٔ ذخیرهشده و backupهاست.
Rotation باید از ابتدا در طراحی application دیده شود. اگر application فقط هنگام startup Secret را بخواند، تغییر Secret ممکن است تا restart شدن Pod اعمال نشود.
قبل از rotation در production مشخص کنید:
application تغییر credential را بدون restart میپذیرد یا نه.
نسخهٔ قدیمی و جدید چه مدت همزمان معتبر هستند.
آیا connection pool باید دوباره ساخته شود.
چه کسی rotation را اجرا و تأیید میکند.
در صورت شکست، rollback چگونه انجام میشود.
یک روش معمول:
credential جدید ایجاد شود.
application بتواند همزمان credential جدید را مصرف کند.
rollout تدریجی انجام شود.
مصرف credential قدیمی monitor شود.
credential قدیمی revoke شود.
ترتیب مهم است. اگر اول credential قدیمی را revoke کنیم و هنوز همهٔ Podها مقدار جدید را نگرفته باشند، downtime ایجاد میشود.
در زمان افشا، هدف اصلی پاک کردن متن secret از صفحه نیست؛ هدف بیاعتبار کردن آن است.
runbook پیشنهادی:
مشخص کنید چه secretی و در کجا افشا شده است.
credential را فوراً revoke یا rotate کنید.
log، Git history، artifact و backupهای در معرض خطر را بررسی کنید.
usage و access log مربوط به credential را بررسی کنید.
workloadهای مصرفکننده را شناسایی کنید.
مقدار جدید را deploy و rollout کنید.
secret قدیمی را از همهٔ منابع حذف و بیاعتبار کنید.
علت ریشهای را اصلاح کنید تا تکرار نشود.
اگر secret مربوط به registry باشد، باید image pull، pipeline و runnerها هم بررسی شوند. اگر secret مربوط به database باشد، audit query و loginهای مشکوک هم اهمیت پیدا میکنند.
گاهی Secret در manifest نیست، اما در لاگ دیده میشود:
Connecting to database with password=P@ssw0rd-Production
این مشکل باید در چند لایه کنترل شود:
application نباید credential را log کند.
خطاها نباید URL حاوی token را چاپ کنند.
tracing باید headerهای حساس را mask کند.
log collector باید الگوهای secret را شناسایی کند.
دسترسی به logها باید مانند دادهٔ حساس کنترل شود.
Mask کردن در سیستم log مفید است، اما جایگزین اصلاح application نیست؛ ممکن است secret قبل از رسیدن به collector در یک فایل یا agent ثبت شده باشد.
آیا هیچ secret واقعی در Git یا Dockerfile وجود ندارد؟
آیا Secretها با Base64 با رمزنگاری اشتباه گرفته نشدهاند؟
آیا encryption at rest برای etcd فعال است؟
آیا backupهای etcd محافظت میشوند؟
آیا هر workload فقط Secretهای لازم خودش را میخواند؟
آیا list و watch روی Secretها واقعاً ضروریاند؟
آیا Service Account غیرضروری حذف شده است؟
آیا secretها در log، trace و error response mask میشوند؟
آیا rotation بدون downtime آزمایش شده است؟
آیا credential قدیمی بعد از rotation revoke میشود؟
آیا برای افشای secret runbook آماده وجود دارد؟
آیا access log مربوط به خواندن Secret بررسی میشود؟
Secret Management فقط ساختن یک resource با نام Secret نیست. باید کل چرخهٔ عمر credential را مدیریت کنیم: تولید، ذخیرهسازی، انتقال، مصرف، rotation، audit و revoke.
برای سرویسهای ساده شاید Kubernetes Secret با RBAC محدود و encryption at rest کافی باشد. برای سرویسهای حساستر، secret manager خارجی، هویت workload، token کوتاهعمر و rotation خودکار انتخاب بهتری است.
سه قاعدهٔ ساده را همیشه در نظر بگیرید:
Secret را در Git و image قرار ندهید.
هر workload فقط به credential موردنیاز خودش دسترسی داشته باشد.
هر credential باید قابل rotation و revoke باشد.
اگر یک رمز عبور را نمیتوان سریع عوض کرد، احتمالاً آن را بهعنوان یک وابستگی دائمی طراحی کردهایم، نه یک secret قابلمدیریت.