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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: balance
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

(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:

  1. podSelector: definieert de pods die door dit beleid worden beïnvloed (doelen) - vereist;
  2. 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;
  3. ingress: definieert toegestaan inkomend verkeer naar doelpods - optioneel;
  4. 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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:    # <<<
    matchLabels:
      app: 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

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals
Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: my-namespace  # <<<
spec:
...

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres  # <<<
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

Etiketten

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:

namespaceSelector:
  matchLabels:
    project: myproject

Eén waarschuwing: bij gebruik namespaceSelector zorg 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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default   # <<<
spec:
...

Bron en bestemming

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: 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

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals
Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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.

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  policyTypes:
  - Egress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

U kunt dit probleem oplossen door toegang tot de DNS-service te openen:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:               # <<<
    ports:            # <<<
    - protocol: UDP   # <<<
      port: 53        # <<<
  policyTypes:
  - Egress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:
    - namespaceSelector: {} # <<<
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres
  - to:
    - namespaceSelector:         # <<<
        matchLabels:             # <<<
          namespace: kube-system # <<<
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.dns
  namespace: default
spec:
  podSelector: {} # <<<
  egress:
  - to:
    - namespaceSelector: {}
    ports:
    - protocol: UDP
      port: 53
  policyTypes:
  - Egress

Leeg podSelector selecteert alle pods in de naamruimte.

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

Dit beleid selecteert alle peulen in de naamruimte en laat de toegang ongedefinieerd, waardoor al het binnenkomende verkeer wordt geweigerd.

Op een vergelijkbare manier kunt u al het uitgaande verkeer vanuit een naamruimte beperken:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
  namespace: default
spec:
  podSelector: {}
  ingress: # <<<
  - {}     # <<<
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-to-balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  ingress: 
  - {}
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

Het volgende beleid staat al het inkomende en uitgaande verkeer toe, inclusief toegang tot elk IP-adres buiten het cluster:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
spec:
  podSelector: {}
  ingress:
  - {}
  egress:
  - {}
  policyTypes:
  - Ingress
  - Egress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals
Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

Meerdere beleidsmaatregelen combineren

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.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    - podSelector:
        matchLabels:
          app: admin
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
  - from:
    - podSelector:
        matchLabels:
          app: admin
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

3. Verschillende beleidsmaatregelen worden ook gecombineerd met logische OR

Maar als je ze combineert, is er één beperking gewezen Chris 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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector: # <<<
        matchLabels:
          namespace: default
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          namespace: default
      podSelector: # <<<
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database.postgres
  namespace: database
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
  - from:
    - namespaceSelector: {}
      podSelector:
        matchLabels:
          app: admin
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

Meerdere labels werken samen met I

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:

| Source | Destination | Service | Action |
| ----------------------------------------|
| Host_1 | Subnet_A    | HTTPS   | Allow  |
| 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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-dns
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 8.8.8.8/32
    ports:
    - protocol: UDP
      port: 53

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-any
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: egress-any
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 0.0.0.0/0
        except:
        - 10.16.0.0/14

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

Poorten en protocollen

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    - podSelector:
        matchLabels:
          app: admin
    ports:             # <<<
      - port: 443      # <<<
        protocol: TCP  # <<<
      - port: 80       # <<<
        protocol: TCP  # <<<
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

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:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default.postgres
  namespace: default
spec:
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: indexer
    ports:             # <<<
     - port: 443       # <<<
       protocol: TCP   # <<<
  - from:
    - podSelector:
        matchLabels:
          app: admin
    ports:             # <<<
     - port: 80        # <<<
       protocol: TCP   # <<<
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
  - Ingress

Een inleiding tot Kubernetes-netwerkbeleid voor beveiligingsprofessionals

Standaard poortwerking:

  • 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:

  1. Het architectuurpatroon van Service Mesh maakt gebruik van zijspancontainers om gedetailleerde telemetrie en verkeerscontrole op serviceniveau te bieden. Als voorbeeld kunnen we nemen Istio.
  2. Sommige CNI-leveranciers hebben hun tools uitgebreid om verder te gaan dan het Kubernetes-netwerkbeleid.
  3. 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).

aanvullende informatie

Conclusie

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.

PS van vertaler

Lees ook op onze blog:

Bron: www.habr.com

Voeg een reactie