KUBERNETES

ConfigMap و Secret در Kubernetes: مدیریت تنظیمات و رمزها

روش‌های تزریق ConfigMap و Secret به Pod (env، envFrom، volume)، به‌روزرسانی بدون ری‌استارت، محدودیت‌های امنیتی Secret و راهکارهای واقعی مثل Sealed Secrets.

یک اصل ثابت در استقرار برنامه‌ها این است که تنظیمات از ایمیج جدا بماند: یک ایمیج واحد باید در توسعه، آزمایش و تولید اجرا شود و فقط پیکربندی آن عوض شود. در Kubernetes این جداسازی با دو منبع انجام می‌شود: ConfigMap برای تنظیمات عادی و Secret برای داده‌ی حساس. این راهنما روش‌های ساخت و تزریق آن‌ها به Pod، رفتار به‌روزرسانی و محدودیت‌های امنیتی Secret را توضیح می‌دهد.

K8SKubernetes YAML GeneratorConfigMap و Secret را با فرم بسازید و به Deployment متصل کنید.

ساخت ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  LOG_LEVEL: info
  FEATURE_X: "true"
  app.yaml: |
    server:
      port: 8080
    cache:
      ttl: 60s

مقدارهای ConfigMap رشته‌اند؛ مقدارهایی مثل true و عددها را داخل کوتیشن بنویسید تا YAML آن‌ها را به نوع دیگری تفسیر نکند. هر کلید می‌تواند یک مقدار کوتاه یا محتوای کامل یک فایل (با |) باشد. از خط فرمان هم می‌توان ساخت:

kubectl create configmap app-config --from-literal=LOG_LEVEL=info --from-file=app.yaml

سه روش تزریق به Pod

۱. متغیر محیطی تکی (env)

env:
  - name: LOG_LEVEL
    valueFrom:
      configMapKeyRef:
        name: app-config
        key: LOG_LEVEL

۲. همه‌ی کلیدها (envFrom)

envFrom:
  - configMapRef:
      name: app-config
  - secretRef:
      name: app-secret

۳. فایل (volume)

containers:
  - name: app
    volumeMounts:
      - name: config
        mountPath: /etc/app
        readOnly: true
volumes:
  - name: config
    configMap:
      name: app-config
      items:
        - key: app.yaml
          path: app.yaml

کدام روش؟

روشبه‌روزرسانی خودکارمناسب برای
env / envFromخیر؛ نیاز به ساخت دوباره‌ی Podتنظیمات ساده و کلید-مقدار
volumeبله، پس از تأخیر کوتاه (به‌جز subPath)فایل‌های پیکربندی کامل
note تغییر یک ConfigMap به‌خودی‌خود Deployment را ری‌استارت نمی‌کند. روش رایج برای اعمال تنظیم جدید، kubectl rollout restart deployment/app است؛ یا هش محتوای ConfigMap را به‌عنوان annotation در Pod template قرار دهید (کاری که Helm معمولاً با یک checksum انجام می‌دهد) تا هر تغییر، rollout جدید بسازد.

Secret

Secret ساختاری شبیه ConfigMap دارد، با دو تفاوت: مقدارها در فیلد data به‌صورت Base64 نوشته می‌شوند (یا در stringData به‌صورت متن ساده که API خودش کدگذاری می‌کند)، و رفتار آن در لاگ و دسترسی‌ها حساس‌تر است.

apiVersion: v1
kind: Secret
metadata:
  name: app-secret
type: Opaque
stringData:
  DB_PASSWORD: s3cr3t-change-me
  API_TOKEN: replace-with-real-token
B64Base64 Encoder/Decoderمقدار Secret را به Base64 تبدیل کنید یا یک مقدار موجود را رمزگشایی و بررسی کنید.

چند نوع داخلی Secret وجود دارد که ابزارها آن‌ها را می‌شناسند: kubernetes.io/tls (گواهی و کلید برای Ingress)، kubernetes.io/dockerconfigjson (ورود به رجیستری خصوصی برای imagePullSecrets) و kubernetes.io/basic-auth.

kubectl create secret tls example-com-tls --cert=fullchain.pem --key=privkey.pem
kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com --docker-username=ci --docker-password="$TOKEN"

Secret چقدر امن است؟

پاسخ کوتاه: به‌تنهایی زیاد نه. چند واقعیت مهم:

  • Base64 رمزنگاری نیست. هر کسی که بتواند Secret را بخواند، با یک دستور آن را رمزگشایی می‌کند.
  • etcd: مقدارها به‌طور پیش‌فرض بدون رمزنگاری ذخیره می‌شوند. برای رمزنگاری در حالت سکون، EncryptionConfiguration را برای API server فعال کنید (یا از KMS ابری استفاده کنید).
  • RBAC: دسترسی get/list روی Secretها را فقط به حساب‌هایی بدهید که لازم دارند؛ list همه‌ی مقدارها را در یک درخواست برمی‌گرداند.
  • متغیر محیطی: مقدار envها به‌راحتی در لاگ برنامه، crash dump و ابزارهای عیب‌یابی نشت می‌کند. mount به‌صورت فایل معمولاً ایمن‌تر است.
  • هر کسی که بتواند Pod بسازد در یک namespace، می‌تواند Secretهای آن را در Pod خودش mount کند.

Secret در Git: چطور؟

در رویکرد GitOps همه‌چیز در Git است، ولی Secret را نباید به‌صورت متن ساده commit کرد. گزینه‌های رایج:

ابزارایده
Sealed SecretsSecret با کلید عمومی کلاستر رمزنگاری و در Git ذخیره می‌شود؛ فقط کنترلر داخل کلاستر آن را می‌گشاید
SOPSفایل‌های YAML با کلید (age، KMS، PGP) رمزنگاری می‌شوند و فقط مقدارها پوشیده می‌مانند
External Secrets OperatorSecret از یک مخزن خارجی (Vault، AWS Secrets Manager و …) به کلاستر همگام می‌شود

ConfigMapهای تغییرناپذیر

با immutable: true، ConfigMap یا Secret بعد از ساخت قابل‌ویرایش نیست؛ هم خطای ناخواسته را کم می‌کند و هم بار روی API server را (kubelet دیگر آن را پایش نمی‌کند). برای تغییر، یک نسخه‌ی جدید با نام تازه می‌سازید (مثل app-config-v2) و Deployment را به آن ارجاع می‌دهید؛ و rollout هم به‌طور طبیعی رخ می‌دهد.

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-v2
immutable: true
data:
  LOG_LEVEL: debug

عیب‌یابی

  • CreateContainerConfigError: ConfigMap یا Secret (یا کلید داخل آن) وجود ندارد. با kubectl describe pod نام دقیق را ببینید.
  • برنامه مقدار قدیمی را می‌خواند: env است و Pod ری‌استارت نشده، یا فایل با subPath mount شده است.
  • مقدار با کاراکتر اضافه می‌آید: هنگام Base64‌کردن از echo بدون -n استفاده شده و خط جدید انتهای رشته هم رمز شده است.
kubectl get secret app-secret -o jsonpath='{.data.DB_PASSWORD}' | base64 -d
echo -n 'value' | base64          # -n مهم است

جمع‌بندی و مطالعه‌ی بعدی

تنظیمات عادی را در ConfigMap، داده‌ی حساس را در Secret بگذارید؛ برای فایل‌های پیکربندی از volume و برای مقدارهای ساده از env استفاده کنید؛ و Secret را همیشه با RBAC، رمزنگاری etcd و ابزار مدیریت رمز (Sealed Secrets، SOPS یا External Secrets) همراه کنید. مانیفست‌های Deployment که این منابع به آن‌ها متصل می‌شوند در راهنمای مانیفست‌های Kubernetes آمده است و اگر Pod با خطای پیکربندی بالا نمی‌آید، راهنمای عیب‌یابی را ببینید.

پرسش‌های متداول

آیا Secret در Kubernetes رمزنگاری می‌شود؟
به‌طور پیش‌فرض نه: مقدار Secret فقط Base64 است و در etcd به همین شکل ذخیره می‌شود. برای محافظت واقعی باید encryption at rest را برای etcd فعال کنید و دسترسی به Secretها را با RBAC محدود کنید.
تغییر ConfigMap چرا روی Pod اعمال نشد؟
متغیرهای محیطی فقط هنگام ساخت کانتینر خوانده می‌شوند؛ برای اعمال تغییر باید Pod را دوباره بسازید (مثلاً kubectl rollout restart). فایل‌های mount‌شده از ConfigMap پس از مدتی خودکار به‌روز می‌شوند، مگر با subPath mount شده باشند.
فرق env و envFrom چیست؟
env متغیرها را یکی‌یکی (با نام و ارجاع به کلید) تعریف می‌کند؛ envFrom همه‌ی کلیدهای یک ConfigMap یا Secret را یک‌جا به متغیر محیطی تبدیل می‌کند. envFrom کوتاه‌تر است ولی کنترل کمتری روی نام‌ها می‌دهد.
حداکثر حجم ConfigMap و Secret چقدر است؟
هر کدام حداکثر حدود ۱ مگابایت (محدودیت etcd) هستند. برای فایل‌های بزرگ از volume یا ذخیره‌ی خارجی استفاده کنید.