Calico pro networking v Kubernetes: úvod a malá zkušenost

Calico pro networking v Kubernetes: úvod a malá zkušenost

Účelem článku je seznámit čtenáře se základy síťování a správy síťových zásad v Kubernetes a také s pluginem Calico třetí strany, který rozšiřuje standardní možnosti. Snadná konfigurace a některé funkce budou předvedeny na skutečných příkladech z našich provozních zkušeností.

Rychlý úvod do síťového zařízení Kubernetes

Cluster Kubernetes si nelze představit bez sítě. O jejich základech jsme již publikovali materiály: “Ilustrovaný průvodce vytvářením sítí v Kubernetes"A"Úvod do síťových zásad Kubernetes pro profesionály v oblasti zabezpečení".

V kontextu tohoto článku je důležité poznamenat, že samotný K8 není zodpovědný za síťové připojení mezi kontejnery a uzly: CNI pluginy (Container Networking Interface). Více o tomto konceptu my také mi řekli.

Například nejběžnější z těchto pluginů je Flanel — poskytuje plnou síťovou konektivitu mezi všemi uzly clusteru zvednutím mostů na každém uzlu a přiřazením podsítě. Úplná a neregulovaná dostupnost však není vždy prospěšná. Pro zajištění určité minimální izolace v clusteru je nutné zasáhnout do konfigurace firewallu. V obecném případě je umístěn pod kontrolu stejného CNI, a proto mohou být jakékoli zásahy třetích stran do iptables interpretovány nesprávně nebo mohou být zcela ignorovány.

A je k dispozici „out of the box“ pro organizaci správy síťových zásad v clusteru Kubernetes NetworkPolicy API. Tento zdroj, distribuovaný ve vybraných jmenných prostorech, může obsahovat pravidla pro rozlišení přístupu z jedné aplikace do druhé. Umožňuje také konfigurovat dostupnost mezi konkrétními moduly, prostředími (jmennými prostory) nebo bloky IP adres:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - ipBlock:
        cidr: 172.17.0.0/16
        except:
        - 172.17.1.0/24
    - namespaceSelector:
        matchLabels:
          project: myproject
    - podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 6379
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978

Toto není nejprimitivnější příklad oficiální dokumentace může jednou provždy odradit od touhy porozumět logice fungování síťových politik. Přesto se pokusíme pochopit základní principy a metody zpracování dopravních toků pomocí síťových politik...

Je logické, že existují 2 typy provozu: vstup do pod (Ingress) a výstup z něj (Egress).

Calico pro networking v Kubernetes: úvod a malá zkušenost

Ve skutečnosti je politika rozdělena do těchto 2 kategorií podle směru pohybu.

Dalším povinným atributem je selektor; ten, na koho se pravidlo vztahuje. Může to být pod (nebo skupina podů) nebo prostředí (tj. jmenný prostor). Důležitý detail: oba typy těchto objektů musí obsahovat štítek (štítek v terminologii Kubernetes) – to jsou ty, se kterými politici operují.

Kromě konečného počtu selektorů sjednocených nějakým štítkem je možné psát pravidla jako „Povolit/zakázat vše/všem“ v různých variantách. K tomuto účelu se používají konstrukce formuláře:

  podSelector: {}
  ingress: []
  policyTypes:
  - Ingress

— v tomto příkladu jsou všechny moduly v prostředí blokovány pro příchozí provoz. Opačného chování lze dosáhnout pomocí následující konstrukce:

  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress

Podobně pro odchozí:

  podSelector: {}
  policyTypes:
  - Egress

- vypnout. A zde je to, co zahrnout:

  podSelector: {}
  egress:
  - {}
  policyTypes:
  - Egress

Pokud se vrátíme k volbě CNI pluginu pro cluster, stojí za zmínku ne každý síťový plugin podporuje NetworkPolicy. Například již zmíněný Flannel neumí konfigurovat síťové zásady, což je to řečeno přímo v oficiálním úložišti. Je tam zmíněna i alternativa - Open Source projekt Kaliko, který výrazně rozšiřuje standardní sadu Kubernetes API z hlediska síťových zásad.

Calico pro networking v Kubernetes: úvod a malá zkušenost

Poznávání Calico: teorie

Zásuvný modul Calico lze použít v integraci s Flannel (podprojekt Canal) nebo nezávisle, pokrývající jak možnosti síťové konektivity, tak možnosti správy dostupnosti.

Jaké příležitosti poskytuje použití „krabicového“ řešení K8s a sady API od Calico?

Zde je to, co je zabudováno do NetworkPolicy:

  • politici jsou omezeni prostředím;
  • zásady jsou aplikovány na pody označené štítky;
  • pravidla lze aplikovat na moduly, prostředí nebo podsítě;
  • pravidla mohou obsahovat protokoly, pojmenované nebo symbolické specifikace portů.

Zde je návod, jak Calico rozšiřuje tyto funkce:

  • zásady lze aplikovat na jakýkoli objekt: pod, kontejner, virtuální stroj nebo rozhraní;
  • pravidla mohou obsahovat konkrétní akci (zákaz, povolení, protokolování);
  • cílem nebo zdrojem pravidel může být port, řada portů, protokoly, atributy HTTP nebo ICMP, IP nebo podsíť (4. nebo 6. generace), libovolné selektory (uzly, hostitelé, prostředí);
  • Navíc můžete regulovat průchod provozu pomocí nastavení DNAT a zásad přesměrování provozu.

První commity na GitHubu v úložišti Calico se datují do července 2016 a o rok později projekt zaujal přední místo v organizaci síťové konektivity Kubernetes – dokládají to například výsledky průzkumu, dirigoval The New Stack:

Calico pro networking v Kubernetes: úvod a malá zkušenost

Mnoho velkých řízených řešení s K8, jako např Amazon EX, Azure AKS, Google GKE a jiní jej začali doporučovat k použití.

Co se týče výkonu, vše je zde skvělé. Při testování svého produktu prokázal vývojový tým Calico astronomický výkon, provozoval více než 50000 500 kontejnerů na 20 fyzických uzlech s rychlostí vytváření XNUMX kontejnerů za sekundu. Nebyly zjištěny žádné problémy s škálováním. Takové výsledky byly oznámeny již při oznámení první verze. Nezávislé studie zaměřené na propustnost a spotřebu zdrojů také potvrzují, že výkon Calico je téměř stejně dobrý jako výkon Flannel. Například:

Calico pro networking v Kubernetes: úvod a malá zkušenost

Projekt se vyvíjí velmi rychle, podporuje práci v populárních řešeních řízených K8s, OpenShift, OpenStack, je možné použít Calico při nasazení clusteru pomocí kop, jsou zde odkazy na výstavbu sítí Service Mesh (Zde je příklad používá se ve spojení s Istio).

Cvičte s Calico

V obecném případě použití vanilla Kubernetes spočívá instalace CNI na použití souboru calico.yaml, staženo z oficiálních stránek, s помощью kubectl apply -f.

Aktuální verze pluginu je zpravidla kompatibilní s nejnovějšími 2-3 verzemi Kubernetes: provoz ve starších verzích není testován a není zaručen. Podle vývojářů běží Calico na linuxových jádrech nad 3.10 s CentOS 7, Ubuntu 16 nebo Debian 8, nad iptables nebo IPVS.

Izolace v prostředí

Pro obecné pochopení se podívejme na jednoduchý případ, abychom pochopili, jak se síťové zásady v notaci Calico liší od standardních a jak přístup k vytváření pravidel zjednodušuje jejich čitelnost a flexibilitu konfigurace:

Calico pro networking v Kubernetes: úvod a malá zkušenost

V clusteru jsou nasazeny 2 webové aplikace: v Node.js a PHP, z nichž jedna používá Redis. Chcete-li zablokovat přístup k Redis z PHP a zároveň zachovat konektivitu s Node.js, stačí použít následující zásady:

kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
  name: allow-redis-nodejs
spec:
  podSelector:
    matchLabels:
      service: redis
  ingress:
  - from:
    - podSelector:
        matchLabels:
          service: nodejs
    ports:
    - protocol: TCP
      port: 6379

V podstatě jsme povolili příchozí provoz na port Redis z Node.js. A nic jiného zjevně nezakázali. Jakmile se zobrazí NetworkPolicy, začnou se izolovat všechny v ní uvedené selektory, pokud není uvedeno jinak. Pravidla izolace se však nevztahují na jiné objekty, na které se selektor nevztahuje.

Příklad používá apiVersion Kubernetes je po vybalení, ale nic vám nebrání v jeho používání zdroj stejného jména z dodávky Calico. Syntaxe je zde podrobnější, takže budete muset pravidlo pro výše uvedený případ přepsat do následujícího tvaru:

apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
  name: allow-redis-nodejs
spec:
  selector: service == 'redis'
  ingress:
  - action: Allow
    protocol: TCP
    source:
      selector: service == 'nodejs'
    destination:
      ports:
      - 6379

Výše uvedené konstrukce pro povolení nebo zakázání veškerého provozu prostřednictvím běžného API NetworkPolicy obsahují konstrukce se závorkami, které jsou obtížně srozumitelné a zapamatovatelné. V případě Calico, chcete-li změnit logiku pravidla brány firewall na opačnou, stačí změnit action: Allow na action: Deny.

Izolace prostředím

Nyní si představte situaci, kdy aplikace generuje obchodní metriky pro sběr v Prometheus a další analýzu pomocí Grafany. Nahrávka může obsahovat citlivá data, která jsou opět ve výchozím nastavení veřejně viditelná. Skryjme tato data před zvědavýma očima:

Calico pro networking v Kubernetes: úvod a malá zkušenost

Prometheus je zpravidla umístěn v samostatném servisním prostředí - v příkladu to bude jmenný prostor, jako je tento:

apiVersion: v1
kind: Namespace
metadata:
  labels:
    module: prometheus
  name: kube-prometheus

Pole metadata.labels ukázalo se, že to nebyla náhoda. Jak je zmíněno výše, namespaceSelector (jakož i podSelector) pracuje se štítky. Proto, aby bylo možné převzít metriky ze všech modulů na konkrétním portu, budete muset přidat nějaký druh štítku (nebo převzít z existujících) a poté použít konfiguraci jako:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-metrics-prom
spec:
  podSelector: {}
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          module: prometheus
    ports:
    - protocol: TCP
      port: 9100

A pokud používáte zásady Calico, syntaxe bude vypadat takto:

apiVersion: crd.projectcalico.org/v1
kind: NetworkPolicy
metadata:
  name: allow-metrics-prom
spec:
  ingress:
  - action: Allow
    protocol: TCP
    source:
      namespaceSelector: module == 'prometheus'
    destination:
      ports:
      - 9100

Obecně platí, že přidáním těchto druhů zásad pro konkrétní potřeby můžete chránit před škodlivým nebo náhodným zásahem do provozu aplikací v clusteru.

Nejlepším postupem je podle tvůrců Calico přístup „Zablokujte vše a výslovně otevřete, co potřebujete“, zdokumentovaný v oficiální dokumentace (ostatní používají podobný přístup - zejména v již zmíněný článek).

Použití dalších objektů Calico

Dovolte mi připomenout, že prostřednictvím rozšířené sady Calico API můžete regulovat dostupnost uzlů, nejen podů. V následujícím příkladu použití GlobalNetworkPolicy možnost předávat požadavky ICMP v clusteru je uzavřena (například ping z podu do uzlu, mezi pody nebo z uzlu do IP podu):

apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
  name: block-icmp
spec:
  order: 200
  selector: all()
  types:
  - Ingress
  - Egress
  ingress:
  - action: Deny
    protocol: ICMP
  egress:
  - action: Deny
    protocol: ICMP

Ve výše uvedeném případě je stále možné, aby se uzly clusteru vzájemně „dosáhly“ prostřednictvím protokolu ICMP. A tento problém se řeší prostředky GlobalNetworkPolicy, aplikovaný na entitu HostEndpoint:

apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
  name: deny-icmp-kube-02
spec:
  selector: "role == 'k8s-node'"
  order: 0
  ingress:
  - action: Allow
    protocol: ICMP
  egress:
  - action: Allow
    protocol: ICMP
---
apiVersion: crd.projectcalico.org/v1
kind: HostEndpoint
metadata:
  name: kube-02-eth0
  labels:
    role: k8s-node
spec:
  interfaceName: eth0
  node: kube-02
  expectedIPs: ["192.168.2.2"]

Případ VPN

Nakonec uvedu velmi reálný příklad použití funkcí Calico pro případ interakce blízké shluku, kdy standardní sada politik nestačí. Pro přístup k webové aplikaci používají klienti tunel VPN a tento přístup je přísně kontrolován a omezen na konkrétní seznam povolených služeb:

Calico pro networking v Kubernetes: úvod a malá zkušenost

Klienti se připojují k VPN přes standardní UDP port 1194 a po připojení přijímají trasy do klastrových podsítí podů a služeb. Celé podsítě jsou posunuty, aby nedošlo ke ztrátě služeb během restartů a změn adres.

Port v konfiguraci je standardní, což ukládá určité nuance procesu konfigurace aplikace a jejího přenosu do clusteru Kubernetes. Například ve stejném AWS se LoadBalancer pro UDP objevil doslova na konci minulého roku v omezeném seznamu regionů a NodePort nelze použít kvůli jeho přesměrování na všechny uzly clusteru a není možné škálovat počet instancí serveru pro pro účely odolnosti proti chybám. Navíc budete muset změnit výchozí rozsah portů...

Na základě hledání možných řešení bylo vybráno následující:

  1. Pody s VPN jsou naplánovány pro každý uzel v hostNetwork, tedy do skutečné IP.
  2. Služba je vyvěšena venku přes ClusterIP. Na uzlu je fyzicky nainstalován port, který je zvenčí přístupný s menšími výhradami (podmíněná přítomnost skutečné IP adresy).
  3. Určení uzlu, na kterém se lusk zvedl, přesahuje rámec našeho příběhu. Řeknu jen, že můžete službu pevně „přibít“ na uzel nebo napsat malou postranní službu, která bude sledovat aktuální IP adresu služby VPN a upravovat DNS záznamy registrované u klientů - kdo má dostatek fantazie.

Z hlediska směrování můžeme klienta VPN jednoznačně identifikovat podle jeho IP adresy vydané serverem VPN. Níže je uveden primitivní příklad omezení přístupu takového klienta ke službám, ilustrovaný na výše uvedeném Redis:

apiVersion: crd.projectcalico.org/v1
kind: HostEndpoint
metadata:
  name: vpnclient-eth0
  labels:
    role: vpnclient
    environment: production
spec:
  interfaceName: "*"
  node: kube-02
  expectedIPs: ["172.176.176.2"]
---
apiVersion: crd.projectcalico.org/v1
kind: GlobalNetworkPolicy
metadata:
  name: vpn-rules
spec:
  selector: "role == 'vpnclient'"
  order: 0
  applyOnForward: true
  preDNAT: true
  ingress:
  - action: Deny
    protocol: TCP
    destination:
      ports: [6379]
  - action: Allow
    protocol: UDP
    destination:
      ports: [53, 67]

Zde je připojení na port 6379 přísně zakázáno, ale zároveň je zachován provoz služby DNS, jejíž fungování při sestavování pravidel poměrně často trpí. Protože, jak již bylo zmíněno, když se objeví selektor, použije se na něj výchozí zásada odmítnutí, pokud není uvedeno jinak.

Výsledky

Pomocí pokročilého API Calico tedy můžete flexibilně konfigurovat a dynamicky měnit směrování v clusteru a kolem něj. Obecně může jeho použití vypadat jako střílení vrabců kanónem a implementace L3 sítě s BGP a IP-IP tunely vypadá v jednoduché instalaci Kubernetes na ploché síti monstrózně... Jinak však nástroj vypadá celkem životaschopně a užitečně .

Izolace clusteru pro splnění bezpečnostních požadavků nemusí být vždy proveditelná a právě zde přichází na pomoc Calico (nebo podobné řešení). Příklady uvedené v tomto článku (s drobnými úpravami) jsou použity v několika instalacích našich klientů v AWS.

PS

Přečtěte si také na našem blogu:

Zdroj: www.habr.com

Přidat komentář