Google Kubernetes Engine: NetworkPolicy cho phép đi ra k8s-metadata-proxy

Oct 02 2020

Bối cảnh

Tôi có một cụm Google Kubernetes Engine (GKE) với Nhận dạng khối lượng công việc được bật. Là một phần của Workload Identity, DaemonSet k8s-metadata-proxy chạy trên cụm. Tôi có một không gian tên my-namespacevà muốn từ chối tất cả lưu lượng đi ra của các nhóm trong không gian tên ngoại trừ việc đi ra DaemonSet k8s-metadata-proxy. Như vậy, tôi có NetworkPolicy sau:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: my-namespace
spec:
  # Apply to all pods.
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - ports:
    # This is needed to whitelist k8s-metadata-proxy. See https://github.com/GoogleCloudPlatform/k8s-metadata-proxy
    - protocol: TCP
      port: 988

Vấn đề

NetworkPolicy quá rộng vì nó cho phép đi ra lưu lượng TCP tới bất kỳ máy chủ nào trên cổng 988 thay vì chỉ đi ra DaemonSet k8s-metadata-proxy, nhưng tôi dường như không thể tìm ra cách chỉ định .spec.egress[0].tođể đạt được mức độ chi tiết mà tôi muốn.

Tôi đã thử các cách sau to:

  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          namespace: kube-system
    ports:
    - protocol: TCP
      port: 988
  - to:
    - ipBlock:
        cidr: <cidr of pod IP range>
    - ipBlock:
        cidr: <cidr of services IP range>
    ports:
    - protocol: TCP
      port: 988

nhưng các quy tắc này dẫn đến lưu lượng truy cập đến k8s-metadata-proxy bị chặn.

Câu hỏi

Làm cách nào tôi có thể chọn DaemonSet k8s-metadata-proxy trong tophần của quy tắc đầu ra trong a networking.k8s.io/v1/NetworkPolicy?

Trả lời

DawidKruk Oct 05 2020 at 12:55

Như tôi đã nói trong bình luận:

Xin chào. Bạn có thể thêm vào podSelector.matchLabels của định nghĩa Egress để cho phép nhóm của bạn chỉ kết nối với các Nhóm có nhãn cụ thể. Bạn có thể đọc thêm về nó tại đây: cloud.google.com/kubernetes-engine/docs/tutorials/…

Nhận xét này có thể gây hiểu lầm vì giao tiếp với gke-metadata-serverđược mô tả trong tài liệu chính thức:

  • Cloud.google.com: Kubernetes Engine: Nhận dạng khối lượng công việc: GKE-MDS

Tập trung vào phần của tài liệu trên:

Hiểu máy chủ siêu dữ liệu GKE

Máy chủ siêu dữ liệu GKE là một máy chủ siêu dữ liệu mới được thiết kế để sử dụng với Kubernetes. Nó chạy như một bộ daemonset , với một Pod trên mỗi nút cụm. Máy chủ siêu dữ liệu chặn các yêu cầu HTTP đểhttp://metadata.google.internal( 169.254.169.254:80), bao gồm các yêu cầu như GET /computeMetadata/v1/instance/service-accounts/default/tokentruy xuất mã thông báo cho tài khoản dịch vụ của Google mà Pod được định cấu hình để hoạt động. Lưu lượng truy cập vào máy chủ siêu dữ liệu không bao giờ rời khỏi phiên bản VM lưu trữ Pod.

Lưu ý : Nếu bạn có chính sách mạng cụm nghiêm ngặt , bạn phải cho phép đi ra 127.0.0.1/32 trên cổng 988 để Pod của bạn có thể giao tiếp với máy chủ siêu dữ liệu GKE.

Quy tắc chỉ cho phép lưu lượng truy cập GKE Metadata serverđược mô tả trong đoạn cuối của trích dẫn trên. Các YAMLđịnh nghĩa nên trông giống như dưới đây:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: egress-rule
  namespace: restricted-namespace # <- namespace your pod is in 
spec:
  policyTypes:
  - Egress
  podSelector:
    matchLabels:
      app: nginx # <- label used by pods trying to communicate with metadata server
  egress:
  - to:
    - ipBlock:
        cidr: 127.0.0.1/32 # <- allow communication with metadata server #1 
  - ports:
    - protocol: TCP
      port: 988 # <- allow communication with metadata server #2 

Giả sử rằng:

  • Bạn có một cụm Kubernetes với:
    • Network Policy được kích hoạt
    • Workload Identity được kích hoạt
  • Bạn Podsđang cố gắng giao tiếp từ restricted-namespacekhông gian tên

Đầu ra để mô tả cần thiết NetworkPolicy:

  • $ kubectl describe networkpolicy -n restricted-namespace egress-rule
Name:         egress-rule
Namespace:    restricted-namespace
Created on:   2020-10-04 18:31:10 +0200 CEST
Labels:       <none>
Annotations:  kubectl.kubernetes.io/last-applied-configuration:
                {"apiVersion":"networking.k8s.io/v1","kind":"NetworkPolicy","metadata":{"annotations":{},"name":"egress-rule","namespace":"restricted-name...
Spec:
  PodSelector:     app=nginx
  Allowing ingress traffic:
    <none> (Selected pods are isolated for ingress connectivity)
  Allowing egress traffic:
    To Port: <any> (traffic allowed to all ports)
    To:
      IPBlock:
        CIDR: 127.0.0.1/32
        Except: 
    ----------
    To Port: 988/TCP
    To: <any> (traffic not restricted by source)
  Policy Types: Egress

Khước từ!

Việc áp dụng các quy tắc đó sẽ từ chối tất cả lưu lượng truy cập từ các nhóm có app=nginxnhãn không được gửi đến máy chủ siêu dữ liệu!

Bạn có thể tạo và execđưa vào nhóm có nhãn app=nginxbằng cách:

kubectl run -it --rm nginx \
--image=nginx \
--labels="app=nginx" \
--namespace=restricted-namespace \
-- /bin/bash

Tiền boa!

Hình ảnh nginxđược sử dụng vì nó đã curlđược cài đặt theo mặc định!

Bằng ví dụ này, bạn sẽ không thể giao tiếp với máy chủ DNS. Bạn có thể:

  • cho phép các nhóm của bạn giao tiếp với máy chủ DNS
  • đặt envbiến cho máy chủ siêu dữ liệu (169.254.169.254)

Ví dụ về giao tiếp với GKE Metadata Server:

  • $ curl 169.254.169.254/computeMetadata/v1/instance/ -H 'Metadata-Flavor: Google'
attributes/
hostname
id
service-accounts/
zone

Các nguồn bổ sung:

  • Cloud.google.com: Compute: Lưu trữ siêu dữ liệu đang truy xuất


Để cho phép các nhóm cụ thể chỉ gửi lưu lượng đến các nhóm cụ thể trên các cổng cụ thể, bạn có thể sử dụng chính sách sau:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: egress-rule
  namespace: restricted-namespace # <- namespace of "source" pod
spec:
  policyTypes:
  - Egress
  podSelector:
    matchLabels:
      app: ubuntu # <- label for "source" pod
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: nginx # <- label for "destination" pod
  - ports:
    - protocol: TCP
      port: 80 # <- allow only port 80