Network policies in ACS clusters

更新时间:
复制 MD 格式

Alibaba Cloud Container Compute Service (ACS) lets you implement policy-based network control with Kubernetes NetworkPolicy. Use network policies to control network traffic at the IP address or port level for specific applications in your cluster. This topic explains how to use network policies in an ACS cluster and provides common use cases.

Applicability

  • Only general-purpose and compute-optimized CPU pods are supported.

  • Only IPv4 is supported.

Notes

  • NetworkPolicy rules allow you to select namespaces or pods using a LabelSelector. However, applying more NetworkPolicies to a pod increases the time it takes for the rules to take effect. Many NetworkPolicy rules can also complicate cluster management and troubleshooting. Therefore, keep the number of NetworkPolicies in your cluster under 40.

Step 1: Enable NetworkPolicy

  1. Install the Poseidon component.

    1. Log on to the ACS console. In the left navigation pane, click Clusters.

    2. On the Clusters page, click the name of the target cluster. In the left navigation pane, click Add-ons.

    3. On the Component management page, click the Network tab. On the Poseidon card, click Install.

    4. On the Install Component Poseidon page, select Enable NetworkPolicy, and then click Confirm.

      After the component is installed, Installed appears in the upper-right corner of the card.

  2. Enable NetworkPolicy in the Pod annotation.

    To enable NetworkPolicy for a Pod, add the following annotation to its metadata: network.alibabacloud.com/enable-network-policy-agent: "true" .

    apiVersion: v1
    kind: Pod
    metadata:
      annotations:
        network.alibabacloud.com/enable-network-policy-agent: "true"
      name: example
      namespace: default
    spec:
      containers:
      - image: nginx
        imagePullPolicy: IfNotPresent
        name: example

Step 2: Create an Nginx test application

kubectl

  1. Obtain the kubeconfig file of the cluster and use kubectl to connect to the cluster.

  2. Create an Nginx application and communicate with it through a Service named nginx.

    Create the Nginx application:

    kubectl run nginx --image=nginx

    Expected output:

    pod/nginx created

    Check the pod status:

    kubectl get pod

    Expected output:

    NAME                     READY   STATUS    RESTARTS   AGE
    nginx                    1/1     Running   0          45s

    Create a Service named nginx:

    kubectl expose pod nginx --port=80

    Expected output:

    service/nginx exposed

    View the Service:

    kubectl get service

    Expected output:

    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   172.XX.XX.1     <none>        443/TCP   30m
    nginx        ClusterIP   172.XX.XX.48    <none>        80/TCP    12s
  3. Create a Pod named busybox and access a Service named nginx.

    kubectl run busybox --rm -ti --image=registry.cn-hangzhou.aliyuncs.com/acs/busybox:v1.29.2 /bin/sh

    Expected output:

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

    Test access to Nginx:

    If you don't see a command prompt, try pressing enter.
    / #
    / # wget nginx  # Enter wget nginx here.

    Expected output:

    Connecting to nginx (172.XX.XX.48:80)
    saving to 'index.html'
    index.html           100% |****************************************************************************************************************************************************|   612  0:00:00 ETA
    'index.html' saved

Step 3: Use a network policy

You can use network policies in the following scenarios as needed.

Scenario 1: Allow access by label

kubectl

  1. Use the following YAML template and run the commandvim policy.yaml to create thepolicy.yaml file.

    vim policy.yaml

    The following is the content of the YAML file.

    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: access-nginx
    spec:
      podSelector:
        matchLabels:
          run: nginx
      ingress:
      - from:
        - podSelector:
            matchLabels:
              access: "true"
  2. Create a network policy from the policy.yaml file.

    kubectl apply -f policy.yaml 

    Expected output:

    networkpolicy.networking.k8s.io/access-nginx created
  3. When no access labels are defined, requests to the Service named nginx will time out and fail.

    kubectl run busybox --rm -ti --image=registry.cn-hangzhou.aliyuncs.com/acs/busybox:v1.29.2 /bin/sh

    Test access to the Service named nginx:

    wget nginx

    Expected output:

    Connecting to nginx (172.19.XX.XX:80)
    wget: can't connect to remote host (172.19.XX.XX): Connection timed out
  4. Define access labels.

    kubectl run busybox --rm -ti --labels="access=true" --image=registry.cn-hangzhou.aliyuncs.com/acs/busybox:v1.29.2 /bin/sh

    Test the Nginx Service:

    wget nginx

    Expected output:

    Connecting to nginx (172.21.XX.XX:80)
    saving to 'index.html'
    index.html           100% |****************************************************************************************************************************************************|   612  0:00:00 ETA
    'index.html' saved

    A 100% progress indicates a successful connection to the Nginx service.

Scenario 2: Restrict access by source CIDR block

kubectl

  1. Create an Alibaba Cloud SLB service for the Nginx application and set type=LoadBalancer to expose the Nginx service to the internet.

    vim nginx-service.yaml

    The following is the content for the nginx-service.yaml file.

    # Paste the following YAML content into nginx-service.yaml.
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        run: nginx
      name: nginx-slb
    spec:
      externalTrafficPolicy: Local
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        run: nginx
      type: LoadBalancer

    Create the service from the nginx-service.yaml file.

    kubectl apply -f nginx-service.yaml 

    Expected output:

    service/nginx-slb created

    Check if the application exposes the Nginx service:

    kubectl get service nginx-slb

    Expected output:

    NAME        TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
    nginx-slb   LoadBalancer   172.19.xx.xxx   47.110.xxx.xxx   80:32240/TCP   8m
  2. Access the SLB instance's IP address, 47.110.xxx.xxx. The connection fails.

    wget 47.110.xxx.xxx

    Expected output:

    --2018-11-21 11:46:05--  http://47.110.xx.xxx/
    Connecting to 47.110.XX.XX:80... failed: Connection refused.
    Note

    The connection fails for the following reasons:

    • The network policy only allows access from applications with the label access=true.

    • Traffic from the SLB IP address originates outside the cluster. The current network policy only allows traffic from pods with a specific label, not external traffic.

    Solution: Modify the network policy to add the allowed source CIDR block.

  3. Check the IP address of your local machine.

    curl myip.ipip.net

    Expected output:

    Current IP: 10.0.x.x From: China Beijing Beijing # This is an example. The actual output from your device may vary.
  4. Modify the policy.yaml file that you created.

    vim policy.yaml

    Modify the policy.yaml file as follows:

    # The following is the content of the YAML file.
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: access-nginx
    spec:
      podSelector:
        matchLabels:
          run: nginx
      ingress:
      - from:
        - podSelector:
            matchLabels:
              access: "true"
        - ipBlock:
            cidr: 100.64.0.0/10
        - ipBlock:
            cidr: 10.0.0.1/24      # Your local IP address. This is an example. Your actual address may vary.

    Apply the updated policy:

    kubectl apply -f policy.yaml 

    Expected output:

    networkpolicy.networking.k8s.io/access-nginx unchanged
    Note
    • Some networks have multiple egress IP addresses. Use a /24 address range in this case.

    • SLB health check addresses are in the 100.64.0.0/10 address block. Therefore, you must configure 100.64.0.0/10.

  5. Run a test pod to access the Nginx service.

    kubectl run busybox --rm -ti --labels="access=true" --image=registry.cn-hangzhou.aliyuncs.com/acs/busybox:v1.29.2 /bin/sh

    Access the Nginx service:

    wget 47.110.XX.XX

    Expected output:

    Connecting to 47.110.XX.XX (47.110.XX.XX:80)
    index.html           100% |***********************************************************|   612  0:00:00 ETA

    A progress of 100% indicates a successful connection to the Nginx service.

Scenario 3: Restrict pod access to specific addresses

Kubectl

  1. Resolve the www.aliyun.com domain.

    dig +short www.aliyun.com

    Expected output:

    www-jp-de-intl-adns.aliyun.com.
    www-jp-de-intl-adns.aliyun.com.gds.alibabadns.com.
    v6wagbridge.aliyun.com.
    v6wagbridge.aliyun.com.gds.alibabadns.com.
    106.XX.XX.21
    140.XX.XX.4
    140.XX.XX.13
    140.XX.XX.3
  2. Create the busybox-policy file.

    vim busybox-policy.yaml

    The busybox-policy.yaml file contains the following:

    # The following is the content of the YAML file.
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: busybox-policy
    spec:
      podSelector:
        matchLabels:
          run: busybox
      egress:
      - to:
        - ipBlock:
            cidr: 106.XX.XX.21/32
        - ipBlock:
            cidr: 140.XX.XX.4/32
        - ipBlock:
            cidr: 140.XX.XX.13/32
        - ipBlock:
            cidr: 140.XX.XX.3/32
      - to:
        - ipBlock:
            cidr: 0.0.0.0/0
        - namespaceSelector: {}
        ports:
        - protocol: UDP
          port: 53
    Note

    The egress rule in the busybox-policy.yaml file restricts the application's outbound access. To ensure DNS resolution works, the policy must also allow UDP requests on port 53.

  3. Create a network policy from the busybox-policy.yaml file.

    kubectl apply -f busybox-policy.yaml 

    Expected output:

    networkpolicy.networking.k8s.io/busybox-policy created
  4. Create a busybox pod to test the policy.

    kubectl run busybox --rm -ti --image=registry.cn-hangzhou.aliyuncs.com/acs/busybox:v1.29.2 /bin/sh

    Try to access a website other than www.aliyun.com, for example, www.taobao.com:

    wget www.taobao.com

    Expected output:

    Connecting to www.taobao.com (64.13.XX.XX:80)
    wget: can't connect to remote host (64.13.XX.XX): Connection timed out

    The message can't connect to remote host indicates that access to the service was denied.

  5. Try to access www.aliyun.com.

    wget www.aliyun.com

    Expected output:

    Connecting to www.aliyun.com (140.205.XX.XX:80)
    Connecting to www.aliyun.com (140.205.XX.XX:443)
    wget: note: TLS certificate validation not implemented
    index.html           100% |***********************************************************|  462k  0:00:00 ETA

    The 100% completion status indicates a successful connection.

Use case 4: Control public network access for Pods

Note

This operation might affect online services that are accessing the public network. We recommend that you perform the following steps in an empty namespace.

kubectl

  1. Create a test namespace to verify the restriction.

    Create a namespace named test-np.

    kubectl create ns test-np

    Expected output:

    namespace/test-np created
  2. Set a default network policy for this namespace that only allows outbound traffic to the private network.

    vim default-deny.yaml

    Create a file named default-deny.yaml with the following content:

    # The following is the content of the YAML file.
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      namespace: test-np
      name: deny-public-net
    spec:
      podSelector: {}
      ingress:
      - from:
        - ipBlock:
            cidr: 0.0.0.0/0
      egress:
      - to:
        - ipBlock:
            cidr: 192.168.0.0/16
        - ipBlock:
            cidr: 172.16.0.0/12
        - ipBlock:
            cidr: 10.0.0.0/8

    Create the network policy from the default-deny.yaml file.

    kubectl apply -f default-deny.yaml

    Expected output:

    networkpolicy.networking.k8s.io/deny-public-net created

    View the network policy:

    kubectl get networkpolicy -n test-np

    Expected output:

    NAME                              POD-SELECTOR          AGE
    deny-public-net                   <none>                1m
  3. Allow Pods with a specific label to access the public network.

    vim allow-specify-label.yaml

    An example label is public-network=true.

    # The following is the content of the YAML file.
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: allow-public-network-for-labels
      namespace: test-np
    spec:
      podSelector:
        matchLabels:
          public-network: "true"
      ingress:
      - from:
        - ipBlock:
            cidr: 0.0.0.0/0
      egress:
      - to:
        - ipBlock:
            cidr: 0.0.0.0/0
        - namespaceSelector:
            matchLabels:
              ns: kube-system

    Run the following command to create the network policy:

    kubectl apply -f allow-specify-label.yaml

    Expected output:

    networkpolicy.networking.k8s.io/allow-public-network-for-labels created

    View the network policy:

    kubectl get networkpolicy -n test-np

    Expected output:

    NAME                              POD-SELECTOR          AGE
    allow-public-network-for-labels   public-network=true    1m
    deny-public-net                   <none>                 3m
  4. Verify that a Pod without the specific label cannot access the public network.

    kubectl run -it --namespace test-np --rm --image=registry.cn-hangzhou.aliyuncs.com/acs/busybox:v1.29.2  busybox-intranet
    ping aliyun.com

    Expected output:

    PING aliyun.com (106.11.2xx.xxx): 56 data bytes
    ^C
    --- aliyun.com ping statistics ---
    9 packets transmitted, 0 packets received, 100% packet loss

    The message 0 packets received indicates that access failed.

    Note

    Access fails because the deny-public-net network policy blocks public network access by default for all Pods in the test-np namespace.

  5. Verify that a Pod with the public-network=true label can access the public network.

    kubectl run -it --namespace test-np --labels public-network=true --rm --image registry.cn-hangzhou.aliyuncs.com/acs/busybox:v1.29.2  busybox-internet
    ping aliyun.com

    Expected output:

    PING aliyun.com (106.11.1xx.xx): 56 data bytes
    64 bytes from 106.11.1xx.xx: seq=0 ttl=47 time=4.235 ms
    64 bytes from 106.11.1xx.xx: seq=1 ttl=47 time=4.200 ms
    64 bytes from 106.11.1xx.xx: seq=2 ttl=47 time=4.182 ms
    ^C
    --- aliyun.com ping statistics ---
    3 packets transmitted, 3 packets received, 0% packet loss
    round-trip min/avg/max = 4.182/4.205/4.235 ms

    The message 0% packet loss indicates successful access to the public network.

    Note

    Access is successful because the allow-public-network-for-labels network policy grants public network access to Pods with the public-network=true label, such as the busybox-internet Pod.