پرش به محتویات

شب ۲۳: TLS در Kubernetes

بخش ۲۳ از مجموعهٔ آموزش Traefik در ۳۰ شب؛ هر جلسه برای ۶۰ تا ۹۰ دقیقه مطالعه، تمرین عملی، بررسی نتیجه و تمرین رفع خرابی طراحی شده است. مثال‌ها مطابق منبع با Traefik Proxy v3.7 نوشته شده‌اند؛ برای محیط عملیاتی نسخهٔ اصلاحی آزموده‌شده یا digest مشخصی را ثابت کنید. تمرین‌ها را روی میزبان یا کلاستر آزمایشگاهی اجرا کنید.

فهرست کامل دورهٔ ترافیک در ۳۰ شب

هدف‌های یادگیری

  • خاتمهٔ TLS با Kubernetes Secrets و چرخش زندهٔ آن.
  • افزودن تغییرمسیرها و گزینه‌های امن TLS.
  • درک نقش cert-manager و عیب‌یابی ACME.

تمرین عملی: TLS مبتنی بر Secret

kubectl -n apps create secret tls whoami-tls \
  --cert=certs/whoami.crt --key=certs/whoami.key \
  --dry-run=client -o yaml > whoami-tls.yaml
kubectl apply -f whoami-tls.yaml
apiVersion: traefik.io/v1alpha1
kind: TLSOption
metadata: {name: modern, namespace: apps}
spec:
  minVersion: VersionTLS12
  sniStrict: true
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata: {name: https-redirect, namespace: apps}
spec:
  redirectScheme: {scheme: https, permanent: true}
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata: {name: whoami-http, namespace: apps}
spec:
  entryPoints: [web]
  routes:
    - match: Host(`whoami.example.test`)
      kind: Rule
      middlewares: [{name: https-redirect}]
      services: [{name: whoami, port: 80}]
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata: {name: whoami-https, namespace: apps}
spec:
  entryPoints: [websecure]
  routes:
    - match: Host(`whoami.example.test`)
      kind: Rule
      services: [{name: whoami, port: 80}]
  tls:
    secretName: whoami-tls
    options: {name: modern, namespace: apps}
kubectl apply -f tls-route.yaml
kubectl -n apps describe secret whoami-tls
openssl s_client -connect 127.0.0.1:443 -servername whoami.example.test \
  -CAfile certs/lab-ca.crt -verify_return_error </dev/null
curl --cacert certs/lab-ca.crt --resolve whoami.example.test:443:127.0.0.1 \
  https://whoami.example.test/

فایل whoami-tls.yaml را commit نکنید؛ دادهٔ کلید خصوصی آن با base64 کدگذاری شده و رمزگذاری نشده است. برای وضعیت مطلوب از روندهای sealed secret یا secret خارجی استفاده کنید.

نمونهٔ شیء cert-manager، پس از نصب و ایمن‌سازی جداگانهٔ cert-manager:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata: {name: whoami, namespace: apps}
spec:
  secretName: whoami-tls
  dnsNames: [whoami.example.com]
  issuerRef: {kind: ClusterIssuer, name: letsencrypt-staging}
kubectl -n apps get certificate,certificaterequest,order,challenge
kubectl -n apps describe certificate whoami
kubectl -n apps get secret whoami-tls -o jsonpath='{.metadata.resourceVersion}{"\n"}'

با اعمال TLS Secret تازه‌تولیدشده، گواهی آزمایشگاه را بچرخانید، resourceVersion آن را یادداشت کنید و openssl s_client را تا تغییر شمارهٔ سریال تکرار کنید. این کار بازخوانی کنترلر بدون restart شدن podها را ثابت می‌کند.

نکته‌های عیب‌یابی

  • TLS Secret رد می‌شود: tls.crt یا tls.key ندارد، زنجیره نامعتبر است یا کلید با گواهی منطبق نیست.
  • وضعیت Certificate برابر Ready=False است: شرایط و رویدادها را به‌ترتیب در CertificateRequest، سپس Order و Challenge دنبال کنید.
  • گواهی اشتباه است: عدم تطابق SNI با میزبان مسیر، رفتار پیش‌فرض TLSStore یا خطای نام و namespace مربوط به secret را بررسی کنید.
  • HTTPS کار می‌کند اما HTTP تغییرمسیر نمی‌دهد: مسیریاب جداگانهٔ web یا تغییرمسیر entrypoint بسازید.

خودآزمایی

  1. آیا base64 یک کنترل امنیتی است؟ خیر.
  2. چرا صدور خارجی برای چند نمونه بهتر است؟ تمام نمونه‌ها یک Secret همگام‌شده را مصرف می‌کنند و وضعیت محلی تغییرپذیر ACME را مشترک نمی‌کنند.
  3. کدام فیلد گواهی IngressRoute را انتخاب می‌کند؟ spec.tls.secretName.
  4. اثبات کنید: Secret را بچرخانید و تغییر سریال گواهی ارائه‌شده را بدون انتشار مجدد Traefik نشان دهید.