Calico 네트워크 정책

Update : 2020-11-17

Calico 네트워킹 소개

Calico는 컨테이너, 가상 머신 및 기본 호스트 기반 워크로드를 위한 오픈 소스 네트워킹 및 네트워크 보안 솔루션입니다. Calico는 Kubernetes, OpenShift, Docker EE, OpenStack 및 베어 메탈 서비스를 포함한 광범위한 플랫폼을 지원합니다.

Calico는 유연한 네트워킹 기능과 보안 기능을 결합하여 네이티 Linux 커널 성능과 클라우드 네이티브 확장성을 갖춘 솔루션을 제공합니다. Calico 네트워크 정책 집행을 통해 네트워크 세분화 및 테넌트 격리를 구현할 수 있습니다. 이는 테넌트를 각각 격리해야 하는 다중 테넌트 환경에서 또는 개발, 스테이징 및 프로덕션에 별도의 환경을 생성하고자 하는 경우 유용합니다. 네트워크 정책은 네트워크 인,아 규칙을 생성할 수 있다는 점에서 AWS 보안 그룹과 유사하지만, 인스턴스를 보안 그룹에 할당하는 대신 포드의 selector, label등 사용하여 네트워크 정책을 Pod 할당합니다.

주의 !!! Amazon EKS와 함께 Fargate를 사용하는 경우 Calico가 지원되지 않습니다.

이 랩에서는 Calico CNI를 사용하지 않습니다. Calico의 Network Policy만 구성해서 사용합니다.

해당 LAB은 Project Calico 를 참조합니다. https://docs.projectcalico.org/security/kubernetes-policy

EKS에 Calico 설치하기

aws/amazon-vpc-cni-k8s GitHub 프로젝트에서 Calico 매니페스트를 적용합니다. 이 매니페스트는 kube-system 네임스페이스에 데몬 세트를 생성합니다.

kubectl apply -f https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/release-1.7/config/v1.7/calico.yaml

calico 매니페스트 파일의 주요 내용을 살펴 봅니다.

more calico.yaml

정상적으로 설치되었는 지 확인합니다.

kubectl get daemonsets -n kube-system

아래와 같이 결과를 확인 할 수 있습니다. 모든 노드에 분산 설치되기 위해 Daemonset으로 설치 되었습니다.

whchoi98:~/environment/myeks (master) $ kubectl get daemonsets -n kube-system                                                                           
NAME          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                 AGE
aws-node      6         6         6       6            6           <none>                        8d
calico-node   6         6         6       6            6           beta.kubernetes.io/os=linux   10m
kube-proxy    6         6         6       6            6           <none>             

Calico 기반의 네트워크 정책 구성.

1.데모 앱 배포.

이 랩에서는 EKS Cluster에 새로운 Namespace, front-end, back-end, Client, UI 서비스 등을 만들고, 상호간의 네트워크 통신을 허용 또는 제어하는 네트워크 정책을 생성합니다. 또한 각 서비스간에 사용 가능한 송/수신 경로를 보여주는 UI를 포함하고 있습니다.

  • name space : stars

    • Pod : frontend , backend 각 1개

    • replicationcontroller : frontend, backend 1개에 설정

    • service : frontend, backend에 ClusterIP type으로 설정

  • name space : management-ui

    • Pod : management-ui

    • replicationcontroller : management-ui 1개에 설정

    • service : management-ui에 LoadBalcer Type으로 설정.

  • name space : client

    • Pod: client-sjnjk

    • replicationcontroller : client에 1개 설정

    • service : client에 ClusterIP type으로 설정

cd ~/environment/myeks
git pull origin master
mkdir ~/environment/calico_resources
cd ~/environment/calico_resources
kubectl apply -f ~/environment/myeks/calico_demo/namespace.yaml
kubectl apply -f ~/environment/myeks/calico_demo/management-ui.yaml
kubectl apply -f ~/environment/myeks/calico_demo/backend.yaml
kubectl apply -f ~/environment/myeks/calico_demo/frontend.yaml
kubectl apply -f ~/environment/myeks/calico_demo/client.yaml 
kubectl -n stars get all -o wide
kubectl -n management-ui get all -o wide
kubectl -n client get all -o wide 

아래와 같은 출력 결과를 확인 할 수 있습니다.

whchoi98:~/environment/calico_resources $ kubectl -n stars get all -o wide
NAME                 READY   STATUS    RESTARTS   AGE     IP             NODE                                               NOMINATED NODE   READINESS GATES
pod/backend-4z6z5    1/1     Running   0          9m58s   10.11.123.18   ip-10-11-114-132.ap-northeast-2.compute.internal   <none>           <none>
pod/frontend-rvcf7   1/1     Running   0          9m53s   10.11.107.25   ip-10-11-114-132.ap-northeast-2.compute.internal   <none>           <none>

NAME                             DESIRED   CURRENT   READY   AGE     CONTAINERS   IMAGES                     SELECTOR
replicationcontroller/backend    1         1         1       9m58s   backend      calico/star-probe:v0.1.0   role=backend
replicationcontroller/frontend   1         1         1       9m53s   frontend     calico/star-probe:v0.1.0   role=frontend

NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     SELECTOR
service/backend    ClusterIP   172.20.176.57    <none>        6379/TCP   9m58s   role=backend
service/frontend   ClusterIP   172.20.145.253   <none>        80/TCP     9m53s   role=frontend
whchoi98:~/environment/calico_resources $ kubectl -n management-ui get all -o wide
NAME                      READY   STATUS    RESTARTS   AGE   IP              NODE                                              NOMINATED NODE   READINESS GATES
pod/management-ui-75xht   1/1     Running   0          12m   10.11.172.124   ip-10-11-189-67.ap-northeast-2.compute.internal   <none>           <none>

NAME                                  DESIRED   CURRENT   READY   AGE   CONTAINERS      IMAGES                       SELECTOR
replicationcontroller/management-ui   1         1         1       12m   management-ui   calico/star-collect:v0.1.0   role=management-ui

NAME                    TYPE           CLUSTER-IP     EXTERNAL-IP                                                                    PORT(S)        AGE   SELECTOR
service/management-ui   LoadBalancer   172.20.18.17   a927c1a56c9a144aba431cdb58b9c5a7-1577995596.ap-northeast-2.elb.amazonaws.com   80:32184/TCP   12m   role=management-ui
whchoi98:~/environment/calico_resources
whchoi98:~/environment/calico_resources $ kubectl -n client get all -o wide                                                                                  
NAME               READY   STATUS    RESTARTS   AGE   IP             NODE                                               NOMINATED NODE   READINESS GATES
pod/client-sjnjk   1/1     Running   0          14m   10.11.122.81   ip-10-11-114-132.ap-northeast-2.compute.internal   <none>           <none>

NAME                           DESIRED   CURRENT   READY   AGE   CONTAINERS   IMAGES                     SELECTOR
replicationcontroller/client   1         1         1       14m   client       calico/star-probe:v0.1.0   role=client

NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   SELECTOR
service/client   ClusterIP   172.20.86.231   <none>        9000/TCP   14m   role=client

각 매니페스트 파일을 참조하십시요

ind: Namespace
apiVersion: v1
metadata:
  name: stars

frontend.yaml

apiVersion: v1
kind: Service
metadata:
  name: frontend 
  namespace: stars
spec:
  ports:
  - port: 80 
    targetPort: 80 
  selector:
    role: frontend 
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: frontend 
  namespace: stars
spec:
  replicas: 1
  template:
    metadata:
      labels:
        role: frontend 
    spec:
      containers:
      - name: frontend 
        image: calico/star-probe:v0.1.0
        imagePullPolicy: Always
        command:
        - probe
        - --http-port=80
        - --urls=http://frontend.stars:80/status,http://backend.stars:6379/status,http://client.client:9000/status
        ports:
        - containerPort: 80 

backend.yaml

apiVersion: v1
kind: Service
metadata:
  name: backend 
  namespace: stars
spec:
  ports:
  - port: 6379
    targetPort: 6379 
  selector:
    role: backend 
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: backend 
  namespace: stars
spec:
  replicas: 1
  template:
    metadata:
      labels:
        role: backend 
    spec:
      containers:
      - name: backend 
        image: calico/star-probe:v0.1.0
        imagePullPolicy: Always
        command:
        - probe
        - --http-port=6379
        - --urls=http://frontend.stars:80/status,http://backend.stars:6379/status,http://client.client:9000/status
        ports:
        - containerPort: 6379 

management-ui.yaml 파일

apiVersion: v1
kind: Namespace
metadata:
  name: management-ui 
  labels:
    role: management-ui 
---
apiVersion: v1
kind: Service
metadata:
  name: management-ui 
  namespace: management-ui 
spec:
  type: LoadBalancer
  ports:
  - port: 80 
    targetPort: 9001
  selector:
    role: management-ui 
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: management-ui 
  namespace: management-ui 
spec:
  replicas: 1
  template:
    metadata:
      labels:
        role: management-ui 
    spec:
      containers:
      - name: management-ui 
        image: calico/star-collect:v0.1.0
        imagePullPolicy: Always
        ports:
        - containerPort: 9001

client yaml 파일

kind: Namespace
apiVersion: v1
metadata:
  name: client
  labels:
    role: client
---
apiVersion: v1
kind: ReplicationController
metadata:
  name: client 
  namespace: client
spec:
  replicas: 1
  template:
    metadata:
      labels:
        role: client 
    spec:
      containers:
      - name: client 
        image: calico/star-probe:v0.1.0
        imagePullPolicy: Always
        command:
        - probe
        - --urls=http://frontend.stars:80/status,http://backend.stars:6379/status
        ports:
        - containerPort: 9000 
---
apiVersion: v1
kind: Service
metadata:
  name: client
  namespace: client
spec:
  ports:
  - port: 9000 
    targetPort: 9000
  selector:
    role: client 

2. management-ui에 접속

management UI Pod는 External IP로 LB Service를 제공하고 있습니다. 아래와 같은 명령을 통해서 External IP를 확인합니다.

export ELB_SERVICE_URL=$(kubectl get svc -n management-ui management-ui --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
echo "ELB SERVICE URL = $ELB_SERVICE_URL"

출력 결과는 아래와 같습니다.

whchoi98:~/environment/calico_resources $ echo "ELB SERVICE URL = $ELB_SERVICE_URL"
ELB SERVICE URL = a927c1a56c9a144aba431cdb58b9c5a7-1577995596.ap-northeast-2.elb.amazonaws.com

해당 웹 사이트는 Client App , Front end App, Back end App 간의 트래픽 허용 상태를 제공해 줍니다.

3.네트워크 정책 적용

Network Policy를 적용해서 Pod간의 제어를 확인해 봅니다.

먼저 stars, client namespace 에 deny 정책을 업데이트 합니다.

cd ~/environment/myeks/calico_demo/
kubectl apply -n stars -f default-deny.yaml
kubectl apply -n client -f default-deny.yaml

default-deny.yaml을 확인해 봅니다.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: default-deny
spec:
  podSelector:
    matchLabels: {}

다시 아래 management-ui 로 접속해 봅니다.

whchoi98:~/environment/calico_resources $ echo "ELB SERVICE URL = $ELB_SERVICE_URL"
ELB SERVICE URL = a927c1a56c9a144aba431cdb58b9c5a7-1577995596.ap-northeast-2.elb.amazonaws.com

ELB 주소로 접속하면, All deny로 출력되는 결과가 없습니다.

다시 정책을 허용합니다.

kubectl apply -f allow-ui.yaml
kubectl apply -f allow-ui-client.yaml

아래에서 처럼 이제 management-ui로는 접속이 가능합니다. 하지만 Frontend, Backend, Client Pod간에는 통신되지 않습니다.

아래 매니페스트 파일을 확인해 봅니다.

namespace : stars 의 frontend, backend pod는 management-ui에 연결이 가능하도록 합니다.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: stars
  name: allow-ui 
spec:
  podSelector:
    matchLabels: {}
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              role: management-ui 

namespace : client 의 client pod는 management-ui에 연결이 가능하도록 합니다.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: client 
  name: allow-ui 
spec:
  podSelector:
    matchLabels: {}
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              role: management-ui 

이제 Client에서 Front end로 유입되는 트래픽을 허용합니다.

kubectl apply -f frontend-policy.yaml

아래에서 매니페스트 파일을 통해 상세 내용을 확인 할 수 있습니다.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: stars
  name: frontend-policy
spec:
  podSelector:
    matchLabels:
      role: frontend
  ingress:
    - from:
        - namespaceSelector:
            matchLabels:
              role: client
      ports:
        - protocol: TCP
          port: 80

다시 management-ui 로 접속해 보면 트래픽 허용되는 것을 확인 할 수 있습니다.

이제 frontend에서 backend로 유입되는 트래픽을 허용합니다.

kubectl apply -f backend-policy.yaml

아래에서 매니페스트 파일을 통해 상세 내용을 확인 할 수 있습니다.

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  namespace: stars
  name: backend-policy
spec:
  podSelector:
    matchLabels:
      role: backend
  ingress:
    - from:
        - podSelector:
            matchLabels:
              role: frontend
      ports:
        - protocol: TCP
          port: 6379

다시 management-ui 로 접속해 보면 트래픽 허용되는 것을 확인 할 수 있습니다.

Last updated