Introduction to Istio, Part 10

·

9 min read

Service Entries for Registry-Only Outbound Traffic Policy

Khi một dịch vụ được tạo bên trong mesh, Istio sẽ tự động tạo một mục (entry) cho dịch vụ đó trong service registry. Đây là một phần của quá trình service discovery trong Istio.

Tuy nhiên, có những tình huống mà quá trình tự động phát hiện dịch vụ (automatic service discovery) không xảy ra hoặc không thể thực hiện, nhưng dịch vụ đó vẫn cần được Istio nhận biết và thêm vào service registry. Một số ví dụ bao gồm:

  • Legacy workloads (khối lượng công việc cũ).

  • Cụm cơ sở dữ liệu (database cluster) mà các dịch vụ trong mesh cần truy cập, nhưng bản thân cụm cơ sở dữ liệu không thuộc về mesh.

Để xử lý những trường hợp này, Istio cung cấp ServiceEntry, một loại tài nguyên tùy chỉnh (custom resource), cho phép chúng ta định nghĩa các dịch vụ này một cách rõ ràng.

Phân Biệt Dịch Vụ Bên Trong và Bên Ngoài Mesh

Istio phân biệt hai loại dịch vụ:

  1. Dịch vụ bên trong mesh (mesh-internal services):

    • Ví dụ: legacy workloads.
  2. Dịch vụ bên ngoài mesh (mesh-external services):

    • Ví dụ: API của bên thứ ba.

ServiceEntry và Các Chính Sách Traffic

Khi tạo một ServiceEntry cho một API bên thứ ba, chúng ta có thể:

  • Định nghĩa các chính sách điều hướng và lưu lượng (routing and traffic policies) thông qua Virtual ServicesDestination Rules.

  • Ví dụ:

    • Retries (thử lại).

    • Timeouts (giới hạn thời gian).

    • Mirroring (nhân bản lưu lượng).

    • Fault injection (tiêm lỗi).

    • Chiến lược cân bằng tải.

    • Outlier detection (phát hiện lỗi).

Nếu API của bên thứ ba không ổn định, việc định nghĩa các chính sách như timeoutretry là cần thiết. Với Istio, chúng ta có thể làm điều này một cách tập trung mà không cần sửa đổi mã nguồn của bất kỳ workload nào gửi yêu cầu đến API đó.

Ví Dụ Cấu Hình ServiceEntry

Dưới đây là một ví dụ về ServiceEntry dành cho www.googleapis.com, định nghĩa API của bên thứ ba này là MESH_EXTERNAL:

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: googleapis-svc-entry
spec:
  hosts:
  - www.googleapis.com
  location: MESH_EXTERNAL
  resolution: DNS
  ports:
  - number: 443
    name: https
    protocol: TLS
  • location: MESH_EXTERNAL:

    • Chỉ định rằng dịch vụ nằm ngoài mesh.
  • resolution: DNS:

    • Cho biết cách xác định endpoint thật sự của dịch vụ, trong trường hợp này là sử dụng DNS resolution.

Lợi Ích

  • ServiceEntry giúp tích hợp các dịch vụ bên ngoài vào mesh mà không cần sửa đổi ứng dụng.

  • Định nghĩa chính sách tại một nơi duy nhất giúp quản lý dễ dàng và tập trung hơn.

Bây giờ hãy tưởng tượng một tình huống khác: bạn muốn kết nối với một cụm cơ sở dữ liệu nội bộ mesh (mesh-internal database cluster) và muốn chỉ định trực tiếp các địa chỉ IP của cụm đó. Trong trường hợp này, cấu hình ServiceEntry sẽ trông như sau:

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: external-svc-mongocluster
spec:
  hosts:
  - mymongodb.somedomain # không được sử dụng
  addresses:
  - 192.192.192.192/24 # Các VIPs
  ports:
  - number: 27018
    name: mongodb
    protocol: MONGO
  location: MESH_INTERNAL
  resolution: STATIC
  endpoints:
  - address: 2.2.2.2
  - address: 3.3.3.3

Giải Thích Cấu Hình

  1. location: MESH_INTERNAL

    • Chỉ định rằng đây là một dịch vụ nội bộ mesh.
  2. resolution: STATIC

    • Thay vì sử dụng DNS để phân giải (resolve) địa chỉ, cấu hình này chỉ định các địa chỉ IP tĩnh trong trường endpoints.
  3. endpoints

    • Danh sách các địa chỉ IP tĩnh được sử dụng làm điểm kết nối (endpoints) cho dịch vụ.

    • Trong ví dụ này, hai địa chỉ IP 2.2.2.23.3.3.3 được cung cấp làm endpoints.

  4. hosts

    • Trường này không được sử dụng trong trường hợp resolutionSTATIC.
  5. addresses

    • Trường này khai báo một dải địa chỉ IP (VIPs - Virtual IPs) đại diện cho dịch vụ.

Lựa Chọn Thay Thế: workloadSelector

Thay vì sử dụng trường endpoints, bạn cũng có thể chọn workloadSelector để tự động chọn endpoints dựa trên nhãn (labels) của workload. Điều này cho phép Istio tìm kiếm và kết nối các workload cụ thể mà không cần chỉ định IP tĩnh.

Ví dụ sử dụng workloadSelector:

workloadSelector:
  labels:
    app: mongodb
    version: v1

Khi Nào Sử Dụng Cách Tiếp Cận Này?

  • Cụm cơ sở dữ liệu nội bộ hoặc dịch vụ khác không đăng ký qua DNS.

  • Các dịch vụ cần sử dụng IP tĩnh để kết nối (ví dụ: cơ sở dữ liệu không hỗ trợ DNS).

  • Các tình huống mà cần kiểm soát thủ công các endpoint hoặc VIPs.

Sử dụng ServiceEntry như trên giúp bạn tích hợp các dịch vụ nội bộ mesh một cách chính xác, đặc biệt khi các dịch vụ không hỗ trợ DNS hoặc khi cần cấu hình IP tĩnh rõ ràng.

Cấu Hình Service Entries với Chính Sách Outbound Registry-Only

Việc bảo mật egress traffic (lưu lượng thoát ra ngoài) là một phần quan trọng trong việc bảo vệ một service mesh. Istio cho phép cấu hình chính sách outbound traffic để chỉ cho phép gọi đến các dịch vụ đã được đăng ký trong service registry. Điều này giúp kiểm soát và ngăn chặn các kết nối không mong muốn ra ngoài.

Registry-Only Outbound Traffic Policy

Khi cấu hình mesh ở chế độ này, bạn phải tạo một tài nguyên ServiceEntry cho từng dịch vụ bên ngoài (mesh-external service) mà bạn muốn cho phép truy cập. Nếu không, mọi kết nối outbound đến các dịch vụ bên ngoài sẽ bị chặn.

Thực Hành: Cấu Hình Outbound Traffic Policy

  1. Chuyển sang chế độ "registry-only" Bước đầu tiên là cấu hình mesh để sử dụng chế độ registry-only outbound traffic policy. Sau đó, kiểm tra và xác nhận rằng một dịch vụ chạy bên trong mesh không thể gọi đến bất kỳ dịch vụ bên ngoài nào, chẳng hạn như github.com.

    Yêu cầu trước:

    • Cụm Kubernetes đã chạy sẵn.

    • Istio được cài đặt và cấu hình với profile demo.

Chạy lệnh sau để kích hoạt chế độ "registry-only":

    istioctl install --set profile=demo \
        --set meshConfig.outboundTrafficPolicy.mode=REGISTRY_ONLY

Lưu ý: Công cụ Istio CLI đủ thông minh để nhận ra rằng Istio đã được cài đặt sẵn. Khi chạy lệnh này, cấu hình của cài đặt hiện tại sẽ được cập nhật mà không cần cài lại toàn bộ.

Kết Quả:

  • Sau khi thực hiện cấu hình, bất kỳ dịch vụ nào bên trong mesh sẽ không còn khả năng gọi đến các dịch vụ bên ngoài, trừ khi bạn khai báo chúng trong một ServiceEntry.

Kiểm Tra Cấu Hình Istio

Sau khi cập nhật cấu hình outbound traffic policy sang chế độ REGISTRY_ONLY, bạn cần xác minh giá trị cấu hình mới này.

  1. Xem cấu hình ConfigMap của Istio: Chạy lệnh sau để hiển thị giá trị ConfigMap trong namespace istio-system:

     kubectl get cm -n istio-system istio -o yaml
    
  2. Xác minh giá trị của outboundTrafficPolicy.mode: Kiểm tra trong đầu ra rằng trường outboundTrafficPolicy.mode đã được đặt thành REGISTRY_ONLY.

Thực Hiện Kết Nối Từ Trong Mesh

  1. Triển khai ứng dụng mẫu sleep: Ứng dụng sleep của Istio sẽ đóng vai trò là dịch vụ chạy bên trong mesh để kiểm tra kết nối outbound.

    • Điều hướng đến thư mục chứa bộ cài Istio:

        cd <path_to_istio_distribution>
      
    • Triển khai workload sleep:

        kubectl apply -f samples/sleep/sleep.yaml
      
  2. Lấy tên pod của ứng dụng sleep: Chạy lệnh sau để lấy tên của pod sleep đang chạy:

     SLEEP_POD=$(kubectl get pod -l app=sleep -ojsonpath='{.items[0].metadata.name}')
    
  3. Thử thực hiện kết nối outbound tới github.com:

    • Chạy lệnh sau để gửi yêu cầu HTTP từ pod sleep đến github.com:

        kubectl exec $SLEEP_POD -it -- curl -v https://github.com
      
    • Xác nhận rằng yêu cầu không thành công với thông báo lỗi tương tự:

        * Trying 140.82.114.4:443...
        * Connected to github.com (140.82.114.4) port 443 (#0)
        * ALPN: offers h2
        * ALPN: offers http/1.1
        * CAfile: /cacert.pem
        * CApath: none
        * TLSv1.3 (OUT), TLS handshake, Client hello (1):
        * OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443
        * Closing connection 0
        curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443
        command terminated with exit code 35
      

Kết Quả:

Kết nối outbound từ dịch vụ bên trong mesh đến github.com đã bị chặn thành công, thể hiện chính sách REGISTRY_ONLY hoạt động đúng cách. Ở bước tiếp theo, bạn sẽ cần tạo một ServiceEntry để cấp quyền truy cập tới github.com.

Định Nghĩa ServiceEntry

Để cấp quyền truy cập đến dịch vụ bên ngoài mesh, chúng ta sẽ định nghĩa một ServiceEntry như sau:

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: github-external
spec:
  hosts:
  - github.com
  ports:
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS
  location: MESH_EXTERNAL
  • location: Được đặt là MESH_EXTERNAL, xác định rằng đây là một dịch vụ bên ngoài mesh.

  • hosts: Xác định hostname mà bạn muốn truy cập, ở đây là github.com.

  • ports: Định nghĩa cổng và giao thức (443, HTTPS) cho dịch vụ.

Triển khai ServiceEntry

  1. Lưu tài nguyên trên vào tệp service-entry.yaml.

  2. Áp dụng cấu hình ServiceEntry vào cluster:

     kubectl apply -f service-entry.yaml
    

Kiểm Tra Kết Nối

Sau khi ServiceEntry được tạo, thử lại kết nối từ pod sleep đến github.com:

kubectl exec $SLEEP_POD -it -- curl -v https://github.com
  • Kết quả mong đợi: Lần này, yêu cầu thành công và trả về nội dung HTML từ github.com.

Cấu Hình Nâng Cao Với Egress Gateway

Việc định nghĩa ServiceEntry chỉ là bước đầu trong việc cấu hình dịch vụ bên ngoài. Để tăng cường kiểm soát, Istio hỗ trợ triển khai thành phần Egress Gateway:

  1. Egress Gateway giúp định tuyến tất cả lưu lượng outbound qua gateway thay vì cho phép truy cập trực tiếp.

  2. Kết hợp với các tài nguyên như Gateway, VirtualService, và DestinationRule, bạn có thể cấu hình chi tiết các chính sách định tuyến, retries, hay timeouts cho lưu lượng outbound.

Tích Hợp AuthorizationPolicy

Nhờ vào khả năng xác định danh tính của workload trong Istio, bạn có thể kết hợp AuthorizationPolicy để kiểm soát chi tiết:

  • Ai (dịch vụ nội mesh) được phép truy cập

  • Dịch vụ nào (dịch vụ ngoài mesh).

Ví dụ: Chỉ cho phép web-frontend gọi đến github.com trong khi từ chối các dịch vụ khác. Điều này giúp đảm bảo bảo mật và tuân thủ chính sách truy cập.