Network Policy

    在使用 Network Policy 时,需要注意

    • v1.6 以及以前的版本需要在 kube-apiserver 中开启
    • v1.7 版本 Network Policy 已经 GA,API 版本为 networking.k8s.io/v1
    • v1.8 版本新增 EgressIPBlock 的支持
    • 网络插件要支持 Network Policy,如 Calico、Romana、Weave Net 和 trireme 等,参考 这里

    默认情况下,所有 Pod 之间是全通的。每个 Namespace 可以配置独立的网络策略,来隔离 Pod 之间的流量。

    v1.7 + 版本通过创建匹配所有 Pod 的 Network Policy 来作为默认的网络策略,比如默认拒绝所有 Pod 之间 Ingress 通信

    默认拒绝所有 Pod 之间 Egress 通信的策略为

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: default-deny
    5. spec:
    6. podSelector: {}
    7. policyTypes:
    8. - Egress

    甚至是默认拒绝所有 Pod 之间 Ingress 和 Egress 通信的策略为

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: default-deny
    5. spec:
    6. podSelector: {}
    7. policyTypes:
    8. - Ingress
    9. - Egress

    而默认允许所有 Pod 之间 Ingress 通信的策略为

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: allow-all
    5. spec:
    6. podSelector: {}
    7. ingress:
    8. - {}

    默认允许所有 Pod 之间 Egress 通信的策略为

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: allow-all
    5. spec:
    6. podSelector: {}
    7. egress:
    8. - {}

    而 v1.6 版本则通过 Annotation 来隔离 namespace 的所有 Pod 之间的流量,包括从外部到该 namespace 中所有 Pod 的流量以及 namespace 内部 Pod 相互之间的流量:

    1. kubectl annotate ns <namespace> "net.beta.kubernetes.io/network-policy={\"ingress\": {\"isolation\": \"DefaultDeny\"}}"

    Pod 隔离

    通过使用标签选择器(包括 namespaceSelector 和 podSelector)来控制 Pod 之间的流量。比如下面的 Network Policy

    • 允许 default namespace 中带有 role=frontend 标签的 Pod 访问 default namespace 中带有 role=db 标签 Pod 的 6379 端口
    • 允许带有 project=myprojects 标签的 namespace 中所有 Pod 访问 default namespace 中带有 role=db 标签 Pod 的 6379 端口
    1. # v1.6 以及更老的版本应该使用 extensions/v1beta1
    2. # apiVersion: extensions/v1beta1
    3. apiVersion: networking.k8s.io/v1
    4. kind: NetworkPolicy
    5. metadata:
    6. name: test-network-policy
    7. namespace: default
    8. spec:
    9. podSelector:
    10. matchLabels:
    11. role: db
    12. ingress:
    13. - from:
    14. - namespaceSelector:
    15. matchLabels:
    16. project: myproject
    17. - podSelector:
    18. matchLabels:
    19. role: frontend
    20. ports:
    21. - protocol: tcp
    22. port: 6379
    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: test-network-policy
    5. namespace: default
    6. spec:
    7. podSelector:
    8. matchLabels:
    9. role: db
    10. policyTypes:
    11. - Ingress
    12. - Egress
    13. ingress:
    14. - from:
    15. - ipBlock:
    16. cidr: 172.17.0.0/16
    17. except:
    18. - namespaceSelector:
    19. matchLabels:
    20. project: myproject
    21. - podSelector:
    22. matchLabels:
    23. role: frontend
    24. ports:
    25. - protocol: TCP
    26. port: 6379
    27. - to:
    28. - ipBlock:
    29. cidr: 10.0.0.0/24
    30. ports:
    31. - protocol: TCP
    32. port: 5978

    它用来隔离 default namespace 中带有 role=db 标签的 Pod:

    • 允许 default namespace 中带有 role=frontend 标签的 Pod 访问 default namespace 中带有 role=db 标签 Pod 的 6379 端口
    • 允许带有 project=myprojects 标签的 namespace 中所有 Pod 访问 default namespace 中带有 role=db 标签 Pod 的 6379 端口
    • 允许 default namespace 中带有 role=db 标签的 Pod 访问 10.0.0.0/24 网段的 TCP 5987 端口

    以 calico 为例看一下 Network Policy 的具体用法。

    首先配置 kubelet 使用 CNI 网络插件

    安装 calio 网络插件

    1. # 注意修改 CIDR,需要跟 k8s pod-network-cidr 一致,默认为 192.168.0.0/16
    2. kubectl apply -f https://docs.projectcalico.org/v3.0/getting-started/kubernetes/installation/hosted/kubeadm/1.7/calico.yaml

    首先部署一个 nginx 服务

    1. $ kubectl run nginx --image=nginx --replicas=2
    2. deployment "nginx" created
    3. $ kubectl expose deployment nginx --port=80
    4. service "nginx" exposed

    此时,通过其他 Pod 是可以访问 nginx 服务的

    1. $ kubectl get svc,pod
    2. NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    3. svc/kubernetes 10.100.0.1 <none> 443/TCP 46m
    4. svc/nginx 10.100.0.16 <none> 80/TCP 33s
    5. NAME READY STATUS RESTARTS AGE
    6. po/nginx-701339712-e0qfq 1/1 Running 0 35s
    7. po/nginx-701339712-o00ef 1/1 Running 0
    8. $ kubectl run busybox --rm -ti --image=busybox /bin/sh
    9. Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
    10. Hit enter for command prompt
    11. / # wget --spider --timeout=1 nginx
    12. Connecting to nginx (10.100.0.16:80)
    13. / #

    开启 default namespace 的 DefaultDeny Network Policy 后,其他 Pod(包括 namespace 外部)不能访问 nginx 了:

    1. $ cat default-deny.yaml
    2. apiVersion: networking.k8s.io/v1
    3. kind: NetworkPolicy
    4. metadata:
    5. name: default-deny
    6. spec:
    7. podSelector: {}
    8. policyTypes:
    9. - Ingress
    10. $ kubectl create -f default-deny.yaml
    11. $ kubectl run busybox --rm -ti --image=busybox /bin/sh
    12. Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
    13. Hit enter for command prompt
    14. / # wget --spider --timeout=1 nginx
    15. Connecting to nginx (10.100.0.16:80)
    16. wget: download timed out
    17. / #

    最后再创建一个运行带有 access=true 的 Pod 访问的网络策略

    1. $ cat nginx-policy.yaml
    2. kind: NetworkPolicy
    3. apiVersion: networking.k8s.io/v1
    4. metadata:
    5. name: access-nginx
    6. spec:
    7. podSelector:
    8. matchLabels:
    9. run: nginx
    10. ingress:
    11. - from:
    12. - podSelector:
    13. matchLabels:
    14. access: "true"
    15. $ kubectl create -f nginx-policy.yaml
    16. networkpolicy "access-nginx" created
    17. # 不带 access=true 标签的 Pod 还是无法访问 nginx 服务
    18. $ kubectl run busybox --rm -ti --image=busybox /bin/sh
    19. Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
    20. Hit enter for command prompt
    21. / # wget --spider --timeout=1 nginx
    22. Connecting to nginx (10.100.0.16:80)
    23. wget: download timed out
    24. / #
    25. $ kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh
    26. Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
    27. Hit enter for command prompt
    28. / # wget --spider --timeout=1 nginx
    29. Connecting to nginx (10.100.0.16:80)
    30. / #

    最后开启 nginx 服务的外部访问:

    1. $ cat nginx-external-policy.yaml
    2. apiVersion: networking.k8s.io/v1
    3. kind: NetworkPolicy
    4. metadata:
    5. name: front-end-access
    6. namespace: sock-shop
    7. spec:
    8. podSelector:
    9. matchLabels:
    10. run: nginx
    11. ingress:
    12. - ports:
    13. - protocol: TCP
    14. port: 80
    15. $ kubectl create -f nginx-external-policy.yaml
    1. kubectl run web --image=nginx --labels app=web,env=prod --expose --port 80

    网络策略

    只允许指定 Pod 访问服务

    1. kubectl run apiserver --image=nginx --labels app=bookstore,role=api --expose --port 80

    网络策略

    1. kind: NetworkPolicy
    2. apiVersion: networking.k8s.io/v1
    3. metadata:
    4. name: api-allow
    5. spec:
    6. podSelector:
    7. matchLabels:
    8. app: bookstore
    9. role: api
    10. ingress:
    11. - from:
    12. - podSelector:
    13. matchLabels:
    14. app: bookstore

    NetworkPolicy - 图3

    1. apiVersion: networking.k8s.io/v1
    2. kind: NetworkPolicy
    3. metadata:
    4. name: default-deny
    5. namespace: default
    6. spec:
    7. podSelector: {}

    禁止其他 namespace 访问服务

    1. kubectl create namespace secondary
    2. kubectl run web --namespace secondary --image=nginx \
    3. --labels=app=web --expose --port 80

    网络策略

    1. kind: NetworkPolicy
    2. apiVersion: networking.k8s.io/v1
    3. metadata:
    4. namespace: secondary
    5. name: web-deny-other-namespaces
    6. spec:
    7. podSelector:
    8. matchLabels:
    9. ingress:
    10. - from:
    11. - podSelector: {}
    1. kubectl run web --image=nginx \
    2. --labels=app=web --expose --port 80

    NetworkPolicy - 图5

    网络策略

    1. kind: NetworkPolicy
    2. apiVersion: networking.k8s.io/v1
    3. metadata:
    4. name: web-allow-prod
    5. spec:
    6. podSelector:
    7. matchLabels:
    8. app: web
    9. ingress:
    10. - from:
    11. - namespaceSelector:
    12. matchLabels:
    13. purpose: production

    允许外网访问服务

    1. kind: NetworkPolicy
    2. apiVersion: networking.k8s.io/v1
    3. metadata:
    4. name: web-allow-external
    5. spec:
    6. podSelector:
    7. matchLabels:
    8. app: web
    9. ingress:
    10. - ports:
    11. - port: 80
    12. from: []