一文学会calico及k8s网络策略入门

一、calico网络策略原理

1. 值

  • 外部的Kubernetes network policy

calico网络策略提供了一系列的策略能力,其中包括策略的顺序/优先级,拒绝规则和其它更灵活的匹配规则。kubernetes网络策略仅应用于Pod,而Calico网络策略可以应用于多种类型的终端,比如pods, VMs和主机接口等。 而且,当使用istio service mesh的话,那么Calico network policy还支持应用的5-7层的网络策略。

  • 写一次,应用到所有
    写一次策略,你可以应用几乎所有的云提供商中。

  • 和kubernetes 网络策略无缝的结合

你可以使用Calico 网络策略附加到Kubernetes网络策略,也可单独使用。 比如,你可以 允许开发者针对他们的微服务定义kubernetes网络策略,而允许安全团队或ops团队定义它们的calico 网络策略。

2. 功能

Calico 网络策略支持以下功能:

  • 策略可以应用任何的端点: Pods/containers,VMs,and/or host interfaces.

  • 策略可以定应用于ingress,egress或两者的规则

  • 策略规则支持:

    • Actions: allow, deny, log, pass

    • Source and destination match criteria:

      • Ports: numbered, ports in a range, and Kubernetes named ports
      • Protocols: TCP, UDP, ICMP, SCTP, UDPlite, ICMPv6, protocol numbers (1-255)
      • HTTP attributes (if using Istio service mesh)
      • ICMP attributes
      • IP version (IPv4, IPv6)
      • IP or CIDR
      • Endpoint selectors (using label expression to select pods, VMs, host interfaces, and/or network sets)
      • Namespace selectors
      • Service account selectors
  • 可选的包处理控制:在DNAT前,关闭连接追踪,应用转发策略 and/or 本地流量终止。

3. 概念

  1. 名称空间和全局网络策略
  • calico network policy是名称空间资源,它应用于那个名称空间的pods/containers/VMs。
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-tcp-6379
  namespace: production
  • calico global network policy 是非名称空间资源,它应用于任何类型的endpoint(pods, VMs, host interfaces). 是独立于名称空间的.
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: allow-tcp-port-6379
  1. kubectl vs calicoctl

请记住一点:calico network policy和calico global network policies是使用calicoctl应用的。

  1. Ingress and egress
    从endpint的视图而言(pod,VM, host interface), ingress是进入到endpint的流量,而egress是从endpoints出去的流量 。

下面是应用的关系表:

Ingress rule present? Engress rule present? Value
No No Ingress
Yes No Ingress
No Yes Egress
Yes Yes Ingress, Egress
  1. 网络策略的行为: deny and allow

Kubernetes网络政策规范定义了以下行为:

  • 如果没有网络策略应用于pod,那么从pod出去的流量或进入pod的都是允许的。

  • 如果有定义位于pod ingress rules,那么仅那些被允许的Ingress流量是放行的,其它拒绝。

  • 如果有定义位于pod egress rules,那么仅那些被允许的egress流量是放行的,其它拒绝。

为了和kuberneres兼容,calico network policy遵循善存 kubernetes pods相同的行为。针对其它endpoints的类型(VMs, host interfaces),Calico network policy是默认的拒绝。

二、启用默认的策略

  1. Enable default deny calico global network policy, non-namespaced
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: default-deny
spec:
  selector: all()
  types:
  - Ingress
  - Egress
  1. Enable default deny Calico network policy, namespaced
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: engineering
spec:
  selector: all()
  types:
  - Ingress
  - Egress
  1. Enable default deny kubernetes policy, namespaced
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: engineering
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

三、calico网络策略案例

4. 案例

  1. Control traffic to/from endpoints in a namespace

    • 实验环境构建
# 创建网络名称空间
$ kubectl create ns production

# 创建默认的策略
$ cat default-deny-for-production.yaml
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: production
spec:
  selector: all()
  types:
  - Ingress

# 应用默认的策略
$ calico apply -f default-deny-for-production.yaml

# 部署redis应用
$ cat redis-rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: redis
  namespace: production
spec:
   replicas: 1
   selector:
     color: red
   template:
     metadata:
       labels:
         color: red
     spec:
       containers:
       - name: redis
         image: redis
         ports:
         - containerPort: 6379
  • 在下面的案例中,假如来自相同的名称空间的pod,它的标签为run:access到名称空间production的标签为color:red是,且端口号为6379的是允许的。
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-tcp-6379
  namespace: production
spec:
  selector: color == 'red'
  ingress:
  - action: Allow
    protocol: TCP
    source:
      selector: run == 'access'
    destination:
      ports:
        - 6379
  • 使用如下进行测试
kubectl run --namespace=production deny --rm -ti --image busybox /bin/sh
kubectl run --namespace=production access --rm -ti --image busybox /bin/sh
  • 使用名称空间选择器的案例
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-tcp-6379
  namespace: production
spec:
  selector: color == 'red'
  ingress:
  - action: Allow
    protocol: TCP
    source:
      selector: run == 'access'
      namespaceSelector: name == 'zangxueyuan'
    destination:
      ports:
      - 6379

# 使用如下进行测试
$ kubectl label ns default name=zangxueyuan
$ kubectl run --namespace=default access --rm -ti --image busybox /bin/sh
  1. Control traffic to/from endpoints independent of namespace

案例如下:

apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: deny-blue
spec:
  selector: color == 'red'
  ingress:
  - action: Deny
    protocol: TCP
    source:
      selector: color == 'blue'
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: deny-circle-blue
spec:
  selector: color == 'red'
  ingress:
  - action: Deny
    protocol: TCP
    source:
      selector: color == 'blue'
      namespaceSelector: shape == 'circle'
  1. Control traffic to/from endpoints using IP addresses or CIDR ranges
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
  name: allow-egress-external
  namespace: production
spec:
  selector:
    color == 'red'
  types:
    - Egress
  egress:    
    - action: Deny
      destination:
        nets:
        - 1.2.3.4/24
  1. Apply network policies in specific order

应用的顺序数字从小到大:

apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: drop-other-ingress
spec:
  order: 20
  ...deny policy rules here...
apiVersion: projectcalico.org/v3
kind: GlobalNetworkPolicy
metadata:
  name: allow-cluster-internal-ingress
spec:
  order: 10
  ...allow policy rules here...
  1. 针对指定的流量产生日志
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
Metadata:
  name: allow-tcp-6379
  namespace: production
Spec:
  selector: role == 'database'
  types:
  - Ingress
  - Egress
  ingress:
  - action: Log
    protocol: TCP
    source:
      selector: role == 'frontend'
  - action: Deny
    protocol: TCP
    source:
      selector: role == 'frontend'

四、kubernetes网络策略原理

Kubernetes网络政策允许开发人员获得和他们的应用程序使用相同的简单的语言使用部署它们。开发人员可以专注于他们的应用程序不了解底层网络的概念。使开发人员能够轻松地使用网络政策确保他们的应用程序DevOps环境。

1. 功能

kubernetes Network Policy API 支持如下功能:

  • 策略作用于名称空间的范围

  • 策略仅用于那些label selectors的pods.

  • 策略规则可以指定流量 to/from pods, namespaces, or CIDRs的流量 。

  • 策略规则可以指定协议(TCP,UDP,SCTP),端口的名字或端口号码

2. 概念

kubernetes网络策略 API提供一个方式,让用户定义网络策略去控制流量 。然后,kubernetes是没有内置的网络策略的,因此,你必须使用插件的方式,比如Calico插件。

3. 动作

  1. 创建ingress policies
  • 允许相同名称空间的pods互访

案例1:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-same-namespace
  namespace: default
spec:
  podSelector:
    matchLabels:
      color: blue
  ingress:
  - from:
    - podSelector:
        matchLabels:
          color: red
    ports:
      - port: 80
  • 允许不同的名称空间的pods互访

案例2:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-same-namespace
  namespace: default
spec:
  podSelector:
    matchLabels:
      color: blue
  ingress:
  - from:
    - podSelector:
        matchLabels:
          color: red
      namespaceSelector:
        matchLabels:
          shape: square
    ports:
    - port: 80
  1. 创建egress policies
  • 允许相同名称空间的pods互访
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-egress-same-namespace
  namespace: default
spec:
  podSelector:
    matchLabels:
      color: blue
  egress:
  - to:
    - podSelector:
        matchLabels:
          color: red
    ports:
    - port: 80
  • 允许egress traffic到IP地址或CIDR块
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-egress-external
  namespace: default
spec:
  podSelector:
    matchLabels:
      color: red
  egress:
  - to:
    - ipBlock:
        cidr: 172.18.0.0/24

4. 最佳实践:创建拒绝所有的默认网络策略

  1. 创建一个默认的拒绝所有的ingress和egress网络策略
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: default-deny
  namespace: policy-demo
spec:
  podSelector:
    matchLabels: {}
  types:
  - Ingress
  - Egress

五、kubernetes策略基础案例

  1. 配置名称空间
kubectl create ns policy-demo
  1. 创建demo pods
  • policy-demo名称空间中创建一些nginx pods
kubectl create deployment nginx --namespace=policy-demo  --image=nginx --replicas=2
kubectl label pod/nginx-6799fc88d8-674ds run=access -n policy-demo
  • 通过服务暴露它们
kubectl expose --namespace=policy-demo deployment nginx --port=80
  • 确定nginx的服务是可以访问的
kubectl run --namespace=policy-demo access --rm -ti --image busybox /bin/sh

Waiting for pod policy-demo/access-472357175-y0m47 to be running, status is Pending, pod ready: false

If you don't see a command prompt, try pressing enter.

/ #
  • 在access的内部,尝试访问nginx服务。
wget -q nginx -O -
  1. 开启隔离
  • 运行下面的命令创建一个NetworkPolicy,它在policy-demo名称空间中执行默认的行为。
kubectl create -f - <
  • 测试隔离
kubectl run --namespace=policy-demo access --rm -ti --image busybox /bin/sh

Waiting for pod policy-demo/access-472357175-y0m47 to be running, status is Pending, pod ready: false

If you don't see a command prompt, try pressing enter.

/ #

wget -q --timeout=5 nginx -O -

wget: download time out
  1. 使用网络策略允许访问
    现在,让我们使用NetworkPolicy开启到nginx 服务的访问. 这只是允许从access pod进入的连接,并不是所有。
  • 创建网络策略access-nginx,内容如下:
kubectl create -f - <
  • 现在应该能够从access pod访问服务
kubectl run --namespace=policy-demo access --rm -ti --image busybox /bin/sh
  • 执行如下命令进行访问测试
wget -q --timeout=5 nginx -O -
  • 如果不是从access的pod的话,那么便不能访问,执行如下
kubectl run --namespace=policy-demo cant-access --rm -ti --image busybox /bin/sh

wget -q --timeout=5 nginx -O -
  • 清除demo的名称空间
kubectl delete ns policy-demo

六、kubernetes策略高级案例

kubernetesNetworkPolicy API 允许用户基于 labels 和 port 定义kubernetes pods ingress 和 egress.

1. 先决条件

  • calico v2.6.1+, kubernetes 1.8+

  • 可以使用kubectl 访问kubernetes集群

  • 你Kubernetes节点能够连接到公共Internet

  • 熟悉kubernetes NetworkPolicy

我们经过以下步骤测试:

  1. 创建名称空间和Nginx服务

  2. 拒绝所有ingress流量

  3. 允许ingress流量到nginx

  4. 拒绝所有egress流量

  5. 允许egress流量到kube-dns

  6. 清除名称空间

2. 创建名称空间和nginx 服务

kubectl create ns advanced-policy-demo
kubectl run --namespace=advanced-policy-demo nginx --replicas=1 --image=nginx
#kubectl expose --namespace=advanced-policy-demo deployment nginx --port=80
kubectl expose pod nginx --port=80 --name=nginx -n advanced-policy-demo
  • 校验访问 - 允许所有ingress和egress
kubectl run --namespace=advanced-policy-demo access --rm -ti --image busybox /bin/sh
  • 访问nginx的服务进行测试
wget -q --timeout=5 nginx -O -
  • 访问外网进行测试
wget -q --timeout=5 www.baidu.com -O -

3. 拒绝所有的ingress 流量

通过部署一个默认的所有Ingress流量策略,在名称空间中开启ingress 隔离。

kubectl create -f - <
  • 校验访问 - 拒绝所有ingress和允许所有egress

(1) 访问Nginx服务

wget -q --timeout=5 nginx -O -

# 返回结果
wget: download timed out

(2)尝试访问baidu.com

wget -q --timeout=5 www.baidu.com -O -

# 返回结果

4. 允许ingress流量到nginx

kubectl create -f - <
  • 校验访问-- 允许nginx ingress
wget -q --timeout=5 nginx -O -

# 返回结果如下



Welcome to nginx!...

5. 拒绝所有egress流量

kubectl create -f - <
  • 校验访问 - 拒绝所有egress
nslookup nginx

#  返回结果
Server:    10.96.0.10
Address 1: 10.96.0.10

nslookup: can't resolve 'nginx'

(2)尝试访问baidu.com

wget -q --timeout=5 www.baidu.com -O -

# 返回结果
wget: bad address 'google.com'

6. 允许DNS egress流量

运行下面的命令在kube-system名称空间上创建一个name: kube-system标签, 并且创建一个网络策略允许advanced-policy-demo名称空间中的任何pods到kube-system DNS egress流量。

kubectl label namespace kube-system name=kube-system
kubectl create -f - <
  • 校验访问 - 允许DNS访问
nslookup nginx

# 返回结果如下
Server:    10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local

nslookup baidu.com

7. 允许egress流量到nginx

创建egress 流量策略允许在advanced-policy-demo名称空间的任何pods到相同名称空间中的匹配标签 run: nginx的pods.

kubectl create -f - <
  • 校验访问- 允许egress访问到nginx
wget -q --timeout=5 nginx -O -

# 返回的结果



Welcome to nginx!...

wget -q --timeout=5 google.com -O -

# 返回的结果
wget: download timed out

8. 清空名称空间

kubectl delete ns advanced-policy-demo

七、calico在生产情况模拟

这包含构建fronted 和 backend service的demo,.

  1. 创建fronted, backend, client 和management-ui apps.
kubectl create -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/manifests/00-namespace.yaml
kubectl create -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/manifests/01-management-ui.yaml
kubectl create -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/manifests/02-backend.yaml
kubectl create -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/manifests/03-frontend.yaml
kubectl create -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/manifests/04-client.yaml
  1. 等待所有的pods处于运行状态:
kubectl get pods --all-namespaces --watch

此时应该可以通过http://:30002进行访问了。

  1. 开启隔离
  • 运行以下命令阻止所有的到fronted,backend,和client服务的访问。
kubectl create -n stars -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/policies/default-deny.yaml
kubectl create -n client -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/policies/default-deny.yaml
  • 隔离的确认

刷新管理UI,现在我们开启隔离,这个UI将不能够再次访问。

  1. 使用网络策略允许UI的访问
kubectl create -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/policies/allow-ui.yaml
kubectl create -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/policies/allow-ui-client.yaml

几秒钟后,刷新UI——它现在应该显示服务,但他们不能互相访问

  1. 创建backend-policy.yaml文件允许流量 从frontend到backend.
kubectl create -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/policies/backend-policy.yaml
  • 刷新UI,你应该能看到如下:

    • 前端现在可以访问后端(仅在TCP端口6379)。
    • 后端不能访问前端。
    • 客户端不能访问前端,也不能访问后端
  1. 暴露前端的服务给客户端名称空间
kubectl create -f https://docs.projectcalico.org/v3.11/security/tutorials/kubernetes-policy-demo/policies/frontend-policy.yaml

现在客户端可以访问前端,而不是后端。前端和后端都无法启动连接客户端。前端仍然能够访问后端。

  1. 清空demo的环境
kubectl delete ns client stars management-ui

你可能感兴趣的:(一文学会calico及k8s网络策略入门)