이제 마지막 스터디 주차이다. 마지막 주차는 어렵기도 어렵고, 적용도 힘든.. Security 보안과 관련된 사항이다.
실습 환경 구성
이번 주차는 vagrant로 구성을 한다. 이전 주차와 크게 다르지 않게 마스터 노드 1대, 워커 노드 2개로 구성한다.
metric server, prometheus, grafana, cilium 1.18을 배포해서 사용한다.
curl -O https://raw.githubusercontent.com/gasida/vagrant-lab/refs/heads/main/cilium-study/8w/Vagrantfile
vagrant up
cilium은 아래와 같이 설치된다. kube proxy 대체하고, cluster ipam을 사용한다. 그리고 native routing을 사용한다.
security를 하기 위해서는 cilium network policy를 사용하기 떄문에 l7 backend envoy를 사용한다.
helm install cilium cilium/cilium --version $2 --namespace kube-system \
--set k8sServiceHost=192.168.10.100 --set k8sServicePort=6443 \
--set ipam.mode="cluster-pool" --set ipam.operator.clusterPoolIPv4PodCIDRList={"172.20.0.0/16"} --set ipv4NativeRoutingCIDR=172.20.0.0/16 \
--set routingMode=native --set autoDirectNodeRoutes=true --set endpointRoutes.enabled=true --set directRoutingSkipUnreachable=true \
--set kubeProxyReplacement=true --set bpf.masquerade=true --set installNoConntrackIptablesRules=true \
--set endpointHealthChecking.enabled=false --set healthChecking=false \
--set hubble.enabled=true --set hubble.relay.enabled=true --set hubble.ui.enabled=true \
--set hubble.ui.service.type=NodePort --set hubble.ui.service.nodePort=30003 \
--set prometheus.enabled=true --set operator.prometheus.enabled=true --set hubble.metrics.enableOpenMetrics=true \
--set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,httpV2:exemplars=true;labelsContext=source_ip\,source_namespace\,source_workload\,destination_ip\,destination_namespace\,destination_workload\,traffic_direction}" \
--set ingressController.enabled=true --set ingressController.loadbalancerMode=shared --set loadBalancer.l7.backend=envoy \
--set localRedirectPolicy=true --set l2announcements.enabled=true \
--set operator.replicas=1 --set ciliumEndpointSlice.enabled=true --set debug.enabled=true >/dev/null 2>&1
Cilium Security
cilium에서는 security, 즉 보안을 적용하기 위해서는 identity 라는 개념을 사용한다.
그리고 ciliumendpoint 객체로 확인할 수 있다. endpointclice와 유사하다.
kubectl get ciliumendpoint = kubectl get cep
다른점은 cilium에서 사용되는 id, identity id를 확인할 수 있다.
id는 cilium-dbg endpoint list 등으로 확인할 수 있는 pod의 고유한 id이다.
반면 identity id는 고유값이 아니다. 동일한 security policy가 적용되면 같은 identity id를 가질 수 있다.
- identity는 pod labels을 기반으로 정해진다.
apiVersion: v1
items:
- apiVersion: cilium.io/v2
kind: CiliumEndpoint
metadata:
labels:
run: nginx
name: nginx
namespace: default
ownerReferences:
- apiVersion: v1
kind: Pod
name: nginx
status:
encryption: {}
external-identifiers:
k8s-namespace: default
k8s-pod-name: nginx
pod-name: default/nginx
id: 3706 <<< 고유한 endpoint id도 확인을 할 수 있다.
identity:
id: 44412 <<< security에서 핵심이 되는 identity 확인도 되고
labels:
- k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default
- k8s:io.cilium.k8s.policy.cluster=default
- k8s:io.cilium.k8s.policy.serviceaccount=default
- k8s:io.kubernetes.pod.namespace=default
- k8s:run=nginx
networking:
addressing:
- ipv4: 172.20.1.106 <<< pod ip도 확인할 수 있고
node: 192.168.10.101 <<< 어떤 노드에 스케줄링 되어 있는지 확인할 수 있고
state: ready
kind: List
cilium에서는 보통 ciliumnetworkpolicy(=cnp) 객체를 통해서 security 기능을 제공하고 있다.
Cilium NetworkPolicy

networkpolicy는 그냥 networkpolicy가 있고, ciliumnetworkpolicy가 존재한다.
2개 모두 트래픽을 제어한다는 목적은 똑같지만, networkpolicy는 label 기반으로만 제어를 하게 되고
ciliumnetworkpolicy(=cnp)는 labels, ip, port, path, protocol 등등으로 모두 제어가 가능하다.
cnp가 없다면, 기본적으로는 모든 트래픽이 적용된다. 하지만 정책이 적용되게 되면 기본 정책이 차단으로 변경된다.
기본 정책은 차단이 되고, cnp로 명시적으로 작성한 정책에 대해서만 허용이 되는것이다.
보통 L3, L4 정책은 cilium-agent에서 처리를 하고, L7 정책을 cilium-envoy에서 처리를 한다.
cnp를 적용하면 기본 정책이 차단되고, 명시적으로 작성한 정책만 허용되기 때문에 반드시 주의해야한다.
Cilium NetworkPolicy 테스트 - label 제어
기본적으로 networkpolicy와 동일하게 label로 테스트를 해보자.
- role: backend labels을 가진 endpoint에만 적용되며, role: frontend의 트래픽만 수용하는 정책이다.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "l3-rule"
spec:
endpointSelector:
matchLabels:
role: backend
ingress:
- fromEndpoints:
- matchLabels:
role: frontend
테스트 앱을 배포해서, 필요한 labels을 추가해서 호출이 잘 되는지 테스트를 해보자
kubectl run backend --image=nginx:latest
kubectl run backend2 --image=nginx:latest
kubectl run frontend --image=nicolaka/netshoot -- /bin/bash
kubecl run client --image=nicolaka/netshoot -- /bin/bash
kubectl label pods/backend role:backend --overwrite
kubectl label pods/backend2 role:backend2 --overwrite
kubectl label pods/frontend role:frontend --overwrite
테스트를 해보면 예상했던것과 같이 backend는 오직 frontend에서 오는 트래픽만 받고 나머지는 timeout이 된다.

테스트는 endpoint label을 기준으로 테스트를 했으나, namespace + svc 그리고 identity 등의 제어를 통해서 할 수 있다.
- 이외에도 fromNodes를 통해서 노드 제어도 가능하고, toCIDR를 통해서 IP ragne도 제어도 가능하다.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "service-rule"
spec:
endpointSelector:
matchLabels:
id: app2
egress:
- toServices:
- k8sService:
serviceName: myservice
namespace: default
- k8sServiceSelector:
selector:
matchLabels:
env: staging
namespace: another-namespace
---
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "dev-to-kube-apiserver"
spec:
endpointSelector:
matchLabels:
env: dev
egress:
- toEntities:
- kube-apiserver
Cilium NetworkPolicy 테스트 - port 제어
이번에는 L4 port 기준으로 cnp를 적용하고 테스트를 해보자.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "l4-rule"
spec:
endpointSelector:
matchLabels:
app: myService
egress:
- toPorts:
- ports:
- port: "80"
protocol: TCP
app= myService labels을 가진 pod에서 nginx:80, 81로 요청을 하면 80을 허용이 되고, 81은 drop되는걸 볼 수 있다.

그리고 특이한점은 src 정보가 myService로 나타난다. 이것은 identity id와 연관성이 있다.
cilium-dbg에서 identity list를 보면 각 identity id에 대한 정보를 알 수 있고, 이때 app key에 대한 values를 표시해준다.

apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "l4-port-range-rule"
spec:
endpointSelector:
matchLabels:
app: myService
egress:
- toPorts:
- ports:
- port: "80"
endPort: 444
protocol: TCP
- toCIDR:
- 192.0.2.0/24
toPorts:
- ports:
- port: "80"
protocol: TCP
단순히 port뿐만 아니라 port ragne도 되고, pods CIDR로 cnp를 적용하는것도 가능하다.
Cilium NetworkPolicy 테스트 - port + path 제어
port + path를 기준으로 테스트를 해보자.
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "rule1"
spec:
description: "Allow HTTP GET /public from env=prod to app=service"
endpointSelector:
matchLabels:
app: service
ingress:
- fromEndpoints:
- matchLabels:
env: prod
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: "GET"
path: "/public"
위에서 말한것과 같이 app=service label을 가지고 있기 때문에 hubble에서 service identity로 표시가 되고,
/public만 허용했기 때문에 그외 나머지 path에 대해서만 차단이 되는 모습이다.

Cilium NetworkPolicy 테스트 - domain 제어
특정 도메인에 대해서만 허용하는것이다. 기본적으로 kube-dns로 가는 트래픽을 허용하고, cilium.io만 허용하는 정책이다.
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: tofqdn-dns-visibility
spec:
egress:
- toEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: kube-system
k8s:k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: '*'
- toFQDNs:
- matchName: cilium.io
- matchName: sub.cilium.io
- matchPattern: '*.sub.cilium.io'
endpointSelector:
matchLabels:
app: service

결국에는 다 도메인을 ip로 전환을 해서 통신을 하는게 도메인에 대해서 어떻게 차단하지? 궁금해서 찾아봤더니
1. cilium에서 kube-dns로 가는 트래픽을 허용하고
2. DNS 질의/응답에 대해 내부 테이블을 저장한다.
3. 그리고 실제 pod에서 호출할 때 dst ip를 2.의 과정에서 만든 테이블에서 ip와 매핑하여 도메인을 확인한다.
- 하지만 왜인지.. 실제로 테이블에 정보가 없다.
4. 허용하는 도메인이 아닐 경우 차단한다.

근데 실제로는 fqdn cache list를 보면 아무런 정보도 없고.. cilium fqdn names으로 검색해보면 도메인/ip 테이블 정보가 없다.
이번 주차는 cilium network policy에 대해서 알아보았다.
cilium은 아니지만 network policy를 이전 회사에서 적용했었다. 하지만 휴먼에러가 너무 많아 발생하고.. 장애 영향도가 컸었다.
굳이 필요하다는 니즈가 없었기도 했고, 그래서 결국에는 network policy를 제거했었다.
개인적으로는 network policy에 대해서는 부정적인 의견을 가지고 있다.
- 기본적으로 필요한 dst 통신 파악이 매우매우 힘들다.
. 개발팀에서도 필요한 통신이 무엇인지, 잘 알지 못한다. 그리고 추가 개발이 있을때마다 networkpolicy에 반영해줘야 한다.
- 정책을 잘못 넣으면 서비스 영향도가 매우 크다.
- 내부시스템끼리 이렇게까지 제어를 해서 얻는 이점이 크지 않는것 같다.
현 회사에서는 보안팀에서 pod 끼리의 통신을 제어해달라는 요청이 있었다.
지금은 istio를 사용하고 있기 때문에 sidecar crd를 통해 istio-system XDS Push만 허용하하고 그외 나머지는 모두 차단하고 있다.
network policy는 아니지만, 약간 우회적으로? 요구사항은 반영한다. 요구사항이 있다면, 반영하는 방법은 여러가지가 있다.
여러가지 방법에 대해서 상황에 따라서 적용하고, 영향도/운영 가능성을 염두해두고 적용을 해야한다.

'기술 토론장 > [K8s] Kubernetes' 카테고리의 다른 글
| [Cilium][8주차] Cilium end to end security + Tetragon (1) | 2025.09.07 |
|---|---|
| kube-apiserver oom 죽지 않기 w. APF (1) | 2025.08.31 |
| [Cilium][7주차] K8s, Cilium 부하 테스트 & 성능 측정 (1) | 2025.08.30 |
| [Cilium][6주차] L7 Aware Traffic Management (0) | 2025.08.24 |
| [Cilium][6주차] Service Mesh Gateway API Support (1) | 2025.08.23 |