ProHoster > blog > administratie > Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals
Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals
Opmerking. vert.: De auteur van het artikel, Reuven Harrison, heeft meer dan 20 jaar ervaring in softwareontwikkeling en is tegenwoordig de CTO en medeoprichter van Tufin, een bedrijf dat oplossingen voor het beheer van beveiligingsbeleid creëert. Hoewel hij het Kubernetes-netwerkbeleid beschouwt als een redelijk krachtig hulpmiddel voor netwerksegmentatie in een cluster, is hij ook van mening dat dit in de praktijk niet zo eenvoudig te implementeren is. Dit materiaal (behoorlijk omvangrijk) is bedoeld om het bewustzijn van specialisten over dit probleem te vergroten en hen te helpen de noodzakelijke configuraties te creëren.
Tegenwoordig kiezen veel bedrijven steeds vaker voor Kubernetes om hun applicaties uit te voeren. De belangstelling voor deze software is zo groot dat sommigen Kubernetes ‘het nieuwe besturingssysteem voor het datacenter’ noemen. Geleidelijk aan begint Kubernetes (of k8s) gezien te worden als een cruciaal onderdeel van het bedrijf, wat de organisatie van volwassen bedrijfsprocessen vereist, inclusief netwerkbeveiliging.
Voor beveiligingsprofessionals die verbaasd zijn over het werken met Kubernetes, kan de echte openbaring het standaardbeleid van het platform zijn: alles toestaan.
Deze gids zal u helpen de interne structuur van netwerkbeleid te begrijpen; begrijp hoe ze verschillen van de regels voor reguliere firewalls. Het behandelt ook enkele valkuilen en geeft aanbevelingen om applicaties op Kubernetes te helpen beveiligen.
Kubernetes-netwerkbeleid
Met het Kubernetes-netwerkbeleidsmechanisme kunt u de interactie beheren van applicaties die op het platform zijn geïmplementeerd op de netwerklaag (de derde in het OSI-model). Netwerkbeleid mist enkele van de geavanceerde functies van moderne firewalls, zoals OSI Layer 7-handhaving en detectie van bedreigingen, maar biedt een basisniveau van netwerkbeveiliging dat een goed startpunt is.
Netwerkbeleid regelt de communicatie tussen pods
Werklasten in Kubernetes worden verdeeld over pods, die bestaan uit een of meer containers die samen worden ingezet. Kubernetes wijst aan elke pod een IP-adres toe dat toegankelijk is vanuit andere pods. Het Kubernetes-netwerkbeleid stelt toegangsrechten voor groepen pods in op dezelfde manier waarop beveiligingsgroepen in de cloud worden gebruikt om de toegang tot instanties van virtuele machines te controleren.
Netwerkbeleid definiëren
Net als andere Kubernetes-bronnen wordt netwerkbeleid gespecificeerd in YAML. In het onderstaande voorbeeld is de applicatie balance toegang tot postgres:
(Opmerking. vert.: deze schermafbeelding is, net als alle daaropvolgende soortgelijke, niet gemaakt met behulp van native Kubernetes-tools, maar met behulp van de Tufin Orca-tool, die is ontwikkeld door het bedrijf van de auteur van het originele artikel en die aan het einde van het materiaal wordt vermeld.)
Om uw eigen netwerkbeleid te definiëren, heeft u basiskennis van YAML nodig. Deze taal is gebaseerd op inspringen (gespecificeerd door spaties in plaats van door tabs). Een ingesprongen element behoort tot het dichtstbijzijnde ingesprongen element erboven. Een nieuw lijstelement begint met een koppelteken, alle andere elementen hebben de vorm sleutel waarde.
Nadat u het beleid in YAML hebt beschreven, gebruikt u kubectlom het in het cluster te maken:
kubectl create -f policy.yaml
Specificatie netwerkbeleid
De Kubernetes-netwerkbeleidsspecificatie omvat vier elementen:
podSelector: definieert de pods die door dit beleid worden beïnvloed (doelen) - vereist;
policyTypes: geeft aan welke soorten beleid hierin zijn opgenomen: ingress en/of egress - optioneel, maar ik raad aan dit in alle gevallen expliciet te specificeren;
ingress: definieert toegestaan inkomend verkeer naar doelpods - optioneel;
egress: definieert toegestaan uitgaand verkeer van doelpods is optioneel.
Voorbeeld overgenomen van de Kubernetes-website (ik heb vervangen role op app), laat zien hoe alle vier de elementen worden gebruikt:
Houd er rekening mee dat niet alle vier de elementen hoeven te worden opgenomen. Het is alleen verplicht podSelector, kunnen naar wens andere parameters worden gebruikt.
Als je het nalaat policyTypes, zal het beleid als volgt worden geïnterpreteerd:
Standaard wordt aangenomen dat dit de ingangszijde definieert. Als het beleid dit niet expliciet vermeldt, gaat het systeem ervan uit dat al het verkeer verboden is.
Het gedrag aan de uitgangszijde wordt bepaald door de aanwezigheid of afwezigheid van de overeenkomstige uitgangsparameter.
Om fouten te voorkomen raad ik aan maak het altijd expliciet policyTypes.
Volgens de bovenstaande logica, als de parameters ingress en / of egress weggelaten, zal het beleid al het verkeer weigeren (zie "Regel voor strippen" hieronder).
Het standaardbeleid is Toestaan
Als er geen beleid is gedefinieerd, staat Kubernetes standaard al het verkeer toe. Alle pods kunnen onderling vrijelijk informatie uitwisselen. Dit lijkt misschien contra-intuïtief vanuit een beveiligingsperspectief, maar onthoud dat Kubernetes oorspronkelijk door ontwikkelaars is ontworpen om interoperabiliteit van applicaties mogelijk te maken. Netwerkbeleid is later toegevoegd.
Naamruimten
Naamruimten zijn het Kubernetes-samenwerkingsmechanisme. Ze zijn ontworpen om logische omgevingen van elkaar te isoleren, terwijl communicatie tussen ruimtes standaard is toegestaan.
Net als de meeste Kubernetes-componenten leeft netwerkbeleid in een specifieke naamruimte. In het blok metadata u kunt opgeven tot welke ruimte het beleid behoort:
Als de naamruimte niet expliciet is opgegeven in de metagegevens, gebruikt het systeem de naamruimte die is opgegeven in kubectl (standaard namespace=default):
kubectl apply -n my-namespace -f namespace.yaml
Ik raad aan specificeer de naamruimte expliciet, tenzij u een beleid schrijft dat meerdere naamruimten tegelijk target.
Primair element podSelector in het beleid worden pods geselecteerd uit de naamruimte waartoe het beleid behoort (toegang tot pods uit een andere naamruimte wordt geweigerd).
Op dezelfde manier, podSelectors in in- en uitgangsblokken kan alleen pods uit hun eigen naamruimte selecteren, tenzij je ze natuurlijk combineert met namespaceSelector (dit wordt besproken in de sectie “Filteren op naamruimten en pods”).
Beleidsnaamgevingsregels
Beleidsnamen zijn uniek binnen dezelfde naamruimte. Er kunnen geen twee beleidsregels met dezelfde naam in dezelfde ruimte aanwezig zijn, maar er kunnen wel beleidsregels met dezelfde naam in verschillende ruimtes aanwezig zijn. Dit is handig als u hetzelfde beleid opnieuw wilt toepassen op meerdere ruimtes.
Ik vind vooral een van de naamgevingsmethoden leuk. Het bestaat uit het combineren van de naamruimtenaam met de doelpods. Bijvoorbeeld:
U kunt aangepaste labels koppelen aan Kubernetes-objecten, zoals pods en naamruimten. Etiketten (labels - tags) zijn het equivalent van tags in de cloud. Kubernetes-netwerkbeleid gebruikt labels om te selecteren peulenwaarop ze van toepassing zijn:
podSelector:
matchLabels:
role: db
… Of naamruimtenwaarop ze van toepassing zijn. In dit voorbeeld worden alle pods in naamruimten met de bijbehorende labels geselecteerd:
Eén waarschuwing: bij gebruik namespaceSelectorzorg ervoor dat de naamruimten die u selecteert het juiste label bevatten. Houd er rekening mee dat ingebouwde naamruimten zoals default и kube-system, bevatten standaard geen labels.
U kunt als volgt een label aan een ruimte toevoegen:
kubectl label namespace default namespace=default
Tegelijkertijd naamruimte in de sectie metadata moet verwijzen naar de daadwerkelijke naam van de ruimte, niet naar het label:
Firewallbeleid bestaat uit regels met bronnen en bestemmingen. Kubernetes-netwerkbeleid wordt gedefinieerd voor een doel (een set peulen waarop ze van toepassing zijn) en stelt vervolgens regels in voor inkomend en/of uitgaand verkeer. In ons voorbeeld zijn alle pods in de naamruimte het doel van het beleid default met label met sleutel app en betekenis db:
Onderafdeling ingress opent in dit beleid binnenkomend verkeer naar de doelpods. Met andere woorden: inkomend verkeer is de bron en doel is de overeenkomstige bestemming. Op dezelfde manier is uitgaand verkeer de bestemming en het doel de bron.
Dit komt overeen met twee firewallregels: Ingress → Doel; Doel → Uitgang.
Egress en DNS (belangrijk!)
Door uitgaand verkeer te beperken, besteed speciale aandacht aan DNS - Kubernetes gebruikt deze service om services aan IP-adressen toe te wijzen. Het volgende beleid werkt bijvoorbeeld niet omdat u de toepassing niet heeft toegestaan balance toegang tot DNS:
Laatste element to is leeg en selecteert daarom indirect alle pods in alle naamruimten, toestaan balance stuur DNS-query's naar de juiste Kubernetes-service (meestal uitgevoerd in de space kube-system).
Deze aanpak werkt, hoe dan ook overdreven toegeeflijk en onzeker, omdat DNS-query's hierdoor buiten het cluster kunnen worden geleid.
Je kunt het in drie opeenvolgende stappen verbeteren.
1. Sta alleen DNS-query's toe внутри clusteren door toe te voegen namespaceSelector:
2. Sta DNS-query's alleen binnen de naamruimte toe kube-system.
Om dit te doen, moet u een label aan de naamruimte toevoegen kube-system: kubectl label namespace kube-system namespace=kube-system - en schrijf het op in het beleid met behulp van namespaceSelector:
3. Paranoïde mensen kunnen nog verder gaan en DNS-query’s beperken tot een specifieke DNS-service kube-system. In de sectie “Filteren op naamruimten EN pods” wordt uitgelegd hoe u dit kunt bereiken.
Een andere optie is om DNS op naamruimteniveau om te zetten. In dit geval hoeft het niet voor elke service te worden geopend:
Leeg podSelector selecteert alle pods in de naamruimte.
Eerste wedstrijd en regelvolgorde
In conventionele firewalls wordt de actie (Toestaan of Weigeren) op een pakket bepaald door de eerste regel waaraan het voldoet. In Kubernetes doet de volgorde van het beleid er niet toe.
Als er geen beleid is ingesteld, is communicatie tussen pods standaard toegestaan en kunnen ze vrijelijk informatie uitwisselen. Zodra u begint met het formuleren van beleid, wordt elke pod die door ten minste één ervan wordt beïnvloed, geïsoleerd volgens de disjunctie (logische OR) van al het beleid dat ervoor heeft geselecteerd. Pods waarop geen enkel beleid van toepassing is, blijven open.
U kunt dit gedrag wijzigen met behulp van een stripregel.
Strippingregel (“Weigeren”)
Firewallbeleid weigert doorgaans al het verkeer dat niet expliciet is toegestaan.
Er is geen ontkenningsactie in KubernetesEen soortgelijk effect kan echter worden bereikt met een regulier (tolerant) beleid door een lege groep bronpods te selecteren (ingress):
Houd er rekening mee dat eventueel aanvullend beleid dat verkeer naar pods in de naamruimte toestaat, heeft voorrang op deze regel (vergelijkbaar met het toevoegen van een regel voor toestaan vóór een regel voor weigeren in een firewallconfiguratie).
Alles toestaan (Any-Any-Any-Allow)
Om een beleid Alles toestaan te maken, moet u het bovenstaande beleid Weigeren aanvullen met een leeg element ingress:
Het biedt toegang vanaf alle peulen in alle naamruimten (en alle IP-adressen) naar elke pod in de naamruimte default. Dit gedrag is standaard ingeschakeld en hoeft dus meestal niet verder te worden gedefinieerd. Soms moet u echter bepaalde specifieke machtigingen tijdelijk uitschakelen om een diagnose van het probleem te kunnen stellen.
De regel kan worden beperkt tot alleen toegang tot een specifieke set peulen (app:balance) in de naamruimte default:
Beleid wordt gecombineerd met behulp van logische OR op drie niveaus; De machtigingen van elke pod worden ingesteld in overeenstemming met de scheiding van al het beleid dat daarop van invloed is:
1. In de velden from и to Er kunnen drie soorten elementen worden gedefinieerd (die allemaal worden gecombineerd met behulp van OR):
namespaceSelector — selecteert de volledige naamruimte;
podSelector — selecteert peulen;
ipBlock — selecteert een subnet.
Bovendien is het aantal elementen (zelfs identieke) in subsecties from/to niet gelimiteerd. Ze worden allemaal gecombineerd door logische OR.
2. Binnen het beleidsgedeelte ingress kan veel elementen bevatten from (gecombineerd door logische OR). Zo ook sectie egress kan veel elementen bevatten to (ook gecombineerd door disjunctie):
3. Verschillende beleidsmaatregelen worden ook gecombineerd met logische OR
Maar als je ze combineert, is er één beperking gewezenChris Cooney: Kubernetes kan alleen beleid combineren met verschillende policyTypes (Ingress of Egress). Beleid dat inkomend (of uitgaand) definieert, zal elkaar overschrijven.
Relatie tussen naamruimten
Standaard is het delen van informatie tussen naamruimten toegestaan. Dit kan worden gewijzigd door een deny-beleid te gebruiken dat het uitgaande en/of binnenkomende verkeer in de naamruimte beperkt (zie "Regel voor strippen" hierboven).
Zodra u de toegang tot een naamruimte heeft geblokkeerd (zie de "Strippingregel" hierboven), kunt u uitzonderingen maken op het weigeringsbeleid door verbindingen vanaf een specifieke naamruimte toe te staan met behulp van namespaceSelector:
Als gevolg hiervan worden alle peulen in de naamruimte default toegang zal hebben tot pods postgres in naamruimte database. Maar wat als u de toegang wilt openen? postgres alleen specifieke peulen in de naamruimte default?
Filter op naamruimten en peulen
Met Kubernetes versie 1.11 en hoger kunt u operators combineren namespaceSelector и podSelector met behulp van logische AND. Het ziet er als volgt uit:
Waarom wordt dit geïnterpreteerd als AND in plaats van de gebruikelijke OR?
Houd er rekening mee dat podSelector begint niet met een koppelteken. In YAML betekent dit dat podSelector en voor hem gaan staan namespaceSelector verwijzen naar hetzelfde lijstelement. Daarom worden ze gecombineerd met logische AND.
Ervoor wordt een koppelteken toegevoegd podSelector zal resulteren in het ontstaan van een nieuw lijstelement, dat zal worden gecombineerd met het vorige namespaceSelector met behulp van logische OR.
Om peulen met een specifiek label te selecteren in alle naamruimten, blanco invullen namespaceSelector:
Regels voor een firewall met meerdere objecten (hosts, netwerken, groepen) worden gecombineerd met behulp van logische OR. De volgende regel werkt als de pakketbron overeenkomt Host_1 ИЛИ Host_2:
Integendeel, in Kubernetes zijn de verschillende labels in podSelector of namespaceSelector worden gecombineerd met logische AND. De volgende regel selecteert bijvoorbeeld pods die beide labels hebben, role=db И version=v2:
podSelector:
matchLabels:
role: db
version: v2
Dezelfde logica is van toepassing op alle typen operators: beleidsdoelselectors, pod-selectors en naamruimteselectors.
Subnetten en IP-adressen (IPBlocks)
Firewalls gebruiken VLAN's, IP-adressen en subnetten om een netwerk te segmenteren.
In Kubernetes worden IP-adressen automatisch aan pods toegewezen en kunnen deze regelmatig veranderen. Daarom worden labels gebruikt om pods en naamruimten in netwerkbeleid te selecteren.
Subnetten (ipBlocks) worden gebruikt bij het beheren van inkomende (inkomende) of uitgaande (uitgaande) externe (Noord-Zuid) verbindingen. Dit beleid is bijvoorbeeld geopend voor alle peulen uit de naamruimte default toegang tot de Google DNS-service:
De lege pod-selector betekent in dit voorbeeld “selecteer alle pods in de naamruimte.”
Dit beleid staat alleen toegang toe tot 8.8.8.8; toegang tot een ander IP-adres is verboden. U hebt dus in wezen de toegang tot de interne Kubernetes DNS-service geblokkeerd. Wilt u deze toch openen, geef dit dan expliciet aan.
Doorgaans ipBlocks и podSelectors sluiten elkaar wederzijds uit, omdat de interne IP-adressen van pods niet worden gebruikt ipBlocks. Door aan te geven interne IP-pods, staat u feitelijk verbindingen toe van/naar pods met deze adressen. In de praktijk weet u niet welk IP-adres u moet gebruiken en daarom mogen deze niet worden gebruikt om pods te selecteren.
Als tegenvoorbeeld omvat het volgende beleid alle IP's en staat daarom toegang tot alle andere pods toe:
U kunt alleen toegang openen voor externe IP-adressen, met uitzondering van de interne IP-adressen van pods. Als het subnet van uw pod bijvoorbeeld 10.16.0.0/14 is:
Normaal gesproken luisteren pods naar één poort. Dit betekent dat u eenvoudigweg geen poortnummers in beleid kunt specificeren en alles op de standaard kunt laten staan. Het wordt echter aanbevolen om het beleid zo beperkend mogelijk te maken, zodat u in sommige gevallen nog steeds poorten kunt opgeven:
Merk op dat de selector ports geldt voor alle elementen in het blok to of from, die bevat. Om verschillende poorten voor verschillende sets elementen op te geven, splitst u ingress of egress in verschillende subsecties met to of from en in elk register uw poorten:
Als u de poortdefinitie volledig weglaat (ports), dit betekent alle protocollen en alle poorten;
Als u de protocoldefinitie (protocol), dit betekent TCP;
Als u de poortdefinitie (port), dit betekent alle poorten.
Best practice: Vertrouw niet op standaardwaarden, maar specificeer expliciet wat u nodig heeft.
Houd er rekening mee dat u podpoorten moet gebruiken en geen servicepoorten (meer hierover in de volgende paragraaf).
Is er beleid gedefinieerd voor pods of services?
Normaal gesproken hebben peulen in Kubernetes toegang tot elkaar via een service: een virtuele load balancer die verkeer omleidt naar de peulen die de service implementeren. Je zou kunnen denken dat netwerkbeleid de toegang tot services controleert, maar dit is niet het geval. Kubernetes-netwerkbeleid werkt op pod-poorten, niet op servicepoorten.
Als een service bijvoorbeeld naar poort 80 luistert, maar verkeer omleidt naar poort 8080 van zijn pods, moet u exact 8080 opgeven in het netwerkbeleid.
Een dergelijk mechanisme moet als suboptimaal worden beschouwd: als de interne structuur van de dienst (de poorten waarvan de pods luisteren) verandert, zal het netwerkbeleid moeten worden bijgewerkt.
Nieuwe architecturale aanpak met behulp van Service Mesh (zie bijvoorbeeld over Istio hieronder - ca. vert.) stelt u in staat dit probleem aan te pakken.
Is het nodig om zowel Ingress als Egress te registreren?
Het korte antwoord is ja. Om pod A te laten communiceren met pod B, moet het toegestaan zijn om een uitgaande verbinding te maken (hiervoor moet u een uitgaand beleid configureren), en moet pod B een inkomende verbinding kunnen accepteren ( hiervoor heeft u daarom een ingress-beleid (beleid).
In de praktijk kunt u er echter op vertrouwen dat het standaardbeleid verbindingen in één of beide richtingen toestaat.
Als er wat pod-bron wordt door één of meerdere geselecteerd uitgang-politici, de beperkingen die daaraan worden opgelegd zullen worden bepaald door hun disjunctie. In dit geval moet u de verbinding met de pod expliciet toestaan -aan de geadresseerde. Als een pod door geen enkel beleid wordt geselecteerd, wordt het uitgaande (uitgaande) verkeer standaard toegestaan.
Op dezelfde manier is het lot van de podgeadresseerde, geselecteerd door een of meer toegang-politici, zullen worden bepaald door hun verdeeldheid. In dit geval moet u expliciet toestaan dat deze verkeer ontvangt van de bronpod. Als een pod door geen enkel beleid wordt geselecteerd, wordt al het binnenkomende verkeer standaard toegestaan.
Zie Stateful of Stateless hieronder.
Logboeken
Het Kubernetes-netwerkbeleid kan geen verkeer registreren. Dit maakt het moeilijk om te bepalen of een beleid werkt zoals bedoeld en bemoeilijkt de beveiligingsanalyse aanzienlijk.
Controle van verkeer naar externe diensten
Het Kubernetes-netwerkbeleid staat niet toe dat u een volledig gekwalificeerde domeinnaam (DNS) opgeeft in uitgaande secties. Dit feit leidt tot aanzienlijk ongemak bij het beperken van verkeer naar externe bestemmingen die geen vast IP-adres hebben (zoals aws.com).
Beleidscontrole
Firewalls zullen u waarschuwen of zelfs weigeren het verkeerde beleid te accepteren. Kubernetes doet ook enige verificatie. Bij het instellen van een netwerkbeleid via kubectl kan Kubernetes verklaren dat dit onjuist is en weigeren dit te accepteren. In andere gevallen neemt Kubernetes het beleid en vult het in met de ontbrekende gegevens. Ze kunnen worden bekeken met behulp van het commando:
kubernetes get networkpolicy <policy-name> -o yaml
Houd er rekening mee dat het Kubernetes-validatiesysteem niet onfeilbaar is en bepaalde soorten fouten kan missen.
Uitvoering
Kubernetes implementeert zelf geen netwerkbeleid, maar is slechts een API-gateway die de controlelast delegeert aan een onderliggend systeem dat de Container Networking Interface (CNI) wordt genoemd. Beleid instellen op een Kubernetes-cluster zonder de juiste CNI toe te wijzen, is hetzelfde als het maken van beleid op een firewallbeheerserver zonder dit vervolgens op firewalls te installeren. Het is aan jou om ervoor te zorgen dat je een fatsoenlijke CNI hebt of, in het geval van Kubernetes-platforms, gehost wordt in de cloud (u kunt de lijst met providers bekijken hier — ca. trans.), schakel netwerkbeleid in dat CNI voor u instelt.
Houd er rekening mee dat Kubernetes u niet zal waarschuwen als u een netwerkbeleid instelt zonder de juiste helper-CNI.
Statelijk of staatloos?
Alle Kubernetes CNI's die ik ben tegengekomen zijn stateful (Calico gebruikt bijvoorbeeld Linux conntrack). Hierdoor kan de pod reacties ontvangen op de TCP-verbinding die deze heeft geïnitieerd, zonder dat deze opnieuw tot stand hoeft te worden gebracht. Ik ben echter niet op de hoogte van een Kubernetes-standaard die statefulness zou garanderen.
Geavanceerd beveiligingsbeleidbeheer
Hier volgen enkele manieren om de handhaving van het beveiligingsbeleid in Kubernetes te verbeteren:
Het architectuurpatroon van Service Mesh maakt gebruik van zijspancontainers om gedetailleerde telemetrie en verkeerscontrole op serviceniveau te bieden. Als voorbeeld kunnen we nemen Istio.
Sommige CNI-leveranciers hebben hun tools uitgebreid om verder te gaan dan het Kubernetes-netwerkbeleid.
Tufin-orka Biedt zichtbaarheid en automatisering van Kubernetes-netwerkbeleid.
Het Tufin Orca-pakket beheert het Kubernetes-netwerkbeleid (en is de bron van de bovenstaande schermafbeeldingen).
Kubernetes-netwerkbeleid biedt een goede set tools voor het segmenteren van clusters, maar is niet intuïtief en kent veel subtiliteiten. Vanwege deze complexiteit ben ik van mening dat veel bestaande clusterbeleidsregels fouten bevatten. Mogelijke oplossingen voor dit probleem zijn onder meer het automatiseren van beleidsdefinities of het gebruik van andere segmentatietools.
Ik hoop dat deze gids een aantal vragen helpt ophelderen en problemen oplost die u mogelijk tegenkomt.