0

Giải thích và thiết Lập SSL Cho Dịch Vụ Public Trên Kubernetes Với Ingress

Xin chào các bạn, ngày hôm nay chúng ta sẽ cùng nhau thảo luận về một chủ đề: Thiết lập SSL cho các dịch vụ Public trên K8s.

Bài toán đặt ra ở đây là khi expose IP ra ngoài cụm k8s rồi nhưng lại chỉ muốn add hosts hoặc đang test nhưng yêu cầu SSL.

Ok mình cùng bắt đầu thôi.

Giới thiệu

  1. Cluster Kubernetes : Cụm K8s cần hoạt động ổn định, có quyền truy cập quản trị
  2. Chứng chỉ SSL
    • Chứng chỉ từ nhà cung cấp uy tín hoặc tự ký (Self-signed certificate).
    • File .crt và .key
  3. Các tài nguyên
    • Namespace (ví dụ: ssl-test)
    • Deployment cần triển khai ssl
    • Ingress Controller
    • Ingress
    • Service
    • Load balancer

Tạo Secret chứa chứng chỉ SSL

Có 2 cách tạo secret chứa SSL là bằng file hoặc bằng CLI. Ví dụ ở đây sẽ tạo 1 secret tên my-ssl-secret có tham số là : tls.crttls.key

  1. Tạo bằng file secret.yaml
    •   apiVersion: v1 
        kind: Secret
        metadata:
            name: my-ssl-secret
            namespace: <Namespace>
        data:
            tls.crt: <base64encode> CERTIFICATE
            tls.key: <base64encode> PRIVATE KEY
        type: kubernetes.io/tls
      
    • Dùng lệnh kubelectl apply -f secret.yaml
  2. Tạo bằng CLI
    • kubectl create secret tls my-ssl-secret --cert=path/to/tls.crt --key=path/to/tls.key -n <Namespace>
    • my-ssl-secret : tên Secret
    • --cert và --key : đường dẫn đến file chứng chỉ và khóa riêng
    • -n <Namespace> : namespace chứa Secret

Luồng đi của các tài nguyên.

Đây sẽ là cách mà luồng traffic từ User về với Pod (Application), chỉ giới thiệu về cách tạo các tài nguyên cần thiết để làm việc này chứ không phải các tài nguyên khác.

Giả sử chúng ta đã có Deployment chứa application. App sẽ expose ra port 3000 (có thể là các port khác tùy theo nhu cầu và mong muốn). Ta có sơ đồ như sau :

image2024-11-14_15-38-0.png

  1. User

    • Người dùng gửi yêu cầu HTTP hoặc HTTPS từ trình duyệt hoặc ứng dụng.
    • Giao tiếp sử dụng cổng 443 cho HTTPS và 80 cho HTTP.
    • Yêu cầu sẽ được DNS phân giải tên miền thành địa chỉ IP public của Load Balancer.
  2. Load balancer

    • Đóng vai trò là endponit của K8s. Lắng nghe trên cổng 80 và 443.
    • Có vai trò chuyển lưu lượng đến các pod của Ingress Controller bên trong cluster trên cổng 80 và 443.
  3. Ingress Controller

    • Chịu trách nhiệm xử lý các yêu cầu HTTP/HTTPS đến cluster, lắng nghe trên cổng 80 và 443.
    • Đối với các yêu cầu HTTPS, Ingress Controller sử dụng Secret chứa chứng chỉ SSL để giải mã lưu lượng, đảm bảo kết nối bảo mật.
    • Sau khi xử lý, Ingress Controller sẽ định tuyến lưu lượng đến dịch vụ phù hợp dựa trên quy tắc trong Ingress Resource.
  4. Ingress Resource

    • Chứa các quy tắc định tuyến, cho phép Ingress Controller biết dịch vụ nào cần xử lý yêu cầu dựa trên tên miền và đường dẫn.
    • Sau khi xác định, Ingress Controller chuyển tiếp yêu cầu đến dịch vụ cụ thể. Lúc này, ta có thể sửa theo cổng theo yêu cầu (ở đây là 3000) để giao tiếp với Service (ClusterIp hoặc NodePort).
  5. Service (ClusterIp hoặc NodePort)

    • Dịch vụ Kubernetes lắng nghe trên cổng 3000 và chuyển tiếp lưu lượng đến ứng dụng chạy trong các pod.
    • Ứng dụng trong pod có thể chạy trên một cổng khác, trong trường hợp này là 3000.
  6. Pod (Application)

    • Pod nhận lưu lượng trên cổng 3000 và xử lý yêu cầu.
    • Ứng dụng trong pod xử lý dữ liệu và trả phản hồi về qua chuỗi dịch vụ.

Cấu hình tệp YAML cho các tài nguyên

  1. Load balancer
apiVersion: v1
kind: Service
metadata:
  name: <Load balancer name>
  namespace: <Namespace>
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-internal: "true" # Cấu hình riêng của từng cloud provider cho phép service expose IP
spec:
  type: LoadBalancer
  selector:
    app: <Ingress Controller Label>
  ports:
    - name: http
      port: 80          # port forward tiếp đến tài nguyên tiếp theo
      targetPort: 80    # port lắng nghe
    - name: https
      port: 443         # port forward tiếp đến tài nguyên tiếp theo
      targetPort: 443   # port lắng nghe
  1. Ingress Controller
apiVersion: apps/v1
kind: Deployment
metadata:
  name: <Ingress Controller Name>
  namespace: <Namespace>
spec:
  replicas: 1
  selector:
    matchLabels:
      app: <Ingress Controller Label>
  template:
    metadata:
      labels:
        app: <Ingress Controller Label>
    spec:
      volumes:
        - name: webhook-cert
          secret:
            secretName: <Ingress Controller Secret>
            defaultMode: 420
      containers:
        - name: <Ingress Container Name>
          image: >-
            registry.k8s.io/ingress-nginx/controller:v1.11.3@sha256:d56f135b6462cfc476447cfe564b83a45e8bb7da2774963b00d12161112270b7
          args:
            - /nginx-ingress-controller
            - --publish-service=$(POD_NAMESPACE)/<Service Name> # Cập nhật tên service
            - '--controller-class=k8s.io/ingress-nginx'
            - '--ingress-class=nginx'
            - '--configmap=$(POD_NAMESPACE)/crm-ingress-ingress-nginx-controller'
            - '--validating-webhook=:8443'
            - '--validating-webhook-certificate=/usr/local/certificates/cert'
            - '--validating-webhook-key=/usr/local/certificates/key'
            - '--enable-metrics=false'
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
            - name: https
              containerPort: 443
              protocol: TCP
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
            - name: LD_PRELOAD
              value: /usr/local/lib/libmimalloc.so
  1. Ingress Recource
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: <Ingress Resource Name>
  namespace: <Namespace>
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"     # Buộc chuyển hướng tất cả các yêu cầu HTTP sang HTTPS.
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - <DOMAIN NAME>
      secretName: <SECRET chứa SSL>
  rules:
    - host: <DOMAIN NAME>
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: <SERVICE NAME>
                port:
                  number: 3000 # Port của Service đẩy sang
  1. Service
apiVersion: v1
kind: Service
metadata:
  name: <Service Name>
  namespace: <Namespace>
spec:
  selector:
    app: <Deployment App Name>
  ports:
    - protocol: TCP
      port: 3000  # Port của Service lắng nghe
      targetPort: 3000  # Port của container nhận traffic
  type: ClusterI

Một số lỗi phổ biến và cách xử lý

  1. x509: certificate signed by unknown authority

    • Nguyên nhân: Chứng chỉ được sử dụng trong Ingress Controller không được công nhận bởi hệ thống hoặc CA (Certificate Authority) không đáng tin cậy.
    • Cách giải quyết:
      • Kiểm tra và đảm bảo rằng chứng chỉ TLS và CA được thêm vào là hợp lệ.
      • Xác minh rằng Secret chứa chứng chỉ đã được tạo đúng cách (sử dụng kubectl get secret <secret-name> -n <namespace>).
      • Sử dụng chứng chỉ từ CA đáng tin cậy hoặc thêm CA vào các pod nếu cần.
  2. Failed calling webhook validate.nginx.ingress.kubernetes.io

    • Nguyên nhân: Webhook của Ingress Controller không hoạt động đúng do lỗi chứng chỉ hoặc không thể kết nối tới service của webhook.
    • Cách giải quyết:
      • Kiểm tra trạng thái của admission controller bằng lệnh kubectl get svc -n <namespace> để đảm bảo nó hoạt động.
      • Đảm bảo rằng chứng chỉ TLS của admission controller là hợp lệ và cập nhật lại nếu cần thiết.
  3. Không chuyển tiếp đúng lưu lượng đến pod (404 hoặc không phản hồi)

    • Nguyên nhân: Cấu hình Ingress hoặc Service không đúng, chẳng hạn như path, port, hoặc serviceName không khớp.
    • Cách giải quyết:
      • Kiểm tra tệp cấu hình Ingress để đảm bảo spec.rules và backend.service được đặt đúng.
      • Đảm bảo rằng Service đúng cổng và đang chuyển tiếp lưu lượng đến pod trên cổng 3000.
  4. No endpoints available for service

    • Nguyên nhân: Service không có endpoint nào khả dụng để chuyển tiếp lưu lượng đến pod.
    • Cách giải quyết:
      • Kiểm tra các pod bằng kubectl get pods -n <namespace> để đảm bảo chúng đang chạy và sẵn sàng.
      • Đảm bảo rằng selector của Service khớp với nhãn của pod.
  5. Default backend - 404 từ Ingress

    • Nguyên nhân: Ingress không thể tìm thấy backend phù hợp cho yêu cầu.
    • Cách giải quyết:
      • Kiểm tra rằng cấu hình host và path trong Ingress khớp với yêu cầu được gửi đến.
      • Đảm bảo rằng Service được tham chiếu tồn tại và hoạt động đúng.
  6. Liên quan đến cấu hình HTTPS không hoạt động

    • Nguyên nhân: Secret TLS hoặc cấu hình tls trong Ingress bị thiếu hoặc không chính xác.
    • Cách giải quyết:
      • Đảm bảo rằng Secret chứa chứng chỉ TLS hợp lệ (kiểm tra với kubectl describe secret <secret-name> -n <namespace>).
      • Đảm bảo cấu hình spec.tls trong Ingress tham chiếu đúng đến Secret chứa chứng chỉ TLS.
  7. Kết nối curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number

    • Nguyên nhân: Phiên bản SSL/TLS không khớp hoặc cấu hình Ingress không đúng.
    • Cách giải quyết:
      • Kiểm tra phiên bản TLS được hỗ trợ trong Ingress Controller và cấu hình client
      • Đảm bảo rằng không có sự cố về phiên bản TLS trong Secret và cấu hình Ingress.
  8. Lỗi load balancer tắc ở trạng thái pending và không có IP

    • Nguyên nhân: Có thể dải IP của cụm K8s không đủ để cũng cấp.
    • Cách giải quyết:
      • Kiểm tra lại cụm xem còn IP có thể expose ra không
      • Xóa những IP không sử dụng.
      • Extend thêm subnet cho cụm k8s.

Trên đây là bài viết đầu tay về tổng quan cách cấu hình SSL trên K8s của mình.

Cảm ơn các bạn đã dành thời gian.

Mình là Hiếu

Một Developer tập tành học DevOps.

Hẹn gặp các bạn trong bài viết sắp tới.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí