Kubernetes Network Policies và Bảo Mật Mạng

Môi trường thử nghiệm

Cài đặt môi trường cơ bản

Tạo các namespace và pod để kiểm tra:

[root@master01 networktest]# vi namespace-test-01.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: test-ns-01
  labels:
    environment: test-ns-01

[root@master01 networktest]# vi namespace-test-02.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: test-ns-02
  labels:
    environment: test-ns-02

[root@master01 networktest]# vi namespace-test-03.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: test-ns-03
  labels:
    environment: test-ns-03

[root@master01 networktest]# vi namespace-test-04.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: test-ns-04
  labels:
    environment: test-ns-04

[root@master01 networktest]# vi pod-alpha.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-alpha
  namespace: test-ns-01
  labels:
    application: pod-alpha
spec:
  containers:
  - name: container-alpha
    image: nginx:alpine
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

[root@master01 networktest]# vi pod-beta.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-beta
  namespace: test-ns-01
  labels:
    application: pod-beta
spec:
  containers:
  - name: container-beta
    image: nginx:alpine
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

[root@master01 networktest]# vi pod-gamma.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-gamma
  namespace: test-ns-01
  labels:
    application: pod-gamma
spec:
  containers:
  - name: container-gamma
    image: nginx:alpine
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

[root@master01 networktest]# vi pod-delta.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-delta
  namespace: test-ns-02
  labels:
    application: pod-delta
spec:
  containers:
  - name: container-delta
    image: nginx:alpine
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

[root@master01 networktest]# vi pod-epsilon.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-epsilon
  namespace: test-ns-03
  labels:
    application: pod-epsilon
spec:
  containers:
  - name: container-epsilon
    image: nginx:alpine
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

[root@master01 networktest]# vi pod-zeta.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-zeta
  namespace: test-ns-04
  labels:
    application: pod-zeta
spec:
  containers:
  - name: container-zeta
    image: nginx:alpine
    imagePullPolicy: IfNotPresent
  restartPolicy: Always

[root@master01 networktest]# kubectl apply -f .

Kiểm tra trạng thái các pod đã được tạo:

[root@master01 networktest]# kubectl -n test-ns-01 get pods -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
pod-alpha  1/1     Running   0          30s   10.20.10.150   worker01   <none>           <none>
pod-beta   1/1     Running   0          30s   10.20.30.200   worker02   <none>           <none>
pod-gamma  1/1     Running   0          30s   10.20.30.201   worker02   <none>           <none>

[root@master01 networktest]# kubectl -n test-ns-02 get pods -o wide
NAME        READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
pod-delta   1/1     Running   0          25s   10.20.30.202   worker02   <none>           <none>

[root@master01 networktest]# kubectl -n test-ns-03 get pods -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP           NODE       NOMINATED NODE   READINESS GATES
pod-epsilon  1/1     Running   0          20s   10.20.10.151 worker01   <none>           <none>

[root@master01 networktest]# kubectl -n test-ns-04 get pods -o wide
NAME      READY   STATUS    RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
pod-zeta  1/1     Running   0          15s   10.20.30.203   worker02   <none>           <none>

Kiểm tra kết nối mạng

[root@master01 networktest]# kubectl -n test-ns-01 exec -ti pod-alpha -- /bin/sh
# ping -c 1 10.20.30.200
PING 10.20.30.200 (10.20.30.200) 56(84) bytes of data.
64 bytes from 10.20.30.200: icmp_seq=1 ttl=62 time=0.450 ms

--- 10.20.30.200 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.450/0.450/0.450/0.000 ms

# ping -c 1 10.20.30.201
PING 10.20.30.201 (10.20.30.201) 56(84) bytes of data.
64 bytes from 10.20.30.201: icmp_seq=1 ttl=62 time=0.380 ms

--- 10.20.30.201 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.380/0.380/0.380/0.000 ms

# ping -c 1 10.20.30.202
PING 10.20.30.202 (10.20.30.202) 56(84) bytes of data.
64 bytes from 10.20.30.202: icmp_seq=1 ttl=63 time=0.120 ms

--- 10.20.30.202 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.120/0.120/0.120/0.000 ms

# ping -c 1 10.20.10.151
PING 10.20.10.151 (10.20.10.151) 56(84) bytes of data.
64 bytes from 10.20.10.151: icmp_seq=1 ttl=62 time=0.420 ms

--- 10.20.10.151 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.420/0.420/0.420/0.000 ms

# ping -c 1 10.20.30.203
PING 10.20.30.203 (10.20.30.203) 56(84) bytes of data.
64 bytes from 10.20.30.203: icmp_seq=1 ttl=63 time=0.090 ms

--- 10.20.30.203 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.090/0.090/0.090/0.000 ms

Chính sách bảo mật mạng

Cấu hình chính sách

[root@master01 networktest]# vi net-policy-example.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: net-policy-example
  namespace: test-ns-01
spec:
  podSelector:
    matchLabels:
      application: pod-alpha
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 10.20.0.0/16
        except:
        - 10.20.30.0/24
    - namespaceSelector:
        matchLabels:
          environment: test-ns-03
    - podSelector:
        matchLabels:
          application: pod-beta
    ports:
    - protocol: TCP
      port: 80
  egress:
  - to:
    - ipBlock:
        cidr: 10.20.30.0/24
    ports:
    - protocol: TCP
      port: 80

[root@master01 networktest]# kubectl apply -f net-policy-example.yaml

Giải thích chi tiết:

  • Trường bắt buộc: Tương tự như các chính sách bảo mật khác trong Kubernetes, tài nguyên NetworkPolicy cần có các trường apiVersion, kind và metadata.
  • spec: phần spec của NetworkPolicy chứa toàn bộ thông tin cần thiết để định nghĩa chính sách mạng cụ thể trong một namespace.
  • podSelector: Mỗi NetworkPolicy bao gồm một podSelector để chọn nhóm Pod mà chiến lược này áp dụng. podSelector trống nghĩa là khớp với tất cả Pod trong namespace.
  • policyTypes: Mỗi NetworkPolicy chứa danh sách policyTypes bao gồm Ingress hoặc Egress hoặc cả hai. Trường policyTypes biểu thị liệu chiến lược này được áp dụng cho lưu lượng vào Pod được chọn hay lưu lượng ra khỏi Pod được chọn, hoặc cả hai. Nếu không chỉ định policyTypes thì mặc định luôn đặt Ingress; nếu NetworkPolicy có bất kỳ quy tắc xuất nào thì phải cấu hình Egress.
  • ingress: Mỗi NetworkPolicy có thể chứa danh sách các quy tắc ingress dưới dạng danh sách trắng. Mỗi quy tắc cho phép lưu lượng đồng thời khớp với phần from và ports.
  • egress: Mỗi NetworkPolicy có thể chứa danh sách các quy tắc egress dưới dạng danh sách trắng. Mỗi quy tắc cho phép lưu lượng khớp với phần to và port.

Chính sách mạng trên có nghĩa:

  • Cách ly Pod có nhãn application=pod-alpha trong namespace test-ns-01, tức là cách ly pod-alpha;
  • Quy tắc Ingress cho phép các Pod sau kết nối đến cổng TCP 80 của tất cả Pod có nhãn application=pod-alpha trong namespace test-ns-01:
    • Cho phép tất cả Pod có nhãn application=pod-alpha trong namespace test-ns-01 vào;
    • Cho phép tất cả Pod trong namespace có nhãn environment=test-ns-03 vào;
    • Cho phép phạm vi địa chỉ IP ngoại trừ 10.20.30.0/24 trong toàn bộ 10.20.0.0/16 vào.
  • Quy tắc Egress cho phép kết nối từ bất kỳ Pod nào có nhãn application=pod-alpha trong namespace test-ns-01 đến cổng TCP 80 trong dải CIDR 10.0.0.0/16.

Thử nghiệm chính sách

Thử nghiệm hướng Ingress

  • Pod có IP 10.20.30.0/24 (ví dụ: pod-delta) truy cập pod-alpha (10.20.10.150):
[root@master01 ~]# kubectl -n test-ns-02 exec -ti pod-delta -- /bin/sh
/ # wget -O- -q http://10.20.10.150:80            # Theo chính sách nên bị chặn
  • Pod có IP 10.20.0.0/16 (ví dụ: pod-gamma) truy cập pod-alpha (10.20.10.150):
[root@master01 ~]# kubectl -n test-ns-01 exec -ti pod-gamma -- /bin/sh
/ # wget -O- -q http://10.20.10.150:80            # Theo chính sách nên thành công
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
  • Tất cả Pod trong namespace test-ns-03 (ví dụ: pod-epsilon) truy cập pod-alpha (10.20.10.150):
[root@master01 ~]# kubectl -n test-ns-03 exec -ti pod-epsilon -- /bin/sh
/ # wget -O- -q http://10.20.10.150:80            # Theo chính sách nên thành công
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
  • Tất cả Pod có nhãn application=pod-beta (ví dụ: pod-beta) truy cập pod-alpha (10.20.10.150):
[root@master01 ~]# kubectl -n test-ns-01 exec -ti pod-beta -- /bin/sh
/ # wget -O- -q http://10.20.10.150:80            # Theo chính sách nên thành công
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

Thử nghiệm hướng Egress

  • pod-alpha truy cập Pod có IP 10.20.30.0/24 (ví dụ: pod-zeta):
[root@master01 ~]# kubectl -n test-ns-01 exec -ti pod-alpha -- /bin/sh
/ # wget -O- -q http://10.20.30.202:80            # Theo chính sách nên thành công
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
/ # wget -O- -q http://10.20.30.203:80            # Theo chính sách nên thành công
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
/ # wget -O- -q http://10.20.10.151:80            # Theo chính sách nên bị chặn

Hành vi của to và from

Có bốn loại selector có thể được chỉ định trong phần from của ingress hoặc phần to của egress:

  • podSelector: Selector này sẽ chọn các Pod cụ thể trong cùng namespace với NetworkPolicy. Trong phần from của ingress, điều này biểu thị việc cho phép các Pod được chọn bởi selector này làm nguồn lưu lượng vào. Trong phần to của egress, điều này biểu thị việc cho phép lưu lượng ra đến các Pod được chọn bởi selector này (tức là Pod được chọn bởi podSelector là đích đến).
  • namespaceSelector: Selector này sẽ chọn các namespace cụ thể, sử dụng tất cả các Pod như nguồn lưu lượng vào hoặc đích đến lưu lượng ra.
  • namespaceSelector và podSelector: Một mục nhập to/from chỉ định cả namespaceSelector và podSelector chọn các Pod cụ thể trong namespace cụ thể.
    • Ví dụ 1: Chỉ cho phép yêu cầu vào từ Pod cụ thể có nhãn role=client trong namespace có nhãn user=alice.
      ...
      ingress:
      - from:
        - namespaceSelector:
            matchLabels:
              user: alice
          podSelector:
            matchLabels:
              role: client
      ...
    
    • Ví dụ 2: Cho phép yêu cầu vào từ bất kỳ Pod nào trong namespace có nhãn user=xhyns hoặc từ Pod có nhãn role=xhyuser trong namespace nơi chiến lược này nằm.
      ...
      ingress:
      - from:
        - namespaceSelector:
            matchLabels:
              user: xhyns
        - podSelector:
            matchLabels:
              role: xhyuser
      ...
    
  • ipBlock: Selector này sẽ chọn dải IP CIDR cụ thể để làm nguồn lưu lượng vào hoặc đích đến lưu lượng ra. Thường là IP bên ngoài cluster, vì IP Pod thường được tạo ngẫu nhiên nên việc sử dụng đoạn IP Pod không thực sự có ý nghĩa.

Chính sách mặc định

Theo mặc định, nếu không có chính sách nào tồn tại trong namespace, tất cả lưu lượng vào và ra khỏi Pod trong namespace đó đều được cho phép. Có thể thay đổi hành vi mặc định trong namespace bằng các cách sau:

  • Từ chối tất cả lưu lượng vào theo mặc định Vô hiệu hóa lưu lượng vào tất cả Pod trong namespace test-ns-01, tức là từ chối mặc định tất cả lưu lượng vào bất kỳ Pod nào trong namespace test-ns-01.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-ingress
  namespace: test-ns-01
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Chiến lược này có thể được sử dụng như chiến lược khớp cuối cùng, đảm bảo rằng ngay cả khi container không khớp với bất kỳ NetworkPolicy nào khác, nó vẫn có thể được cách ly. Chiến lược này không thay đổi hành vi cách ly lưu lượng ra mặc định.

  • Cho phép tất cả lưu lượng vào theo mặc định Cho phép lưu lượng vào tất cả Pod trong namespace test-ns-01, tức là cho phép mặc định tất cả lưu lượng vào bất kỳ Pod nào trong namespace test-ns-01.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-ingress
  namespace: test-ns-01
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - {}
  • Từ chối tất cả lưu lượng ra theo mặc định Vô hiệu hóa lưu lượng ra từ tất cả Pod trong namespace test-ns-01, tức là vô hiệu hóa mặc định lưu lượng ra từ bất kỳ Pod nào trong namespace test-ns-01.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-egress
  namespace: test-ns-01
spec:
  podSelector: {}
  policyTypes:
  - Egress
  • Cho phép tất cả lưu lượng ra theo mặc định Cho phép lưu lượng ra từ tất cả Pod trong namespace test-ns-01, tức là cho phép mặc định lưu lượng ra từ bất kỳ Pod nào trong namespace test-ns-01.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-egress
  namespace: test-ns-01
spec:
  podSelector: {}
  egress:
  - {}
  policyTypes:
  - Egress

Sau khi khớp với chiến lược này, đảm bảo rằng ngay cả khi thêm các chiến lược khiến một số Pod được coi là "cách ly", vẫn có thể cho phép rõ ràng tất cả lưu lượng ra khỏi namespace này.

  • Từ chối tất cả lưu lượng vào và ra theo mặc định Vô hiệu hóa tất cả lưu lượng vào và ra khỏi namespace test-ns-01.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

Chiến lược này có thể được sử dụng như chiến lược khớp cuối cùng, đảm bảo rằng ngay cả những Pod không được chọn bởi bất kỳ NetworkPolicy nào khác cũng sẽ không được phép nhận lưu lượng vào hoặc ra.

Thẻ: Kubernetes network-policy Security Networking container-security

Đăng vào ngày 13 tháng 9 lúc 11:44