Кратко про то, как кастомизировать сетевой стек в Kubernetes с Cilium

Kate

Administrator
Команда форума
Сегодня у нас на повестке дня тема кастомизации сетевого стека в Kubernetes с Cilium.

Cilium — это сетевое решение, которое работает прямо в ядре Linux и построено на основе eBPF. Его главная задача — обеспечить эффективное, а главное, безопасное взаимодействие между подами в кластере Kubernetes. И это не просто замена стандартному kube-proxy. Это полноценный инструмент для построения сетевых политик, мониторинга и кастомизации сетевого стека.

Основные фичи:

  1. Гибкие сетевые политики: можно задать фильтры трафика на уровнях L3 (IP), L4 (TCP/UDP) и L7 (HTTP, gRPC).
  2. Интеграция с Envoy: вместо того, чтобы ограничиваться стандартными функциями, вы можете подключить Envoy для управления сетевыми запросами или даже написать собственные программы на eBPF для уникальных задач.
  3. Устранение узких мест: Cilium устраняет проблемы масштабирования iptables, переходя к использованию eBPF, который выполняет фильтрацию и маршрутизацию пакетов непосредственно в ядре Linux. Вместо линейного перебора правил, как в iptables, eBPF использует хэш-таблицы и карты, которые дают мгновенный доступ к нужным данным. Так трафик обратывается быстрее, с меньшей нагрузкой на процессор и без создания узких мест.

Установим​

Перед тем как начать, убедитесь, что у вас есть:

  • Kubernetes-кластер.
  • Доступ к CLI kubectl.
  • Рабочий helm.
Установим Cilium CLI:

curl -L --remote-name https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64
chmod +x cilium-linux-amd64
sudo mv cilium-linux-amd64 /usr/local/bin/cilium
После устанавливаем Cilium с помощью Helm:

helm repo add cilium https://helm.cilium.io/
helm repo update
helm install cilium cilium/cilium \
--namespace kube-system \
--set kubeProxyReplacement=strict \
--set k8sServiceHost= \
--set k8sServicePort=
Проверяем статус:

kubectl -n kube-system get pods -l k8s-app=cilium
Если все поды в состоянии Running, можно двигаться дальше.

Кастомизация сетевых политик​

Cilium позволяет создавать сетевые политики, которые гораздо мощнее стандартных NetworkPolicy в Kubernetes. Рассмотрим пару примеров.

Ограничение доступа по L7​

Допустим, есть два пода: frontend и backend. Задача — разрешить доступ от frontend к backend только для HTTP GET-запросов.

Создаем CiliumNetworkPolicy:

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-http-get
namespace: default
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: "GET"
path: "/.*"
Применяем политику:

kubectl apply -f allow-http-get.yaml
Теперь фронтенд может обращаться к бэкенду только через GET-запросы. Попробуйте отправить POST-запрос — и он будет заблокирован.

Ограничение исходящего трафика​

Допустим, нужно ограничить доступ из frontend ко всем внешним ресурсам, кроме одного сервиса.

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: restrict-egress
namespace: default
spec:
endpointSelector:
matchLabels:
app: frontend
egress:
- toEntities:
- world
toEndpoints:
- matchLabels:
app: trusted-service
toPorts:
- ports:
- port: "443"
protocol: TCP
Применяем эту политику:

kubectl apply -f restrict-egress.yaml
Теперь трафик из frontend будет ограничен только к определённым ресурсам.

Разрешение доступа только к определенному домену​

Теперь разрешим поду доступ только к домену example.com через HTTPS.

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-specific-domain
namespace: default
spec:
endpointSelector:
matchLabels:
app: frontend
egress:
- toFQDNs:
- matchNames:
- "example.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
Применяем:

kubectl apply -f allow-specific-domain.yaml
Теперь трафик из frontend будет разрешён только к example.com.

Ограничение доступа между namespace​

Допустим, есть два namespace: dev и prod. Нужно запретить всем подам из dev доступ к подам в prod, кроме одного сервиса.

apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: restrict-dev-to-prod
namespace: prod
spec:
endpointSelector:
matchLabels:
app: prod-service
ingress:
- fromEndpoints:
- matchLabels:
namespace: dev
app: allowed-dev-app
Применяем политику:

kubectl apply -f restrict-dev-to-prod.yaml
Теперь только под allowed-dev-app из dev может обращаться к prod-service в prod.

Мониторинг трафика с Hubble​

Hubble — это встроенный инструмент для мониторинга трафика в Cilium. Его установка занимает пару минут:

cilium hubble enable
cilium hubble ui
Открываем веб-интерфейс Hubble и наблюдаем за всем, что происходит в сети кластера. Можно будет увидеть:

  • Какие поды взаимодействуют друг с другом.
  • Какие запросы блокируются политиками.
  • Статистику по каждому сервису.

Кастомные eBPF-программы​

Если очень хочется пойти дальше, Cilium позволяет загружать свои eBPF-программы для реализации специфичных задач. Например, можно написать фильтр, который будет логировать только трафик, идущий через определенный порт.

Простой пример фильтра на eBPF, который логирует HTTP-трафик:

#include
#include
#include

int log_http(struct __sk_buff *skb) {
char msg[] = "HTTP request detected\n";
bpf_trace_printk(msg, sizeof(msg));
return 0;
}
Компилируем и загружаем:

ebpf-loader -o http_filter.o -s log_http.c
Загружаем программу через Cilium:

cilium bpf install http_filter.o
Теперь каждый HTTP-запрос будет логироваться на уровне ядра.

Фильтрация по IP​

Добавим фильтр, который блокирует трафик с определённого IP-адреса:

#include
#include
#include

int block_ip(struct __sk_buff *skb) {
struct iphdr *ip = bpf_hdr_pointer(skb);
if (ip->saddr == htonl(0xC0A80001)) { // 192.168.0.1
return TC_ACT_SHOT; // Drop packet
}
return TC_ACT_OK;
}
Загружаем этот фильтр аналогично:

ebpf-loader -o block_ip.o -s block_ip.c
cilium bpf install block_ip.o
Теперь пакеты с заданного IP-адреса будут блокироваться.

 
Сверху