This topic describes how to use network policies of Alibaba Cloud Container Service for Kubernetes (ACK) for access control.

Prerequisites

Before you configure network policies, make sure that you have completed the following steps:

Test whether an NGINX service can be accessed by other pods.

  1. Run the following command to create an NGINX application. Then, create an NGINX service that external clients can use to access the NGINX application.
    kubectl run nginx --image=nginx
    # Output:
    deployment.apps/nginx created
    
    kubectl get pod
    # Output:
    NAME                     READY   STATUS    RESTARTS   AGE
    nginx-64f497f8fd-z****   1/1     Running   0          45s
    
    kubectl expose deployment nginx --port=80
    # Output:
    service/nginx exposed
    
    kubectl get service
    # Output:
    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   172.XX.XX.1     <none>        443/TCP   3h
    nginx        ClusterIP   172.XX.XX.48    <none>        80/TCP    10s
  2. Run the following command to create a pod named busybox. Then, use the pod to access the NGINX service that is created in Step 1.
    kubectl run busybox --rm -ti --image=busybox /bin/sh
    # Output:
    kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl create instead.
    If you don't see a command prompt, try pressing enter.
    / # wget nginx
    Connecting to nginx (172.19.8.48:80)
    index.html           100% |***************************************************************************************************|   612  0:00:00 ETA
    / #

Configure a network policy to make the NGINX service accessible to only applications with a specified label.

  1. Run the following command to create a policy.yaml file.
    vim policy.yaml
    # Copy the following content to 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. Run the following command to create a network policy based on the policy.yaml file created in Step 1.
    kubectl apply -f policy.yaml 
    # Output:
    networkpolicy.networking.k8s.io/access-nginx created
  3. Run the following command to access the NGINX service. A connection timeout is returned because the pod is not attached with the specified label.
    kubectl run busybox --rm -ti --image=busybox /bin/sh
    # Output:
    If you don't see a command prompt, try pressing enter.
    / # wget nginx
    Connecting to nginx (172.19.8.48:80)
    wget: can't connect to remote host (172.19.8.48): Connection timed out
    / #
  4. Run the following command to attach the specified label to the pod and test whether the NGINX service can be accessed.
    kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh
    # Output:
    If you don't see a command prompt, try pressing enter.
    / # wget nginx
    Connecting to nginx (172.19.8.48:80)
    index.html           100% |***************************************************************************************************|   612  0:00:00 ETA
    / #
    If the output shows 100%, this indicates that the pod can access the NGINX service as expected.

Configure a network policy to limit IP addresses that can access a public-facing Server Load Balancer (SLB) service over the Internet.

  1. Run the following command to create an SLB service for the preceding NGINX application and set the service type to LoadBalancer. This makes the NGINX service accessible over the Internet.
    vim nginx-service.yaml
    # Copy the following content to the YAML file:
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        run: nginx
      name: nginx-nas
    spec:
      externalTrafficPolicy: Local
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        run: nginx
      type: LoadBalancer
    
    kubectl apply -f nginx-service.yaml 
    # Output:
    service/nginx-slb created
    
    kubectl get service nginx-slb
    # 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. Run the following command to connect to the IP address of the created SLB service: 47.110.xxx.xxx. The output shows that the connection request is denied.
    wget 47.110.xxx.xxx
    # Output:
    --2018-11-21 11:46:05--  http://47.110.xx.xxx/
    Connecting to 47.110.XX.XX:80... failed: Connection refused.
    Note
    Cause of the connection failure:
    • The NGINX service can be accessed by only applications labeled with access=true.
    • The requester is not allowed to access the NGINX service because the IP address of the requester is an external IP address to the ACK cluster. Only specified IP addresses are allowed to access the NGINX service over the Internet. This is different from the way using a network policy to allow only applications with a specified label to access an NGINX service.

    Solution: modify the network policy to allow the IP address of the requester to access the NGINX service.

  3. Run the following command to query the IP address of the requester.
    curl myip.ipip.net
    # Output:
    IP address: 10.0.x.x. From: China Beijing Beijing        # This is an example. Use the actual IP address.
  4. Run the following command to modify the policy.yaml file.
    vim policy.yaml
    # Copy the following content to 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      # This is an example. Use the actual IP address.
    
    kubectl apply -f nginx.yaml 
    # Output:
    networkpolicy.networking.k8s.io/access-nginx unchanged
    Note
    • The request may come from different IP addresses. Therefore, specify a CIDR block with a prefix length of 24.
    • The IP address used by the Server Load Balancer service for health checks is within the 100.64.0.0/10 CIDR block. Therefore, make sure that you have also specified 100.64.0.0/10.
  5. Run the following command to test whether the NGINX service can be accessed.
    kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh
    # Output:
    If you don't see a command prompt, try pressing enter.
    / # wget 47.110.XX.XX
    Connecting to 47.110.XX.XX (47.110.XX.XX:80)
    index.html           100% |***********************************************************|   612  0:00:00 ETA
    / #
    If the output shows 100%, this indicates that the NGINX service can be accessed.

Create a network policy to allow a pod to access only www.aliyun.com

  1. Run the following command to query IP addresses to which the domain name www.aliyun.com is resolved.
    dig +short www.aliyun.com
    # 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. Run the following command to create a busybox-policy file.
    vim busybox-policy.yaml
    # Copy the following content to the YAML file:
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: busybox-runc
    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
        ports:
        - protocol: UDP
          port: 53
    Note Egress rules are configured in the busybox-policy file to restrict the external services that the application can access. You must specify a User Datagram Protocol (UDP) port. Otherwise, the domain name cannot be resolved to IP addresses.
  3. Run the following command to create a network policy based on the busybox-policy file.
    kubectl apply -f busybox-policy.yaml 
    # Output:
    networkpolicy.networking.k8s.io/busybox-policy created
  4. Run the following command to access a website other than www.aliyun.com, for example, www.taobao.com.
    kubectl run busybox --rm -ti --image=busybox /bin/sh
    # Output:
    If you don't see a command prompt, try pressing enter.
    / # wget www.taobao.com
    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 output shows can't connect to remote host. This indicates that the application fails to access the domain name.
  5. Run the following command to access www.aliyun.com.
    / # wget www.aliyun.com
    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
    / #
    If the output shows 100%, this indicates that the application can access the domain name.

Create a network policy to restrict access to the Internet for pods in a specified namespace

  1. Run the following command to create a namespace.
    # Create a namespace named test-np.
    kubectl create ns test-np
    # Output:
    namespace/test-np created
  2. Run the following command to set the default network policy rule that allows pods to access only internal services.
    vim default-deny.yaml
    # Copy the following content to 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
    
    kubectl apply -f default-deny.yaml
    # Output:
    networkpolicy.networking.k8s.io/deny-public-net created
    
    kubectl get networkpolicy -n test-np
    # Output:
    NAME                              POD-SELECTOR          AGE
    deny-public-net                   <none>                1m
  3. Run the following command to allow only pods with a specified label to access the Internet.

    In thie example, the pods are labeled with public-network=true.

    vim allow-specify-label.yaml
    # Copy the following content to 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
    
    kubectl apply -f allow-specify-label.yaml
    # Output:
    networkpolicy.networking.k8s.io/allow-public-network-for-labels created
    
    kubectl get networkpolicy -n test-np
    # Output:
    NAME                              POD-SELECTOR          AGE
    allow-public-network-for-labels public-network=true 1m
    deny-public-net                   <none>                 3m
    						
  4. Run the following command to test whether pods without the specified label can access the Internet.
    kubectl run -it --namespace test-np --rm --image busybox busybox-intranet
    # Output:
    If you don't see a command prompt, try pressing enter.
    / # ping aliyun.com
    PING aliyun.com (106.11.248.146): 56 data bytes
    ^C
    --- aliyun.com ping statistics ---
    9 packets transmitted, 0 packets received, 100% packet loss
    The output shows 0 packets received. This indicates that the pod fails to access the Internet.
    Note Cause of the failure: The deny-public-net network policy restricts Internet access to pods in the test-np namespace. Therefore, pods with default labels cannot access the Internet.
  5. Run the following command to test whether a pod with the public-network=true label can access the Internet.
    kubectl run -it --namespace test-np --labels public-network=true --rm --image busybox  busybox-internet
    # Output:
    If you don't see a command prompt, try pressing enter.
    / # ping aliyun.com
    PING aliyun.com (106.11.172.56): 56 data bytes
    64-bytes from 106.11.172.56: seq=0 ttl=47 time=4.235 ms
    64-bytes from 106.11.172.56: seq=1 ttl=47 time=4.200 ms
    64-bytes from 106.11.172.56: 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
    If the output shows 0% packet loss, this indicates that the pod can access the Internet.
    Note The pod can access the Internet because: The allow-public-network-for-labels network policy allows pods with the public-network=true label to access the Internet. Therefore, pods with the busybox-internet label can access the Internet.