KANS 3기 8주차 - Cilium CNI

Oasis·2024년 10월 23일

KANS

목록 보기
8/9

가시다님의 KANS [3기] 스터디 내용을 정리한 포스트 입니다.

1. Cilium 소개

Cilium의 가장 큰 특징 중 하나는 기존의 네트워크 인터페이스를 사용하는 대신에 eBPF라는 기술을 사용한다는 점입니다.

eBPF에 대해 잘 설명한 포스팅을 공유합니다. eBPF link

1.1 eBPF

eBPF는 리눅스 커널에서 네트워크 트래픽을 효율적으로 모니터링하고 필터링할 수 있는 강력한 기술입니다. eBPF는 원래 네트워크 패킷을 필터링하기 위한 도구로 개발되었지만, 지금은 네트워크뿐만 아니라 시스템 모니터링, 보안 등 다양한 분야에서 활용되고 있습니다.

리눅스 네트워크 스택의 단점은 복잡하고, 변경에 시간이 걸리고, 레이어를 건너뛰기 어렵다는 단점이 있습니다. IPTables와 비교할 때 eBPF의 장점은 여러 측면에서 IPTables의 단점을 보완하거나 해결합니다.

  • Linux Network Stack : 리눅스 네트워크 스택의 단점은 복잡하고, 변경에 시간이 걸리고, 레이어를 건너뛰기 어렵다.

1.1.1 IPTables 단점

IPTables와 비교할 때 eBPF의 장점은 여러 측면에서 IPTables의 단점을 보완하거나 해결합니다. 여기서는 eBPF의 관점에서 IPTables의 단점을 설명하겠습니다.

  1. 성능 저하

    • IPTables의 문제점: IPTables는 패킷 필터링을 위해 리눅스 네트워크 스택을 거칩니다. 네트워크 스택은 계층 구조를 가지고 있어, 각 패킷이 여러 단계의 처리를 거치기 때문에 처리 지연이 발생할 수 있습니다. 또한, IPTables 규칙이 많아질수록 패킷 처리 성능이 급격히 저하됩니다.
    • eBPF의 개선: eBPF는 커널 내에서 직접 실행되므로 네트워크 스택을 거치지 않고, 특정한 트래픽 필터링이나 처리를 매우 효율적으로 수행할 수 있습니다. 이로 인해 패킷 처리 속도가 크게 향상되고, 대규모 트래픽 처리에도 성능이 저하되지 않습니다.

  2. 규모가 커질수록 관리 복잡성 증가

    • IPTables의 문제점: IPTables는 많은 규칙이 쌓이면 규칙이 일일이 순차적으로 적용되기 때문에 확장성에 한계가 있습니다. 대규모 클러스터나 복잡한 정책을 적용할 때 규칙 관리가 어렵고, 규칙 업데이트 시 성능 저하가 발생할 수 있습니다.
    • eBPF의 개선: eBPF는 프로그램 형태로 동작하며, 규칙을 효율적으로 적용하고 확장성이 뛰어납니다. 커널에 동적으로 로드되고, 트래픽 필터링이 IPTables처럼 규칙 기반으로 처리되지 않아 대규모 환경에서도 성능이 유지됩니다. 또한 정교한 로깅과 트레이싱이 가능해 네트워크 정책의 모니터링과 디버깅이 용이합니다.

  3. 유연성 부족

    • IPTables의 문제점: IPTables는 주로 L3/L4 계층에서 패킷 필터링을 수행하며, 애플리케이션 레벨(L7)의 트래픽을 필터링하거나 세밀한 제어를 하기가 어렵습니다. 복잡한 네트워크 정책을 구현하려면 제약이 많습니다.
    • eBPF의 개선: eBPF는 L3/L4뿐만 아니라 L7 레벨에서 트래픽을 처리할 수 있어, 애플리케이션 레벨의 트래픽 제어도 가능합니다. 이로 인해 HTTP 요청 필터링, TLS 트래픽 제어, 서비스 메시 통합 등의 고급 기능을 쉽게 구현할 수 있습니다.

  4. 규칙 업데이트의 비효율성

    • IPTables의 문제점: IPTables의 규칙을 수정하거나 추가할 때, 전체 규칙 테이블을 다시 로드해야 하므로 업데이트가 느리고 비효율적입니다. 특히 대규모 시스템에서는 규칙 업데이트 시 트래픽 중단이나 성능 저하가 발생할 수 있습니다.
    • eBPF의 개선: eBPF는 동적으로 커널에 로드되며, 프로그램 자체가 실시간으로 적용됩니다. 규칙을 추가하거나 변경할 때 기존의 모든 규칙을 재적용할 필요가 없으며, 중단 없이 실시간 업데이트가 가능하여 운영 환경에서 유연하게 대응할 수 있습니다.

  5. 가시성 부족

    • IPTables의 문제점: IPTables는 패킷이 어떤 규칙에 의해 처리되었는지, 왜 차단되었는지에 대한 상세한 정보 제공이 부족합니다. 네트워크 트래픽에 대한 가시성이 떨어지며, 이를 모니터링하기 위해 추가 도구가 필요합니다.
    • eBPF의 개선: eBPF는 정교한 트레이싱과 모니터링 기능을 제공합니다. 패킷이 어떻게 처리되고 있는지, 어떤 경로를 거치는지 등을 실시간으로 파악할 수 있어 문제를 신속하게 발견하고 해결할 수 있습니다. Cilium과 같은 도구는 이를 바탕으로 세밀한 네트워크 분석을 제공합니다.

1.1.2 BPF & eBPF

BPF 는 커널에 삽입하여 패킷을 통제(필터링) 할 수 있으며, 다양한 영역에서 Hook 을 통해서 접근 할 수 있습니다.

  • extended Berkeley Packet Filter
    Dynamically program the kernel for efficient networking, observability, tracing, and security

BPF(1992년) 를 확장해서 eBPF가 (2014년, Alexei Starovoitov) 가 나왔고, eBPF다양한 영역 (보안, 추적, 네트워킹, 모니터링)에서 활용하기 시작하였습니다.

  • eBPF is a revolutionary technology that can run sandboxed programs in the Linux kernel without changing kernel source code or loading kernel modules. → 커널 내에 (샌드박스 내에서) 자유롭게 프로그래밍하여 적용 할 수 있다

1.1.3 XDP(eXpress Data Path)

XDP(eXpress Data Path)**는 리눅스 커널의 네트워크 패킷 처리를 위한 고성능 기능으로, eBPF를 기반으로 동작합니다. XDP는 네트워크 인터페이스 카드(NIC) 수준에서 패킷을 필터링하고 처리할 수 있어, 매우 빠른 속도로 패킷을 처리할 수 있다는 장점이 있습니다.

  • 고속 패킷 처리
    • XDP는 커널 네트워크 스택에 진입하기 전에 패킷을 처리하기 때문에, 기존의 네트워크 경로에서 발생하는 오버헤드를 피할 수 있습니다. 패킷을 커널 공간으로 전달하기 전에, 네트워크 드라이버 단계에서 바로 처리하므로 매우 짧은 대기 시간과 높은 처리량을 제공합니다.

  • eBPF 기반 동작
    • XDP는 eBPF 프로그램을 사용하여 패킷을 처리합니다. eBPF 프로그램은 커널에 안전하게 로드되어 특정 규칙에 따라 패킷을 처리하거나 필터링할 수 있습니다. XDP의 모든 로직은 사용자 정의 가능하며, 이를 통해 고유한 네트워크 필터링 규칙을 만들 수 있습니다.

  • 네트워크 성능 최적화
    • XDP는 기존의 리눅스 네트워크 스택과 비교해 훨씬 적은 리소스를 사용하면서도, 대량의 트래픽을 처리할 수 있습니다. 패킷을 커널에서 처리하지 않고 네트워크 카드에서 바로 처리할 수 있어, 패킷 처리 속도가 크게 향상됩니다. 특히, DDoS 공격과 같은 대량의 패킷을 빠르게 드롭할 수 있는 능력은 네트워크 방어에 매우 유용합니다.

  • 유연한 배포
    • XDP는 다양한 네트워크 환경에 쉽게 배포될 수 있습니다. 이를 통해 네트워크 장비와 애플리케이션의 성능을 크게 향상시킬 수 있으며, DDoS 방어, 방화벽, 네트워크 트래픽 분석과 같은 다양한 사용 사례에 적합합니다.

  • 패킷 처리 경로

    • XDP는 크게 세 가지 패킷 처리 경로를 제공합니다:

    • XDP_DROP: 패킷을 즉시 드롭합니다. 이는 DDoS 공격 방어와 같이 불필요한 트래픽을 빠르게 차단하는 데 유용합니다.

    • XDP_PASS: 패킷을 커널 네트워크 스택으로 전달하여 일반적인 네트워크 처리를 계속합니다.

    • XDP_TX: 패킷을 수정한 후 바로 네트워크 인터페이스를 통해 다시 전송합니다.

    • XDP_REDIRECT: 패킷을 다른 네트워크 인터페이스나 사용자 공간 프로그램으로 리디렉션합니다.

1.2 Cilium

Cilium은 클라우드 네이티브 환경에서 고성능 네트워킹과 보안 정책을 제공하기 위해 설계된 오픈소스 CNI(Container Network Interface)입니다. 특히, Kubernetes와 같은 컨테이너 오케스트레이션 플랫폼에서 컨테이너 간의 네트워크 통신을 효율적으로 처리하고, 네트워크 보안 정책을 설정하는 데 주로 사용됩니다. Cilium은 eBPF(Extended Berkeley Packet Filter)를 핵심 기술로 사용하여 기존의 IP 테이블 기반 네트워크 솔루션보다 더 높은 성능과 유연성을 제공합니다.

•	서비스 메시를 관리하고, L3/L4뿐만 아니라 L7 레벨에서의 정책도 제공
•	네트워크 정책을 통해 애플리케이션 간의 트래픽을 제어
•	로드 밸런싱과 네트워크 가시성 제공
  • Cilium과 eBPF의 관계

Cilium은 eBPF를 사용하여 네트워크 트래픽을 처리하고 정책을 적용합니다. 전통적인 CNI는 IP 테이블을 사용하여 네트워크 정책을 처리했지만, eBPF를 사용하면 성능이 훨씬 더 좋아지고, 커널 레벨에서 세밀하게 트래픽을 관리할 수 있습니다.

1.2.1 Cilium 주요 특징

  1. eBPF 기반의 네트워크 처리

    • Cilium은 eBPF를 활용하여 리눅스 커널 내에서 실시간 네트워크 필터링, 로드 밸런싱, 정책 적용 등의 작업을 수행합니다. eBPF는 커널에 안전하게 로드되어 성능 저하 없이 복잡한 네트워크 규칙을 처리할 수 있습니다.
    • eBPF의 사용으로 인해, 네트워크 트래픽을 커널 공간에서 바로 처리하여 성능을 크게 향상시키고, 기존의 IP 테이블과 같은 방식을 사용하는 네트워크 솔루션의 병목을 해결할 수 있습니다.
  2. 고성능 및 확장성

    • Cilium은 대규모 클러스터에서 고성능 네트워킹을 제공합니다. eBPF는 커널에서 직접 동작하여, 기존의 네트워크 스택을 거치지 않고 네트워크 트래픽을 빠르게 처리할 수 있습니다. 이로 인해 확장성 있는 고성능 네트워크 환경을 구축할 수 있으며, 대규모의 마이크로서비스 기반 아키텍처에서도 성능 저하 없이 운영할 수 있습니다.
  3. 정교한 네트워크 보안 정책
    • Cilium은 네트워크 보안 정책을 L3/L4뿐만 아니라 L7 애플리케이션 레벨까지 지원합니다. 이를 통해 HTTP, gRPC, Kafka와 같은 애플리케이션 레벨에서 발생하는 네트워크 트래픽도 세밀하게 관리할 수 있습니다.
    • 보안 정책은 레이어 7 프로토콜을 분석하여 세밀하게 적용할 수 있으며, 애플리케이션 간의 트래픽 흐름을 더욱 안전하게 제어할 수 있습니다.
  4. 통합된 서비스 메시 지원
    • Cilium은 Envoy와 같은 서비스 메시 프록시와 통합되어, L7 레벨에서 트래픽을 제어하고 모니터링할 수 있습니다. 이를 통해 서비스 메시 인프라를 네트워크에 원활하게 결합할 수 있습니다. Cilium은 서비스 메시 환경에서 트래픽 라우팅, 로드 밸런싱, 보안 정책 적용 등을 지원합니다.
  5. 네트워크 가시성 및 모니터링
    • Cilium은 네트워크 트래픽을 실시간으로 가시화하고 모니터링할 수 있는 기능을 제공합니다. 이를 통해 네트워크 상태를 세밀하게 파악할 수 있으며, 문제가 발생했을 때 신속하게 원인을 분석할 수 있습니다. 또한, eBPF를 활용한 트레이싱과 메트릭 수집 기능이 포함되어 있어 네트워크의 성능을 모니터링하고, 최적화할 수 있습니다.
  6. 다양한 클라우드 환경과의 호환성
    • Cilium은 AWS, Google Cloud, Microsoft Azure와 같은 주요 클라우드 플랫폼에서 사용할 수 있으며, 온프레미스 환경에서도 배포 가능합니다. 이로 인해 하이브리드 클라우드 및 멀티 클라우드 환경에서도 Cilium을 통해 일관된 네트워크 정책을 적용할 수 있습니다.

1.2.2 Cilium 주요 구성 요소

  1. Cilium Agent
    • Cilium 에이전트는 각 Kubernetes 노드에서 실행되며, 네트워크 정책 관리와 eBPF 코드 로드를 담당합니다. 각 노드에서 네트워크 트래픽을 분석하고 처리하며, Kubernetes API 서버와 통신하여 정책 적용을 관리합니다.

  2. Cilium CLI
    • Cilium CLI는 Cilium을 관리하기 위한 명령어 도구입니다. 이를 통해 네트워크 정책 설정, 네트워크 상태 확인, 트래픽 모니터링 등을 쉽게 할 수 있습니다.

  3. Cilium Operator
    • Kubernetes 클러스터 내에서 네트워크 상태를 유지하고, 네트워크 정책을 적용하며, Cilium 에이전트를 관리하는 역할을 합니다. 특히 IP 할당과 네트워크 플러그인 간의 통합을 담당합니다.

  4. eBPF Programs
    • eBPF 프로그램은 커널 내에서 네트워크 트래픽을 실시간으로 처리하며, 보안 정책을 적용하거나 트래픽을 라우팅하는 데 사용됩니다. Cilium은 eBPF 프로그램을 통해 고성능 패킷 처리와 정교한 트래픽 제어를 실현합니다.

  5. Hubble : 네트워크와 보안 모니터링 플랫폼 역할을 하여, 'Server, Relay, Client, Graphical UI' 로 구성되어 있다.

  6. Data Store : Cilium Agent 간의 상태를 저장하고 전파하는 데이터 저장소, 2가지 종류 중 선택(K8S CRDs, Key-Value Store)


2. Cilium 배포

2.1 Cilium 배포

  • Cilium 설치 정보(w/Helm) 및 확인
helm repo add cilium https://helm.cilium.io/
helm repo update

#
helm install cilium cilium/cilium --version 1.16.3 --namespace kube-system \
--set k8sServiceHost=192.168.10.10 --set k8sServicePort=6443 --set debug.enabled=true \
--set rollOutCiliumPods=true --set routingMode=native --set autoDirectNodeRoutes=true \
--set bpf.masquerade=true --set bpf.hostRouting=true --set endpointRoutes.enabled=true \
--set ipam.mode=kubernetes --set k8s.requireIPv4PodCIDR=true --set kubeProxyReplacement=true \
--set ipv4NativeRoutingCIDR=192.168.0.0/16 --set installNoConntrackIptablesRules=true \
--set hubble.ui.enabled=true --set hubble.relay.enabled=true --set prometheus.enabled=true --set operator.prometheus.enabled=true --set hubble.metrics.enableOpenMetrics=true \
--set hubble.metrics.enabled="{dns:query;ignoreAAAA,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 operator.replicas=1

## 주요 파라미터 설명
--set debug.enabled=true # cilium 파드에 로그 레벨을 debug 설정
--set autoDirectNodeRoutes=true # 동일 대역 내의 노드들 끼리는 상대 노드의 podCIDR 대역의 라우팅이 자동으로 설정
--set endpointRoutes.enabled=true # 호스트에 endpoint(파드)별 개별 라우팅 설정
--set hubble.relay.enabled=true --set hubble.ui.enabled=true # hubble 활성화
--set ipam.mode=kubernetes --set k8s.requireIPv4PodCIDR=true # k8s IPAM 활용
--set kubeProxyReplacement=true # kube-proxy 없이 (최대한) 대처할수 있수 있게
--set ipv4NativeRoutingCIDR=192.168.0.0/16 # 해당 대역과 통신 시 IP Masq 하지 않음, 보통 사내망 대역을 지정
--set operator.replicas=1 # cilium-operator 파드 기본 1개
--set enableIPv4Masquerade=true --set bpf.masquerade=true # 파드를 위한 Masquerade , 추가로 Masquerade 을 BPF 로 처리 >> enableIPv4Masquerade=true 인 상태에서 추가로 bpf.masquerade=true 적용이 가능

  • Cilium CLI 설치
# Cilium CLI 설치
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
# 확인
cilium status --wait
cilium config view

# cilium 데몬셋 파드 내에서 cilium 명령어로 상태 확인
export CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-s  -o jsonpath='{.items[0].metadata.name}')
alias c0="kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- cilium"
c0 status --verbose
...
KubeProxyReplacement:   True   [ens5   192.168.10.10 fe80::57:abff:fee3:da8d (Direct Routing)]
...
IPAM:                   IPv4: 2/254 allocated from 172.16.0.0/24, 
Allocated addresses:
  172.16.0.159 (router)
  172.16.0.171 (health)
...
Routing:                Network: Native   Host: BPF
...
Device Mode:            veth
Masquerading:           BPF   [ens5]   192.168.0.0/16 [IPv4: Enabled, IPv6: Disabled]
...  
Proxy Status:            OK, ip 172.16.0.159, 0 redirects active on ports 10000-20000, Envoy: external
...
KubeProxyReplacement Details:
  Status:                 True
  Socket LB:              Enabled
  Socket LB Tracing:      Enabled
  Socket LB Coverage:     Full
  Devices:                ens5   192.168.10.10 fe80::57:abff:fee3:da8d (Direct Routing)
  Mode:                   SNAT
  Backend Selection:      Random
  Session Affinity:       Enabled
  Graceful Termination:   Enabled
  NAT46/64 Support:       Disabled
  XDP Acceleration:       Disabled
  Services:
  - ClusterIP:      Enabled
  - NodePort:       Enabled (Range: 30000-32767) 
  - LoadBalancer:   Enabled 
  - externalIPs:    Enabled 
  - HostPort:       Enabled
BPF Maps:   dynamic sizing: on (ratio: 0.002500)
...

# Native Routing 확인 : # 192.168.0.0/16 대역은 IP Masq 없이 라우팅
c0 status | grep KubeProxyReplacement
KubeProxyReplacement:    True   [ens5   192.168.10.10 fe80::50:46ff:fe62:3505 (Direct Routing)]

# enableIPv4Masquerade=true(기본값) , bpf.masquerade=true 확인
cilium config view | egrep 'enable-ipv4-masquerade|enable-bpf-masquerade'
enable-bpf-masquerade                          true
enable-ipv4-masquerade                         true

c0 status --verbose | grep Masquerading
Masquerading:           BPF   [ens5]   192.168.0.0/16 [IPv4: Enabled, IPv6: Disabled]

# Configure the eBPF-based ip-masq-agent
# https://docs.cilium.io/en/stable/network/concepts/masquerading/
helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values --set ipMasqAgent.enabled=true

#
cilium config view | grep -i masq
enable-bpf-masquerade                             true
enable-ip-masq-agent                              true
...

export CILIUMPOD0=$(kubectl get -l k8s-app=cilium pods -n kube-system --field-selector spec.nodeName=k8s-s  -o jsonpath='{.items[0].metadata.name}')
alias c0="kubectl exec -it $CILIUMPOD0 -n kube-system -c cilium-agent -- cilium"
c0 status --verbose | grep Masquerading
Masquerading:           BPF (ip-masq-agent)   [ens5]   192.168.0.0/16 [IPv4: Enabled, IPv6: Disabled]

kubectl get cm -n kube-system cilium-config -o yaml  | grep ip-masq
  enable-ip-masq-agent: "true"

2.2 Cilium 기본 정보 확인

  • Hubble UI 웹 접속
$HubbleUiNodePort=$(kubectl get svc -n kube-system hubble-ui -o jsonpath={.spec.ports[0].nodePort})
$echo -e "Hubble UI URL = http://$(curl -s ipinfo.io/ip):$HubbleUiNodePort"

Hubble UI URL = http://43.201.15.39:32578

  • 자주 쓰는 Cilium CLI 명령어
# cilium 파드 확인
kubectl get pod -n kube-system -l k8s-app=cilium -owide

# cilium 파드 재시작
kubectl -n kube-system rollout restart ds/cilium
혹은
kubectl delete pod -n kube-system -l k8s-app=cilium

# cilium 설정 정보 확인
cilium config view

# cilium 파드의 cilium 상태 확인
c0 status --verbose

# cilium 엔드포인트 확인
kubectl get ciliumendpoints -A
c0 endpoint list
c0 bpf endpoint list
c0 map get cilium_lxc
c0 ip list

# Manage the IPCache mappings for IP/CIDR <-> Identity
c0 bpf ipcache list

# Service/NAT List 확인
c0 service list
c0 bpf lb list
c0 bpf lb list --revnat
c0 bpf nat list

# List all open BPF maps
c0 map list
c0 map list --verbose

# List contents of a policy BPF map : Dump all policy maps
c0 bpf policy get --all
c0 bpf policy get --all -n

# cilium monitor
c0 monitor -v
c0 monitor -v --type l7
  • 네트워크 기본 정보 확인
    k8s-w1/w2 에 SSH 접속 후 ip -c link/route 정보 확인해 봅니다.

# 네트워크 인터페이스 정보 확인
ip -br -c link
ip -br -c addr

--------------------------------------------
# cilium_net 과 cilium_host 는 veth peer 관계이며, cilium_host 는 파드의 GW IP 주소로 지정되며 32bit 이다
ip -c addr show cilium_net ; ip -c addr show cilium_host
3: cilium_net@cilium_host: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default qlen 1000
    link/ether 5e:0d:9c:77:1c:d3 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::5c0d:9cff:fe77:1cd3/64 scope link
       valid_lft forever preferred_lft forever
4: cilium_host@cilium_net: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default qlen 1000
    link/ether 8a:97:09:3e:4b:e4 brd ff:ff:ff:ff:ff:ff
    inet 172.16.0.229/32 scope global cilium_host
       valid_lft forever preferred_lft forever
    inet6 fe80::8897:9ff:fe3e:4be4/64 scope link
       valid_lft forever preferred_lft forever
   ...

# proxy arp 는 disable(0) 상태이며, 파드와 연결된 lxc 도 모두 0 이다
# 파드의 32bit ip의 gw 가 각각 연결된 veth 인터페이스의 mac 으로 cilium_host 의 IP/MAC 응답을 처리한다, 어떻게 동작이 되는걸까요? >> eBPF program!!!
cat /proc/sys/net/ipv4/conf/cilium_net/proxy_arp
0
cat /proc/sys/net/ipv4/conf/cilium_host/proxy_arp
0

# lxc_health 인터페이스는 veth 로 cilium(NET NS 0, 호스트와 다름)과 veth pair 이다 - 링크
# cilium 인터페이스에 파드 IP가 할당되어 있으며, cilium-health-responder 로 동작한다
lsns -t net
        NS TYPE NPROCS   PID USER    NETNSID NSFS COMMAND
4026531840 net     147     1 root unassigned      /sbin/init
4026532326 net       1 13559 root          0      cilium-health-responder --listen 4240 --pidfile /var/run/cilium/state/health-endpoint.pid
  • Cilium Container Networking Control Flow

2.3 Hubble UI & CLI

Cilium Hubble은 Cilium과 함께 제공되는 네트워크 관측 및 모니터링 도구로, 클라우드 네이티브 환경에서 네트워크 트래픽 가시성을 제공하는데요. Hubble은 eBPF를 활용해 실시간으로 네트워크 통신을 추적하고, Kubernetes 클러스터 내부의 컨테이너 간 네트워크 흐름을 시각화하는 강력한 도구입니다. 이를 통해 네트워크 상태, 보안 정책의 적용 여부, 트래픽 흐름 등을 쉽게 확인하고 문제를 신속하게 해결할 수 있습니다.

2.3.1 Cilium Hubble의 주요 특징

  1. 실시간 네트워크 가시성
    • Hubble은 Kubernetes 클러스터에서 발생하는 모든 네트워크 트래픽을 실시간으로 관찰할 수 있게 해줍니다. 컨테이너 간의 패킷 흐름, 서비스 간 통신, 보안 정책 적용 여부 등을 실시간으로 추적하여 네트워크 상태를 명확히 파악할 수 있습니다.
    • 각 네트워크 연결 상태, 통신 지연 시간, 트래픽 흐름 경로 등을 시각적으로 확인할 수 있어 문제 진단과 성능 최적화에 매우 유용합니다.

  2. 세밀한 네트워크 및 보안 모니터링
    • Hubble은 L3/L4뿐만 아니라 L7(Application Layer) 트래픽까지 추적하여, HTTP, gRPC, Kafka 등 애플리케이션 레벨의 네트워크 통신을 모니터링할 수 있습니다. 이를 통해 특정 애플리케이션의 트래픽 상태를 분석하거나, 세밀한 보안 정책이 제대로 적용되고 있는지 확인할 수 있습니다.
    • 또한, Hubble은 네트워크 보안 정책의 로그를 제공하여, 정책에 의해 차단된 트래픽과 허용된 트래픽을 명확히 확인할 수 있습니다.

  3. 다양한 가시성 도구
    • Hubble은 여러 도구를 제공하여 네트워크를 시각적으로 분석할 수 있습니다.
    • Hubble CLI: 명령줄 도구를 통해 실시간으로 네트워크 트래픽을 추적하고, 보안 정책의 적용 결과를 확인할 수 있습니다.
    • Hubble UI: 웹 기반 대시보드를 제공하여 네트워크 상태를 직관적으로 시각화합니다. 이를 통해 각 포드 간의 통신 경로, 트래픽 상태, 정책 적용 상태 등을 한눈에 파악할 수 있습니다.
    • Hubble Relay: 여러 노드에서 수집된 트래픽 정보를 중앙에서 집계하고, 그 데이터를 Hubble UI와 같은 시각화 도구에서 사용 가능하게 합니다.

  4. 네트워크 성능 분석
    • Hubble은 네트워크 지연 시간, 패킷 손실률, 대역폭 사용량 등의 성능 메트릭을 실시간으로 추적하여 네트워크 성능을 분석합니다. 이를 통해 병목 현상이 발생하는 지점을 신속히 찾아내고, 네트워크 성능을 최적화할 수 있습니다.
    • 또한, 서비스 간 통신에서 발생하는 문제점을 실시간으로 모니터링하여 애플리케이션의 성능 저하나 네트워크 장애를 신속히 파악할 수 있습니다.

  5. 강력한 보안 및 감사 기능
    • Hubble은 Kubernetes 네트워크 정책의 적용 상태를 세밀하게 모니터링하고, 네트워크 트래픽에 대한 정책 감사 기능을 제공합니다. 이를 통해 특정 네트워크 흐름이 정책에 의해 허용되었는지, 차단되었는지 기록하여 보안 사고 발생 시 빠르게 대처할 수 있습니다.
    • 감사 기록은 네트워크 보안 상태를 관리하고, 보안 규정을 준수하는 데 중요한 역할을 합니다.

  6. 배포 및 확장성
    • Hubble은 Kubernetes 클러스터에 손쉽게 배포할 수 있으며, Cilium과 긴밀히 통합되어 클러스터의 규모와 관계없이 확장성 있는 네트워크 가시성을 제공합니다. 여러 노드에 걸친 트래픽을 중앙에서 수집하고 시각화하는 기능을 통해 대규모 환경에서도 일관된 네트워크 모니터링이 가능합니다.

2.3.2 Hubble의 주요 구성 요소

  1. Hubble UI
    • 사용자 친화적인 웹 대시보드로, 클러스터에서 발생하는 트래픽을 시각적으로 확인할 수 있습니다. 각 애플리케이션 또는 서비스 간의 트래픽 흐름을 그래프 형태로 보여주며, 세부 트래픽 정보와 정책 적용 상태를 실시간으로 확인할 수 있습니다.

  2. Hubble CLI
    • 명령줄 인터페이스를 통해 Hubble의 다양한 기능을 사용할 수 있습니다. 실시간으로 네트워크 흐름을 모니터링하거나 특정 트래픽을 필터링하여 분석할 수 있습니다. 이는 자동화된 스크립트와도 연동이 가능하여, 운영 환경에서 유연하게 활용할 수 있습니다.

  3. Hubble Relay

    •	분산된 Hubble 에이전트에서 수집된 네트워크 정보를 중앙에서 집계하고 전달하는 역할을 합니다. 이를 통해 대규모 클러스터에서 확장성을 유지하며, 각 노드의 트래픽 정보를 효율적으로 관리할 수 있습니다.
  4. Hubble Metrics

    •	네트워크 상태와 성능 지표를 Prometheus와 같은 모니터링 시스템과 연동하여 메트릭 데이터를 수집하고 시각화할 수 있습니다. 이 데이터를 바탕으로 네트워크 성능을 최적화하거나 경고를 설정할 수 있습니다.

2.3.3 Hubble UI/CLI 접근 및 확인

# 확인
cilium status

# UI 파드 정보 확인
kubectl get pod -n kube-system -l k8s-app=hubble-ui -o wide

# Hubble UI 웹 접속
kubectl patch -n kube-system svc hubble-ui -p '{"spec": {"type": "NodePort"}}'
HubbleUiNodePort=$(kubectl get svc -n kube-system hubble-ui -o jsonpath={.spec.ports[0].nodePort})
echo -e "Hubble UI URL = http://$(curl -s ipinfo.io/ip):$HubbleUiNodePort"

## Service NodePort 생성 후 아래 정보 확인!
iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N CILIUM_OUTPUT_nat
-N CILIUM_POST_nat
-N CILIUM_PRE_nat
-N KUBE-KUBELET-CANARY
-A PREROUTING -m comment --comment "cilium-feeder: CILIUM_PRE_nat" -j CILIUM_PRE_nat
-A OUTPUT -m comment --comment "cilium-feeder: CILIUM_OUTPUT_nat" -j CILIUM_OUTPUT_nat
-A POSTROUTING -m comment --comment "cilium-feeder: CILIUM_POST_nat" -j CILIUM_POST_nat

conntrack -L
conntrack -L |grep -v 2379
tcp      6 0 CLOSE src=127.0.0.1 dst=127.0.0.1 sport=39450 dport=10259 src=127.0.0.1 dst=127.0.0.1 sport=10259 dport=39450 [ASSURED] mark=0 use=1
tcp      6 49 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=51554 dport=9879 src=127.0.0.1 dst=127.0.0.1 sport=9879 dport=51554 [ASSURED] mark=0 use=1
tcp      6 43 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=47728 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=47728 [ASSURED] mark=0 use=1
tcp      6 23 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=54738 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=54738 [ASSURED] mark=0 use=1
tcp      6 79 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=48616 dport=9879 src=127.0.0.1 dst=127.0.0.1 sport=9879 dport=48616 [ASSURED] mark=0 use=1
tcp      6 63 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=41626 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=41626 [ASSURED] mark=0 use=1
tcp      6 105 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=34416 dport=9878 src=127.0.0.1 dst=127.0.0.1 sport=9878 dport=34416 [ASSURED] mark=0 use=1
tcp      6 3 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=49398 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=49398 [ASSURED] mark=0 use=1
tcp      6 0 CLOSE src=127.0.0.1 dst=127.0.0.1 sport=60384 dport=10257 src=127.0.0.1 dst=127.0.0.1 sport=10257 dport=60384 [ASSURED] mark=0 use=1
tcp      6 83 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=56854 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=56854 [ASSURED] mark=0 use=1
tcp      6 45 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=48828 dport=9878 src=127.0.0.1 dst=127.0.0.1 sport=9878 dport=48828 [ASSURED] mark=0 use=1
tcp      6 73 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=38080 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=38080 [ASSURED] mark=0 use=1
tcp      6 75 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=51712 dport=9878 src=127.0.0.1 dst=127.0.0.1 sport=9878 dport=51712 [ASSURED] mark=0 use=1
tcp      6 53 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=52296 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=52296 [ASSURED] mark=0 use=1
tcp      6 79 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=48606 dport=9879 src=127.0.0.1 dst=127.0.0.1 sport=9879 dport=48606 [ASSURED] mark=0 use=1
tcp      6 93 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=34048 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=34048 [ASSURED] mark=0 use=1
tcp      6 19 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=56934 dport=9879 src=127.0.0.1 dst=127.0.0.1 sport=9879 dport=56934 [ASSURED] mark=0 use=1
tcp      6 49 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=51566 dport=9879 src=127.0.0.1 dst=127.0.0.1 sport=9879 dport=51566 [ASSURED] mark=0 use=1
tcp      6 33 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=47774 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=47774 [ASSURED] mark=0 use=1
tcp      6 113 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=59006 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=59006 [ASSURED] mark=0 use=1
tcp      6 109 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=35320 dport=9879 src=127.0.0.1 dst=127.0.0.1 sport=9879 dport=35320 [ASSURED] mark=0 use=1
tcp      6 49 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=43828 dport=33225 src=127.0.0.1 dst=127.0.0.1 sport=33225 dport=43828 [ASSURED] mark=0 use=1
tcp      6 15 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=36790 dport=9878 src=127.0.0.1 dst=127.0.0.1 sport=9878 dport=36790 [ASSURED] mark=0 use=1
tcp      6 109 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=35328 dport=9879 src=127.0.0.1 dst=127.0.0.1 sport=9879 dport=35328 [ASSURED] mark=0 use=1
conntrack v1.4.6 (conntrack-tools): 104 flow entries have been shown.
tcp      6 13 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=41580 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=41580 [ASSURED] mark=0 use=1
tcp      6 49 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=43824 dport=33225 src=127.0.0.1 dst=127.0.0.1 sport=33225 dport=43824 [ASSURED] mark=0 use=1
tcp      6 105 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=34426 dport=9878 src=127.0.0.1 dst=127.0.0.1 sport=9878 dport=34426 [ASSURED] mark=0 use=1
tcp      6 45 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=48830 dport=9878 src=127.0.0.1 dst=127.0.0.1 sport=9878 dport=48830 [ASSURED] mark=0 use=2
tcp      6 75 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=51728 dport=9878 src=127.0.0.1 dst=127.0.0.1 sport=9878 dport=51728 [ASSURED] mark=0 use=1
tcp      6 19 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=56948 dport=9879 src=127.0.0.1 dst=127.0.0.1 sport=9879 dport=56948 [ASSURED] mark=0 use=1
tcp      6 103 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=43656 dport=2381 src=127.0.0.1 dst=127.0.0.1 sport=2381 dport=43656 [ASSURED] mark=0 use=1
tcp      6 15 TIME_WAIT src=127.0.0.1 dst=127.0.0.1 sport=36788 dport=9878 src=127.0.0.1 dst=127.0.0.1 sport=9878 dport=36788 [ASSURED] mark=0 use=1

# Install Hubble Client
HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)
HUBBLE_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then HUBBLE_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-${HUBBLE_ARCH}.tar.gz{,.sha256sum}
sha256sum --check hubble-linux-${HUBBLE_ARCH}.tar.gz.sha256sum
sudo tar xzvfC hubble-linux-${HUBBLE_ARCH}.tar.gz /usr/local/bin
rm hubble-linux-${HUBBLE_ARCH}.tar.gz{,.sha256sum}

# Hubble API Access : localhost TCP 4245 Relay 를 통해 접근, observe 를 통해서 flow 쿼리 확인 가능!
cilium hubble port-forward &
[1] 50952

# CLI 로 Hubble API 상태 확인
hubble status
Healthcheck (via localhost:4245): Ok
Current/Max Flows: 12,285/12,285 (100.00%)
Flows/s: 38.55
Connected Nodes: 3/

# query the flow API and look for flows
hubble observe
# hubble observe --pod netpod
# hubble observe --namespace galaxy --http-method POST --http-path /v1/request-landing
# hubble observe --pod deathstar --protocol http
# hubble observe --pod deathstar --verdict DROPPED


2.3.4 자가 테스트

# k8s-s에서 아래 명령어 수행
$ cilium connectivity test

웹브라우저에서 Hubble UI 접속 후 cilium-test-1 네임스페이스 선택

3. 노드 간 파드 통신 확인

3.1 패킷 플로우

  • Endpoint to Endpoint

  • Egress from Endpoint

  • Ingress to Endpoint

3.2 파드 생성 및 확인

  • 파드 생성
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: netpod
  labels:
    app: netpod
spec:
  nodeName: k8s-s
  containers:
  - name: netshoot-pod
    image: nicolaka/netshoot
    command: ["tail"]
    args: ["-f", "/dev/null"]
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
  name: webpod1
  labels:
    app: webpod
spec:
  nodeName: k8s-w1
  containers:
  - name: container
    image: traefik/whoami
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
  name: webpod2
  labels:
    app: webpod
spec:
  nodeName: k8s-w2
  containers:
  - name: container
    image: traefik/whoami
  terminationGracePeriodSeconds: 0
EOF
  • 확인
kubectl get pod -o wide
c0 status --verbose | grep Allocated -A5
c1 status --verbose | grep Allocated -A5
c2 status --verbose | grep Allocated -A5

$kubectl get ciliumendpoints
NAME      SECURITY IDENTITY   ENDPOINT STATE   IPV4           IPV6
netpod    4167                ready            172.16.0.235
webpod1   51289               ready            172.16.1.47
webpod2   51289               ready            172.16.2.104

$kubectl get ciliumendpoints -A

NAMESPACE     NAME                           SECURITY IDENTITY   ENDPOINT STATE   IPV4           IPV6
default       netpod                         4167                ready            172.16.0.235
default       webpod1                        51289               ready            172.16.1.47
default       webpod2                        51289               ready            172.16.2.104
kube-system   coredns-55cb58b774-75qkq       56456               ready            172.16.2.184
kube-system   coredns-55cb58b774-kkr6r       56456               ready            172.16.2.194
kube-system   hubble-relay-88f7f89d4-wjrb5   20484               ready            172.16.2.65
kube-system   hubble-ui-59bb4cb67b-qknmv     11094               ready            172.16.2.179

$c0 endpoint list
ENDPOINT   POLICY (ingress)   POLICY (egress)   IDENTITY   LABELS (source:key[=value])                                              IPv6   IPv4           STATUS
           ENFORCEMENT        ENFORCEMENT
543        Disabled           Disabled          4167       k8s:app=netpod                                                                  172.16.0.235   ready
                                                           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
1533       Disabled           Disabled          1          k8s:node-role.kubernetes.io/control-plane                                                      ready
                                                           k8s:node.kubernetes.io/exclude-from-external-load-balancers
                                                           reserved:host
3599       Disabled           Disabled          4          reserved:health                                                                 172.16.0.75    ready

$c0 bpf endpoint list
IP ADDRESS        LOCAL ENDPOINT INFO
192.168.10.10:0   (localhost)
172.16.0.235:0    id=543   sec_id=4167  flags=0x0000 ifindex=10  mac=9E:2B:22:46:EC:A3 nodemac=EA:68:2A:30:09:BF
172.16.0.229:0    (localhost)
172.16.0.75:0     id=3599  sec_id=4     flags=0x0000 ifindex=8   mac=FA:1B:DC:45:D4:4A nodemac=3E:1C:AB:C9:28:3E

$c0 map get cilium_lxc
Key              Value                                                                                            State   Error
172.16.0.235:0   id=543   sec_id=4167  flags=0x0000 ifindex=10  mac=9E:2B:22:46:EC:A3 nodemac=EA:68:2A:30:09:BF   sync
172.16.0.75:0    id=3599  sec_id=4     flags=0x0000 ifindex=8   mac=FA:1B:DC:45:D4:4A nodemac=3E:1C:AB:C9:28:3E   sync

$c0 ip list
IP                  IDENTITY                                                                     SOURCE
0.0.0.0/0           reserved:world
172.16.0.75/32      reserved:health
172.16.0.229/32     reserved:host
                    reserved:kube-apiserver
172.16.0.235/32     k8s:app=netpod                                                               custom-resource
                    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
172.16.1.47/32      k8s:app=webpod                                                               custom-resource
                    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
172.16.1.229/32     reserved:remote-node
172.16.1.230/32     reserved:health
172.16.2.65/32      k8s:app.kubernetes.io/name=hubble-relay                                      custom-resource
                    k8s:app.kubernetes.io/part-of=cilium
                    k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system
                    k8s:io.cilium.k8s.policy.cluster=default
                    k8s:io.cilium.k8s.policy.serviceaccount=hubble-relay
                    k8s:io.kubernetes.pod.namespace=kube-system
                    k8s:k8s-app=hubble-relay
172.16.2.104/32     k8s:app=webpod                                                               custom-resource
                    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
172.16.2.129/32     reserved:health
172.16.2.134/32     reserved:remote-node
172.16.2.179/32     k8s:app.kubernetes.io/name=hubble-ui                                         custom-resource
                    k8s:app.kubernetes.io/part-of=cilium
                    k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system
                    k8s:io.cilium.k8s.policy.cluster=default
                    k8s:io.cilium.k8s.policy.serviceaccount=hubble-ui
                    k8s:io.kubernetes.pod.namespace=kube-system
                    k8s:k8s-app=hubble-ui
172.16.2.184/32     k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system   custom-resource
                    k8s:io.cilium.k8s.policy.cluster=default
                    k8s:io.cilium.k8s.policy.serviceaccount=coredns
                    k8s:io.kubernetes.pod.namespace=kube-system
                    k8s:k8s-app=kube-dns
172.16.2.194/32     k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=kube-system   custom-resource
                    k8s:io.cilium.k8s.policy.cluster=default
                    k8s:io.cilium.k8s.policy.serviceaccount=coredns
                    k8s:io.kubernetes.pod.namespace=kube-system
                    k8s:k8s-app=kube-dns
192.168.10.10/32    reserved:host
                    reserved:kube-apiserver
192.168.10.101/32   reserved:remote-node
192.168.10.102/32   reserved:remote-node
  • 파드 변수 지정
# 테스트 파드들 IP
NETPODIP=$(kubectl get pods netpod -o jsonpath='{.status.podIP}')
WEBPOD1IP=$(kubectl get pods webpod1 -o jsonpath='{.status.podIP}')
WEBPOD2IP=$(kubectl get pods webpod2 -o jsonpath='{.status.podIP}')

# 단축키(alias) 지정
alias p0="kubectl exec -it netpod  -- "
alias p1="kubectl exec -it webpod1 -- "
alias p2="kubectl exec -it webpod2 -- "
  • 파드의 ARP 동작 확인 ← Hubble Web UI 모니터링
# netpod 네트워크 정보 확인
p0 ip -c -4 addr
p0 route -n
p0 ping -c 1 $WEBPOD1IP && p0 ping -c 1 $WEBPOD2IP
p0 curl -s $WEBPOD1IP && p0 curl -s $WEBPOD2IP
p0 curl -s $WEBPOD1IP:8080 ; p0 curl -s $WEBPOD2IP:8080
p0 ping -c 1 8.8.8.8 && p0 curl -s wttr.in/seoul
p0 ip -c neigh

# hubble cli 확인
hubble observe --pod netpod
hubble observe --pod webpod1
hubble observe --pod webpod2

# BPF maps : 목적지 파드와 통신 시 어느곳으로 보내야 될지 확인할 수 있다
c0 map get cilium_ipcache
c0 map get cilium_ipcache | grep $WEBPOD1IP

# netpod 의 LXC 변수 지정
LXC=<k8s-s의 가장 나중에 lxc 이름>
LXC=lxc35dd9f4e9602

# 파드와 veth pair 에 IP가 없다! proxy_arp 도 없다! 하지만 GW MAC 요청 시 lxc(veth)의 MAC 으로 응답이 온다! >> eBPF Magic!
# Cilium hijacks ARP table of POD1, forces the next hop to be the peer end (host side) of the veth pair.
ip -c addr show dev $LXC

10: lxc35dd9f4e9602@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default qlen 1000
    link/ether ea:68:2a:30:09:bf brd ff:ff:ff:ff:ff:ff link-netns cni-3e105af7-2b32-fe63-a985-50e366811b8b
    inet6 fe80::e868:2aff:fe30:9bf/64 scope link
       valid_lft forever preferred_lft forever
      

  • Node’s eBPF programs
# list of eBPF programs
c0bpf net show
c0bpf net show | grep $LXC
lxc35dd9f4e9602(10) tcx/ingress cil_from_container prog_id 1360 link_id 23
lxc35dd9f4e9602(10) tcx/egress cil_to_container prog_id 1362 link_id 24

# Use bpftool prog show id to view additional information about a program, including a list of attached eBPF maps:
c0bpf prog show id <출력된 prog id 입력>
c0bpf prog show id 1529
1360: sched_cls  name cil_from_container  tag 0d99c2edeb2964bd  gpl
	loaded_at 2024-10-23T14:10:08+0000  uid 0
	xlated 728B  jited 545B  memlock 4096B  map_ids 176,66
	btf_id 348

c0bpf map list
...
66: percpu_hash  name cilium_metrics  flags 0x1
	key 8B  value 16B  max_entries 1024  memlock 19384B
...
176: prog_array  name cilium_calls_00  flags 0x0
	key 4B  value 4B  max_entries 50  memlock 720B
	owner_prog_type sched_cls  owner jited
...

4. 서비스 통신 확인

4.1 Socket-Based LoadBalancing 소개

그림 왼쪽(네트워크 기반 로드밸런싱) vs 오른쪽(소켓 기반 로드밸런싱)

Pod1 안에서 동작하는 앱이 connect() 시스템콜을 이용하여 소켓을 연결할 때 목적지 주소가 서비스 주소(10.10.8.55)이면 소켓의 목적지 주소를 바로 백엔드 주소(10.0.0.31)로 설정한다. 이후 앱에서 해당 소켓을 통해 보내는 모든 패킷의 목적지 주소는 이미 백엔드 주소(10.0.0.31)로 설정되어 있기 때문에 중간에 DNAT 변환 및 역변환 과정이 필요없어진다.

Socket operations : BPF socket operations program 은 root cgroup 에 연결되며 TCP event(ESTABLISHED) 에서 실행한다.

Socket send/recv : The socket send/recv hook 은 TCP socket 의 모든 송수신 작업에서 실행, hook 에서 검사/삭제/리다이렉션을 할 수 있다

connect() 와 sendto() 소켓 함수에 연결된 프로그램(connect4, sendmsg4)에서는 소켓의 목적지 주소를 백엔드 주소와 포트로 변환하고, cilium_lb4_backends 맵에 백엔드 주소와 포트를 등록해놓는다. 이후 recvmsg() 소켓 함수에 연결된 프로그램(recvmsg4)에서는 cilium_lb4_reverse_nat 맵을 이용해서 목적지 주소와 포트를 다시 서비스 주소와 포트로 변환함

4.2 서비스 생성 및 접속 확인

  • 서비스 생성
cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Service
metadata:
  name: svc
spec:
  ports:
    - name: svc-webport
      port: 80
      targetPort: 80
  selector:
    app: webpod
  type: ClusterIP
EOF
  • 서비스 접속 확인
# 서비스 생성 확인
kubectl get svc,ep svc

# 노드에 iptables 더이상 KUBE-SVC rule 이 생성되지 않는다!
iptables-save | grep KUBE-SVC
iptables-save | grep CILIUM

# 서비스IP를 변수에 지정
SVCIP=$(kubectl get svc svc -o jsonpath='{.spec.clusterIP}')

# Pod1 에서 Service(ClusterIP) 접속 트래픽 발생
kubectl exec netpod -- curl -s $SVCIP
kubectl exec netpod -- curl -s $SVCIP | grep Hostname

# 지속적으로 접속 트래픽 발생
SVCIP=$(kubectl get svc svc -o jsonpath='{.spec.clusterIP}')
while true; do kubectl exec netpod -- curl -s $SVCIP | grep Hostname;echo "-----";sleep 1;done

# 파드에서 SVC(ClusterIP) 접속 시 tcpdump 로 확인 >> 파드 내부 캡쳐인데, SVC(10.108.12.195)는 보이지 않고, DNAT 된 web-pod 의 IP가 확인! Magic!
kubectl exec netpod -- tcpdump -enni any -q
	08:54:55.454271 eth0  Out ifindex 14 92:1a:b9:94:94:37 172.16.0.162.44718 > 172.16.1.234.80: tcp 0
	08:54:55.454798 eth0  In  ifindex 14 8a:0c:cc:a9:21:1a 172.16.1.234.80 > 172.16.0.162.44718: tcp 0
	08:54:55.455030 eth0  Out ifindex 14 92:1a:b9:94:94:37 172.16.0.162.44718 > 172.16.1.234.80: tcp 77
...

service ip인 10.10.214.64가 tcpdump log에서 확인되지 않는다!


kubectl exec netpod -- sh -c "ngrep -tW byline -d eth0 '' 'tcp port 80'"
T 2024/10/20 08:07:36.663329 172.16.0.132:59964 -> 172.16.1.53:80 [AP] #34
GET / HTTP/1.1.
Host: 10.10.124.15.
User-Agent: curl/8.7.1.
Accept: */*.


# 서비스 정보 확인
c0 service list
ID   Frontend              Service Type   Backend
15   10.10.214.64:80       ClusterIP      1 => 172.16.2.104:80 (active)
                                          2 => 172.16.1.47:80 (active)
                                          
c0 bpf lb list
SERVICE ADDRESS       BACKEND ADDRESS
10.108.12.195:80      0.0.0.0:0 (15) (0) [ClusterIP, non-routable]
                      172.16.2.104:80 (15) (1)
                      172.16.1.47:80 (15) (2)
# BPF maps
c0 map list --verbose
c0 map list --verbose | grep lb
c0 map get cilium_lb4_services_v2
c0 map get cilium_lb4_backends_v3
c0 map get cilium_lb4_reverse_nat
c0 map get cilium_lb4_reverse_sk
c0 map get cilium_lxc
c0 map get cilium_ipcache
  • strace 시스템 콜 트레이싱 도구를 통해 파드 내에서 동작 확인
# syacall 호출 확인
kubectl exec netpod -- strace -c curl -s $SVCIP
Hostname: webpod2
IP: 127.0.0.1
IP: ::1
IP: 172.16.2.104
IP: fe80::54ef:65ff:fef5:67fd
RemoteAddr: 172.16.0.235:45872
GET / HTTP/1.1
Host: 10.10.214.64
User-Agent: curl/8.7.1
Accept: */*

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 53.56    0.003825         273        14           mprotect
 18.74    0.001338          16        79           mmap
  5.81    0.000415           7        56        32 open
  5.42    0.000387          14        27           munmap
  5.10    0.000364          11        31           lseek
  2.35    0.000168           7        23           fcntl
  2.30    0.000164           6        27           read
  1.32    0.000094          94         1         1 connect
  1.16    0.000083           3        27           close
  0.95    0.000068          17         4           setsockopt
  0.80    0.000057           4        12           fstat
  0.73    0.000052           1        31           rt_sigaction
  0.39    0.000028          28         1           pipe
  0.35    0.000025          25         1           socket
  0.24    0.000017           1        10           readv
  0.15    0.000011           1         6           poll
  0.14    0.000010           5         2           geteuid
  0.11    0.000008           2         3           brk
  0.10    0.000007           1         4           getsockname
  0.08    0.000006           6         1           getuid
  0.07    0.000005           1         5           getrandom
  0.07    0.000005           5         1           getgid
  0.06    0.000004           4         1           getegid
  0.00    0.000000           0         1           writev
  0.00    0.000000           0         3         3 ioctl
  0.00    0.000000           0         1           sendto
  0.00    0.000000           0         1           recvfrom
  0.00    0.000000           0         1           getsockopt
  0.00    0.000000           0         1           execve
  0.00    0.000000           0        12           rt_sigprocmask
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           set_tid_address
------ ----------- ----------- --------- --------- ----------------
100.00    0.007141          18       389        36 total

# 출력 내용을 편집기에서 확인(검색)
kubectl exec netpod -- strace -s 65535 -f -tt curl -s $SVCIP
------------------------------------------------------------
15:49:48.336836 connect(5, {sa_family=AF_INET, sin_port=htons(80), sin_addr=inet_addr("10.10.214.64")}, 16) = -1 EINPROGRESS (Operation in progress)
15:49:48.337352 getsockname(5, {sa_family=AF_INET, sin_port=htons(34530), sin_addr=inet_addr("172.16.0.235")}, [128 => 16]) = 0# 소켓 주소 가져오기
...
15:49:48.339291 getsockopt(5, SOL_SOCKET, SO_ERROR, [0], [4]) = 0
15:49:48.339406 getsockname(5, {sa_family=AF_INET, sin_port=htons(34530), sin_addr=inet_addr("172.16.0.235")}, [128 => 16]) = 0# 소켓 주소 한번더 확인
...

# 특정 이벤트 : -e
kubectl exec netpod -- strace -e trace=connect curl -s $SVCIP
kubectl exec netpod -- strace -e trace=getsockname curl -s $SVCIP

5. Running Prometheus & Grafana

# 배포
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/1.16.3/examples/kubernetes/addons/prometheus/monitoring-example.yaml
kubectl get all -n cilium-monitoring

# 파드와 서비스 확인
kubectl get pod,svc,ep -o wide -n cilium-monitoring

# NodePort 설정
kubectl patch svc grafana -n cilium-monitoring -p '{"spec": {"type": "NodePort"}}'
kubectl patch svc prometheus -n cilium-monitoring -p '{"spec": {"type": "NodePort"}}'

# Grafana 웹 접속
GPT=$(kubectl get svc -n cilium-monitoring grafana -o jsonpath={.spec.ports[0].nodePort})
echo -e "Grafana URL = http://$(curl -s ipinfo.io/ip):$GPT"

# Prometheus 웹 접속 정보 확인
PPT=$(kubectl get svc -n cilium-monitoring prometheus -o jsonpath={.spec.ports[0].nodePort})
echo -e "Prometheus URL = http://$(curl -s ipinfo.io/ip):$PPT"

Grafana URL = http://43.201.15.39:30123
Prometheus URL = http://43.201.15.39:30503
  • Prometheus 웹 접속 정보 확인

  • Grafana 웹 접속

6. Network Policy (L3, L4, L7)

6.1 Security

cilium은 다음과 같이 굉장히 다양한 보안 기능들을 제공합니다.

  1. 레이어 3/4 (L3/L4) 네트워크 보안 정책
    • Cilium은 IP 주소 및 포트 기반의 L3/L4 레벨 네트워크 정책을 정의하고 관리할 수 있습니다. 이 정책을 통해, 특정 포드나 애플리케이션이 허용된 IP와 포트 범위 내에서만 통신할 수 있게 제어하여, 트래픽을 필터링하고, 승인되지 않은 네트워크 접근을 차단합니다.
    • 예를 들어, 특정 포드가 특정 IP 주소와 특정 포트에서만 통신할 수 있도록 허용하거나 제한할 수 있습니다.

  2. 레이어 7 (L7) 애플리케이션 보안 정책
    • Cilium은 HTTP, gRPC, Kafka, DNS와 같은 애플리케이션 레벨 트래픽(L7)에 대한 보안 정책도 지원합니다. 이를 통해 애플리케이션 프로토콜을 인식하고, 트래픽 패턴을 기반으로 세밀한 보안 제어를 할 수 있습니다.
    • 예를 들어, 특정 API 엔드포인트나 HTTP 메서드(GET, POST 등)에 대한 접근을 제어하거나, 특정 Kafka 토픽에 대한 접근을 제한할 수 있습니다.

  3. 분산형 네트워크 정책
    • Cilium은 Kubernetes 네트워크 정책(Kubernetes Network Policies) 및 Cilium 네트워크 정책을 사용하여, 컨테이너 간 트래픽 흐름을 세밀하게 제어할 수 있습니다. 이를 통해 클러스터 내부뿐만 아니라, 외부에서 들어오는 트래픽까지 관리할 수 있습니다.
    • 정책은 포드의 레이블을 기반으로 설정할 수 있으며, 이를 통해 동적으로 변화하는 컨테이너 환경에서도 유연한 네트워크 보안 정책 적용이 가능합니다.

  4. 투명한 보안 정책 시행
    • Cilium은 eBPF를 활용하여 리눅스 커널 내에서 직접 보안 정책을 적용합니다. 이를 통해 네트워크 스택에서 발생하는 추가적인 오버헤드 없이 보안 정책을 빠르고 효율적으로 시행할 수 있습니다. 이 방식은 특히 성능에 민감한 대규모 환경에서 유리합니다.

  5. 네트워크 정책 감사 및 가시성
    • Hubble과 통합된 Cilium의 보안 기능은 네트워크 정책의 실시간 상태를 모니터링하고, 정책에 따라 트래픽이 허용되었는지 차단되었는지에 대한 감사 로그를 제공합니다. 이를 통해 네트워크 상에서 발생하는 모든 트래픽 흐름을 투명하게 분석할 수 있고, 보안 정책의 적용 상태를 실시간으로 파악할 수 있습니다.
    • 트래픽이 왜 차단되었는지, 어떤 정책에 의해 허용되었는지 등의 정보를 쉽게 확인할 수 있어 보안 문제 진단 및 사고 대응이 신속하게 이루어집니다.

  6. 암호화된 네트워크 트래픽 (Encryption)
    • Cilium은 IPSec이나 WireGuard를 이용한 네트워크 트래픽 암호화를 지원합니다. 이를 통해 노드 간의 네트워크 트래픽이 외부에서 읽히거나 변조되는 것을 방지할 수 있습니다.
    • 암호화는 네트워크 레이어에서 투명하게 처리되며, 클러스터 내의 노드 간 통신에 추가적인 보안 계층을 제공합니다.

  7. DDoS 공격 방어 및 패킷 필터링
    • Cilium은 DDoS 공격이나 트래픽 폭주와 같은 상황에서 네트워크 트래픽을 세밀하게 필터링하고, 불필요한 트래픽을 효율적으로 차단할 수 있습니다. eBPF를 사용해 커널 레벨에서 트래픽을 실시간으로 모니터링하며, 특정 패턴의 트래픽을 빠르게 감지하고 차단할 수 있습니다.
    • 이를 통해 대규모 공격으로부터 클러스터를 보호하고, 서비스의 가용성을 유지할 수 있습니다.

  8. 서비스 메시 보안
    • Cilium은 서비스 메시와의 통합을 통해 L7 트래픽에 대한 보안 정책을 적용할 수 있습니다. Envoy와 같은 서비스 메시 프록시와 통합되어, 서비스 간 트래픽을 세밀하게 관리하고, 각 서비스 간의 보안 경계를 강화할 수 있습니다.
    • 서비스 메시 환경에서 마이크로서비스 간 통신을 보호하고, 트래픽을 모니터링하여 보안 사고를 예방할 수 있습니다.

  9. 멀티 테넌시(Multi-tenancy) 보안
    • Cilium은 여러 사용자나 애플리케이션이 동일한 네트워크 환경을 공유하는 경우에도, 각 테넌트 간의 네트워크 트래픽을 격리하여 보안을 유지합니다. 이 기능은 멀티 테넌시 환경에서 개별 테넌트 간에 트래픽이 서로 혼재되지 않도록 보호하는 데 필수적입니다.

6.2 Multiple level 보안 제공

  1. ID 기반
    이 기능은 레이어 3에서 Identity 기반의 접근 제어를 가능하게 합니다. 레이블은 애플리케이션의 역할, 환경, 위치 등을 나타내며, 이를 통해 네트워크 정책을 정의합니다. 예를 들어, role=frontend 레이블을 가진 모든 엔드포인트는 role=backend 레이블을 가진 엔드포인트로 연결할 수 있도록 설정할 수 있습니다.

  2. 포트 기반
    Cilium은 Kubernetes에서 제공하는 기본 네트워크 정책도 포트 기반 정책을 지원하며 정책을 더 세밀하게 제어할 수 있도록 도와줍니다. 특히 Cilium은 L3/L4 네트워크 정책을 통해 IP 주소와 포트를 결합한 보안 정책을 만들 수 있습니다.

  3. 애플리케이션 기반
    Cilium은 eBPF 기술을 사용하여 이러한 애플리케이션 레벨(L7) 트래픽을 제어할 수 있습니다. HTTP, gRPC, Kafka, DNS와 같은 다양한 애플리케이션 프로토콜에 대해 세밀한 정책을 설정할 수 있으며, 이를 통해 특정 API 호출이나 애플리케이션 간의 통신을 더 정밀하게 제어할 수 있습니다.

Cilium에서는 이러한 L7 기반 정책을 eBPF와 Envoy 프록시를 활용하여 구현합니다.

6.3 애플리케이션 기반 정책 생성 과정

  1. 트래픽 가로채기 (eBPF 기반 트래픽 인식)
    • 네트워크를 통해 들어오는 트래픽은 eBPF 프로그램에 의해 가로채집니다.
    • Cilium은 이 단계에서 트래픽이 어떤 애플리케이션 프로토콜을 사용하는지 파악합니다. 예를 들어, HTTP 요청인지 Kafka 메시지인지 또는 다른 프로토콜인지를 인식할 수 있습니다.
    • 이 트래픽이 L3/L4 기반 정책을 통과했을 경우, L7 정책이 존재하는지 확인한 후 프록시(Envoy)로 트래픽을 전달합니다.

  2. 프록시(Envoy)로 트래픽 전달
    • Envoy는 트래픽을 애플리케이션 레벨에서 분석합니다. 예를 들어, HTTP 요청의 경우 메서드(GET, POST), 경로, 헤더 등을 분석하고, gRPC 호출의 경우 서비스와 메서드를 분석할 수 있습니다.
    • Cilium은 Envoy 프록시를 통해 트래픽이 애플리케이션 기반 정책과 일치하는지 검사하고, 허용 또는 차단 여부를 결정합니다.

  3. 애플리케이션 정책 적용
    • 트래픽이 분석된 후, Cilium이 정의한 애플리케이션 기반 정책이 적용됩니다.
    • 예를 들어, 특정 HTTP 요청 경로로만 접근을 허용하거나, 특정 Kafka 토픽에 대한 메시지 읽기/쓰기를 제어하는 정책이 적용될 수 있습니다.

  4. 정책 결과에 따른 트래픽 허용 또는 차단
    • Envoy 프록시가 트래픽을 분석한 결과, 정책에 맞으면 트래픽은 애플리케이션으로 전달됩니다.
    • 정책에 어긋나면, 해당 트래픽은 차단되고 애플리케이션에 도달하지 않으며, 필요 시 로그로 기록됩니다.

6.4 Network Policy 관련 eBPF Datapath

eBPF Datapath는 커널에서 직접 트래픽을 처리하여, 사용자 공간에서 발생하는 성능 오버헤드를 최소화하면서 네트워크 트래픽을 제어하는 기술입니다. 전통적으로, 네트워크 정책을 적용하기 위해서는 IPTables 같은 툴을 통해 사용자 공간에서 패킷을 분석하고, 규칙을 적용한 후 다시 커널로 트래픽을 전달해야 했습니다. 이 과정에서 성능 문제가 발생할 수 있는데요. 그러나 eBPF Datapath는 이와 달리 네트워크 트래픽을 커널에서 실시간으로 분석하고 처리하여 네트워크 정책을 적용합니다. 이를 통해 성능을 최적화하면서도 보안을 강화할 수 있습니다.

  • Prefilter: An XDP program and provides a set of prefilter rules used to filter traffic from the network for best performance.
  • Endpoint Policy: 정책에 따라 패킷을 차단/전달하거나, 서비스로 전달하거나, L7 로 정책 전달 할 수 있다.
    • the Cilium datapath responsible for mapping packets to identities and enforcing L3 and L4 policies.
  • L7 Policy: The L7 Policy object redirect proxy traffic to a Cilium userspace proxy instance. Cilium uses an Envoy instance as its userspace proxy. Envoy will then either forward the traffic or generate appropriate reject messages based on the configured L7 policy.

6.5 Deploy the Demo Application(실습)

스타워즈에서 영감 받은 예제 : 디플로이먼트(웹 서버, deathstar, replicas 2), 파드(xwing, tiefighter), 서비스(ClusterIP, service/deathstar)

# 배포
kubectl create -f https://raw.githubusercontent.com/cilium/cilium/1.16.3/examples/minikube/http-sw-app.yaml
kubectl get all

# 파드 라벨 확인
kubectl get pod --show-labels
NAME                         READY   STATUS    RESTARTS   AGE    LABELS
deathstar-689f66b57d-4rwkf   1/1     Running   0          113s   app.kubernetes.io/name=deathstar,class=deathstar,org=empire,pod-template-hash=689f66b57d
deathstar-689f66b57d-8p2l5   1/1     Running   0          113s   app.kubernetes.io/name=deathstar,class=deathstar,org=empire,pod-template-hash=689f66b57d
tiefighter                   1/1     Running   0          113s   app.kubernetes.io/name=tiefighter,class=tiefighter,org=empire
xwing                        1/1     Running   0          113s   app.kubernetes.io/name=xwing,class=xwing,org=alliance

# cilium endpoint 확인
kubectl get ciliumendpoints
NAME                         SECURITY IDENTITY   ENDPOINT STATE   IPV4           IPV6
deathstar-689f66b57d-9mbhb   19092               ready            172.16.2.21
deathstar-689f66b57d-dqgxq   19092               ready            172.16.1.10
tiefighter                   49569               ready            172.16.1.252
xwing                        22863               ready            172.16.1.104

c1 endpoint list

c2 endpoint list


# 데스스타 SVC(ClusterIP) 접속하여 웹 파드 연결 확인 >> Hubble UI 에서 실시간 확인해보자!
kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Ship landed

kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Ship landed

# 확인
hubble observe

6.5.1 Identity-Aware and HTTP-Aware Policy Enforcement Apply an L3/L4 Policy

  • Cilium 에서는 Endpoint IP 대신, 파드Labels(라벨)을 사용(기준)하여 보안 정책을 적용합니다
  • IP/Port 필터링을 L3/L4 네트워크 정책이라고 한다
  • 아래 처럼 'org=empire' Labels(라벨) 부착된 파드만 허용해보자
  • Cilium performs stateful connection tracking 이므로 리턴 트래픽은 자동으로 허용됨
# L3/L4 정책 생성
cat <<EOF | kubectl apply -f - 
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "rule1"
spec:
  description: "L3-L4 policy to restrict deathstar access to empire ships only"
  endpointSelector:
    matchLabels:
      org: empire
      class: deathstar
  ingress:
  - fromEndpoints:
    - matchLabels:
        org: empire
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
EOF

# 정책 확인
kubectl get cnp
kc describe cnp rule1
c0 policy get


# 파드 curl 접속 시도 시 파드 sh 접속 후 curl 시도하자!
# 데스스타 SVC(ClusterIP) 접속하여 웹 파드 연결 확인 >> Hubble UI 에서 drop 확인!
kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Ship landed

kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
drop

# hubble cli 모니터링 
hubble observe --pod xwing
hubble observe --pod tiefighter
hubble observe --pod deathstar
Dec  2 05:36:24.490: default/xwing:55464 <> default/deathstar-c74d84667-t7msh:80 Policy denied DROPPED (TCP Flags: SYN)
Dec  2 05:36:24.490: default/xwing:55464 <> default/deathstar-c74d84667-t7msh:80 Policy denied DROPPED (TCP Flags: SYN)

hubble observe --pod deathstar --verdict DROPPED
Oct 23 16:39:02.846: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) policy-verdict:none INGRESS DENIED (TCP Flags: SYN)
Oct 23 16:39:02.847: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) Policy denied DROPPED (TCP Flags: SYN)
Oct 23 16:39:04.895: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) policy-verdict:none INGRESS DENIED (TCP Flags: SYN)
Oct 23 16:39:04.895: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) Policy denied DROPPED (TCP Flags: SYN)
Oct 23 16:39:08.926: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) policy-verdict:none INGRESS DENIED (TCP Flags: SYN)
Oct 23 16:39:08.926: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) Policy denied DROPPED (TCP Flags: SYN)
Oct 23 16:39:17.246: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) policy-verdict:none INGRESS DENIED (TCP Flags: SYN)
Oct 23 16:39:17.246: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) Policy denied DROPPED (TCP Flags: SYN)
Oct 23 16:39:33.631: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) policy-verdict:none INGRESS DENIED (TCP Flags: SYN)
Oct 23 16:39:33.631: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) Policy denied DROPPED (TCP Flags: SYN)
Oct 23 16:40:05.886: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) policy-verdict:none INGRESS DENIED (TCP Flags: SYN)
Oct 23 16:40:05.886: default/xwing:46186 (ID:22863) <> default/deathstar-689f66b57d-9mbhb:80 (ID:19092) Policy denied DROPPED (TCP Flags: SYN)

Inspecting the Policy
# If we run cilium endpoint list again we will see that the pods with the label org=empire and class=deathstar
# now have ingress policy enforcement enabled as per the policy above.

# endpoint list 에서 정책 적용 확인
c1 endpoint list | grep deathstar
249        Enabled            Disabled          19092      k8s:app.kubernetes.io/name=deathstar                                                      172.16.1.10    ready
                                                           k8s:class=deathstar
                                                     
c2 endpoint list
ENDPOINT   POLICY (ingress)   POLICY (egress)   IDENTITY   LABELS (source:key[=value])                                              IPv6   IPv4           STATUS
           ENFORCEMENT        ENFORCEMENT
312        Disabled           Disabled          18300      k8s:class=xwing                                                                 172.16.2.161   ready
                                                           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:org=alliance

1972       Enabled            Disabled          21144      k8s:class=deathstar                                                             172.16.2.66    ready
                                                           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:org=empirec2 endpoint list

6.5.2 Identity-Aware and HTTP-Aware Policy Enforcement (L7)

  • HTTP L7 필터링을 적용 : 아래 처럼 PUT /v1/exhaust-port 요청을 차단!
# 데스스타 SVC(ClusterIP) 접속
kubectl exec tiefighter -- curl -s -XPUT deathstar.default.svc.cluster.local/v1/exhaust-port
Panic: deathstar exploded
...

# POST /v1/request-landing API 호출만 허용 정책으로 기존 정책 내용을 업데이트(configured)!
cat <<EOF | kubectl apply -f - 
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
  name: "rule1"
spec:
  description: "L7 policy to restrict access to specific HTTP call"
  endpointSelector:
    matchLabels:
      org: empire
      class: deathstar
  ingress:
  - fromEndpoints:
    - matchLabels:
        org: empire
    toPorts:
    - ports:
      - port: "80"
        protocol: TCP
      rules:
        http:
        - method: "POST"
          path: "/v1/request-landing"
EOF

# 정책 확인
kc describe ciliumnetworkpolicies
c0 policy get

# 모니터링
c1 monitor -v --type l7
c2 monitor -v --type l7
<- Request http from 0 ([k8s:io.cilium.k8s.policy.cluster=default k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.kubernetes.pod.namespace=default k8s:org=empire k8s:class=tiefighter k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default]) to 1972 ([k8s:class=deathstar k8s:org=empire k8s:io.cilium.k8s.namespace.labels.kubernetes.io/metadata.name=default k8s:io.kubernetes.pod.namespace=default k8s:io.cilium.k8s.policy.serviceaccount=default k8s:io.cilium.k8s.policy.cluster=default]), identity 42720->21144, verdict Denied PUT http://deathstar.default.svc.cluster.local/v1/exhaust-port => 403
 => 403
hubble observe --pod deathstar
hubble observe --pod deathstar --verdict DROPPED


# 접근 테스트
kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
Ship landed

kubectl exec tiefighter -- curl -s -XPUT deathstar.default.svc.cluster.local/v1/exhaust-port
Access denied

## hubble cli 에 차단 로그 확인
hubble observe --pod deathstar --verdict DROPPED
Oct 23 16:50:02.603: default/tiefighter:59092 (ID:49569) -> default/deathstar-689f66b57d-dqgxq:80 (ID:19092) http-request DROPPED (HTTP/1.1 PUT http://deathstar.default.svc.cluster.local/v1/exhaust-port)

hubble observe --pod deathstar --protocol http
Oct 23 16:50:02.603: default/tiefighter:59092 (ID:49569) -> default/deathstar-689f66b57d-dqgxq:80 (ID:19092) http-request DROPPED (HTTP/1.1 PUT http://deathstar.default.svc.cluster.local/v1/exhaust-port)

7. Bandwidth Manager

  • bandwidth manager to optimize TCP and UDP workloads and efficiently rate limit individual Pods - EDT((Earliest Departure Time) 와 eBPF 사용
  • kubernetes.io/egress-bandwidth Pod annotation which is enforced on egress at the native host networking devices.
  • ~~kubernetes.io/ingress-bandwidth~~ annotation is not supported
  • direct routing mode, tunneling mode 둘 다 지원
  • Limitations : L7 Cilium Network Policies
  • 설정 및 확인
# 인터페이스 tc qdisc 확인
tc qdisc show dev ens5
qdisc mq 0: root
qdisc fq_codel 0: parent :4 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
qdisc fq_codel 0: parent :3 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
qdisc fq_codel 0: parent :2 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64
qdisc fq_codel 0: parent :1 limit 10240p flows 1024 quantum 1514 target 5ms interval 100ms memory_limit 32Mb ecn drop_batch 64

# 설정
helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values --set bandwidthManager.enabled=true

# 적용 확인
cilium config view | grep bandwidth
enable-bandwidth-manager                       true

# egress bandwidth limitation 동작하는 인터페이스 확인
c0 status | grep  BandwidthManager
BandwidthManager:        EDT with BPF [CUBIC] [ens5]

# 인터페이스 tc qdisc 확인 : 설정 전후 옵션값들이 상당히 추가된다
tc qdisc
tc qdisc show dev ens5
qdisc mq 8002: root
qdisc fq 8005: parent 8002:2 limit 10000p flow_limit 100p buckets 32768 orphan_mask 1023 quantum 18030b initial_quantum 90150b low_rate_threshold 550Kbit refill_delay 40ms timer_slack 10us horizon 2s horizon_drop
qdisc fq 8003: parent 8002:4 limit 10000p flow_limit 100p buckets 32768 orphan_mask 1023 quantum 18030b initial_quantum 90150b low_rate_threshold 550Kbit refill_delay 40ms timer_slack 10us horizon 2s horizon_drop
qdisc fq 8004: parent 8002:3 limit 10000p flow_limit 100p buckets 32768 orphan_mask 1023 quantum 18030b initial_quantum 90150b low_rate_threshold 550Kbit refill_delay 40ms timer_slack 10us horizon 2s horizon_drop
qdisc fq 8006: parent 8002:1 limit 10000p flow_limit 100p buckets 32768 orphan_mask 1023 quantum 18030b initial_quantum 90150b low_rate_threshold 550Kbit refill_delay 40ms timer_slack 10us horizon 2s horizon_drop
  • 동작 및 확인
# 테스트를 위한 트래픽 발생 서버/클라이언트 파드 생성
cat <<EOF | kubectl apply -f -
---
apiVersion: v1
kind: Pod
metadata:
  annotations:
    # Limits egress bandwidth to 10Mbit/s.
    kubernetes.io/egress-bandwidth: "10M"
  labels:
    # This pod will act as server.
    app.kubernetes.io/name: netperf-server
  name: netperf-server
spec:
  containers:
  - name: netperf
    image: cilium/netperf
    ports:
    - containerPort: 12865
---
apiVersion: v1
kind: Pod
metadata:
  # This Pod will act as client.
  name: netperf-client
spec:
  affinity:
    # Prevents the client from being scheduled to the
    # same node as the server.
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app.kubernetes.io/name
            operator: In
            values:
            - netperf-server
        topologyKey: kubernetes.io/hostname
  containers:
  - name: netperf
    args:
    - sleep
    - infinity
    image: cilium/netperf
EOF

# egress BW 제한 정보 확인
kubectl describe pod netperf-server | grep Annotations:
Annotations:  kubernetes.io/egress-bandwidth: 10M

# egress BW 제한이 설정된 파드가 있는 cilium pod 에서 제한 정보 확인
c1 bpf bandwidth list
c2 bpf bandwidth list
IDENTITY   EGRESS BANDWIDTH (BitsPerSec)
904        10M

c1 endpoint list
c2 endpoint list
ENDPOINT   POLICY (ingress)   POLICY (egress)   IDENTITY   LABELS (source:key[=value])                 IPv6   IPv4           STATUS
           ENFORCEMENT        ENFORCEMENT
904        Disabled           Disabled          21565      k8s:app.kubernetes.io/name=netperf-server          172.16.2.153   ready

# 트래픽 발생 >> Hubble UI 에서 확인
# egress traffic of the netperf-server Pod has been limited to 10Mbit per second. 
NETPERF_SERVER_IP=$(kubectl get pod netperf-server -o jsonpath='{.status.podIP}')
kubectl exec netperf-client -- netperf -t TCP_MAERTS -H "${NETPERF_SERVER_IP}"
Recv   Send    Send
Socket Socket  Message  Elapsed
Size   Size    Size     Time     Throughput
bytes  bytes   bytes    secs.    10^6bits/sec
131072  16384  16384    10.04       9.88

# 5M 제한 설정 후 테스트
kubectl get pod netperf-server -o json | sed -e 's|10M|5M|g' | kubectl apply -f -
c1 bpf bandwidth list
c2 bpf bandwidth list
kubectl exec netperf-client -- netperf -t TCP_MAERTS -H "${NETPERF_SERVER_IP}"
Recv   Send    Send
Socket Socket  Message  Elapsed
Size   Size    Size     Time     Throughput
bytes  bytes   bytes    secs.    10^6bits/sec
131072 16384   16384    10.09    4.56  # 4.5Mbps 제한 확인!


# 20M 제한 설정 후 테스트
kubectl get pod netperf-server -o json | sed -e 's|5M|20M|g' | kubectl apply -f -
kubectl exec netperf-client -- netperf -t TCP_MAERTS -H "${NETPERF_SERVER_IP}"
Recv   Send    Send
Socket Socket  Message  Elapsed
Size   Size    Size     Time     Throughput
bytes  bytes   bytes    secs.    10^6bits/sec
131072 16384   16384    10.00    18.95 # 19Mbps 제한 확인!

tc qdisc show dev ens5
qdisc mq 8002: root
qdisc fq 8005: parent 8002:2 limit 10000p flow_limit 100p buckets 32768 orphan_mask 1023 quantum 18030b initial_quantum 90150b low_rate_threshold 550Kbit refill_delay 40ms timer_slack 10us horizon 2s horizon_drop
qdisc fq 8003: parent 8002:4 limit 10000p flow_limit 100p buckets 32768 orphan_mask 1023 quantum 18030b initial_quantum 90150b low_rate_threshold 550Kbit refill_delay 40ms timer_slack 10us horizon 2s horizon_drop
qdisc fq 8004: parent 8002:3 limit 10000p flow_limit 100p buckets 32768 orphan_mask 1023 quantum 18030b initial_quantum 90150b low_rate_threshold 550Kbit refill_delay 40ms timer_slack 10us horizon 2s horizon_drop
qdisc fq 8006: parent 8002:1 limit 10000p flow_limit 100p buckets 32768 orphan_mask 1023 quantum 18030b initial_quantum 90150b low_rate_threshold 550Kbit refill_delay 40ms timer_slack 10us horizon 2s horizon_drop


# 삭제
kubectl delete pod netperf-client netperf-server

8. L2 Announcements / L2 Aware LB

  • L2 Announcements는 로컬 영역 네트워크에서 서비스를 표시하고 도달 가능하게 만드는 기능입니다. 이 기능은 주로 사무실 또는 캠퍼스 네트워크와 같이 BGP 기반 라우팅이 없는 네트워크 내에서 온프레미스 배포를 위해 고안되었습니다.
  • 이 기능을 사용하면 ExternalIP 및/또는 LoadBalancer IP에 대한 ARP 쿼리에 응답합니다. 이러한 IP는 여러 노드의 가상 IP(네트워크 장치에 설치되지 않음)이므로 각 서비스에 대해 한 번에 한 노드가 ARP 쿼리에 응답하고 MAC 주소로 응답합니다. 이 노드는 서비스 로드 밸런싱 기능으로 로드 밸런싱을 수행하여 북쪽/남쪽 로드 밸런서 역할을 합니다.
  • NodePort 서비스에 비해 이 기능의 장점은 각 서비스가 고유한 IP를 사용할 수 있으므로 여러 서비스가 동일한 포트 번호를 사용할 수 있다는 것입니다. NodePort를 사용할 때 트래픽을 보낼 호스트를 결정하는 것은 클라이언트에게 달려 있으며 노드가 다운되면 IP+Port 콤보를 사용할 수 없게 됩니다. L2 공지를 사용하면 서비스 VIP가 다른 노드로 간단히 마이그레이션되고 계속 작동합니다.

  • 설정 및 확인
#
helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values \
--set l2announcements.enabled=true --set externalIPs.enabled=true \
--set l2announcements.leaseDuration=3s --set l2announcements.leaseRenewDeadline=1s --set l2announcements.leaseRetryPeriod=200ms
 
#
c0 config --all  |grep L2
EnableL2Announcements             : true
EnableL2NeighDiscovery            : true
L2AnnouncerLeaseDuration          : 3000000000
L2AnnouncerRenewDeadline          : 1000000000
L2AnnouncerRetryPeriod            : 200000000

# CiliumL2AnnouncementPolicy 생성
cat <<EOF | kubectl apply -f - 
apiVersion: "cilium.io/v2alpha1"
kind: CiliumL2AnnouncementPolicy
metadata:
  name: policy1
spec:
  serviceSelector:
    matchLabels:
      color: blue
  nodeSelector:
    matchExpressions:
      - key: node-role.kubernetes.io/control-plane
        operator: DoesNotExist
  interfaces:
  - ^ens[0-9]+
  externalIPs: true
  loadBalancerIPs: true
EOF

# 확인
kubectl get ciliuml2announcementpolicy
kc describe l2announcement

#
cat <<EOF | kubectl apply -f - 
apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
  name: "cilium-pool"
spec:
  allowFirstLastIPs: "No"
  blocks:
  - cidr: "10.10.200.0/29"
EOF

# cilium ip pool 조회
kubectl get CiliumLoadBalancerIPPool
NAME          DISABLED   CONFLICTING   IPS AVAILABLE   AGE
cilium-pool   false      False         3               3m5s
  • 테스트용 파드, 서비스 생성
#
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: webpod1
  labels:
    app: webpod
spec:
  nodeName: k8s-w1
  containers:
  - name: container
    image: traefik/whoami
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Pod
metadata:
  name: webpod2
  labels:
    app: webpod
spec:
  nodeName: k8s-w2
  containers:
  - name: container
    image: traefik/whoami
  terminationGracePeriodSeconds: 0
---
apiVersion: v1
kind: Service
metadata:
  name: svc1
spec:
  ports:
    - name: svc1-webport
      port: 80
      targetPort: 80
  selector:
    app: webpod
  type: LoadBalancer  # 서비스 타입이 LoadBalancer
---
apiVersion: v1
kind: Service
metadata:
  name: svc2
spec:
  ports:
    - name: svc2-webport
      port: 80
      targetPort: 80
  selector:
    app: webpod
  type: LoadBalancer
---
apiVersion: v1
kind: Service
metadata:
  name: svc3
spec:
  ports:
    - name: svc3-webport
      port: 80
      targetPort: 80
  selector:
    app: webpod
  type: LoadBalancer
EOF
  • 접속 확인
#
kubectl get svc,ep
NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP      10.10.0.1       <none>        443/TCP        5h20m
service/svc1         LoadBalancer   10.10.226.228   10.10.200.1   80:32693/TCP   5m30s
service/svc2         LoadBalancer   10.10.166.59    10.10.200.2   80:30107/TCP   5m30s
service/svc3         LoadBalancer   10.10.106.144   10.10.200.3   80:31564/TCP   5m30s

NAME                   ENDPOINTS                        AGE
endpoints/kubernetes   192.168.10.10:6443               5h20m
endpoints/svc1         172.16.1.52:80,172.16.2.196:80   5m30s
endpoints/svc2         172.16.1.52:80,172.16.2.196:80   5m30s
endpoints/svc3         172.16.1.52:80,172.16.2.196:80   5m30s

#
curl -s 10.10.200.1
curl -s 10.10.200.2
curl -s 10.10.200.3

0개의 댓글