Ha Kubernetes-t uzemeltetek az EU-ban, a NIS2 ram is vonatkozik. Az iranyelvek 2024 oktobere ota hatalyosak, es a tagallamok azota ultetik at a nemzeti jogba. Az elmult honapokban tobb klasztert is atneztem megfeleles szempontbol, es ebbol osszeraktam, mi az, ami tenyleg szamit a gyakorlatban.

Ez nem jogi elemzes. Inkabb az a technikai checklista, amit en is sokkal hamarabb szerettem volna kezbe kapni.

Mit jelent a NIS2 K8s uzemeltetoknek (roviden)

A NIS2 boviti az eredeti NIS iranyelv hatalyat. Ha a ceg, ahol dolgozom, “alapveto” vagy “fontos” szervezetnek minosul (energia, kozlekedes, egeszsegugy, digitalis infrastruktura es meg sok mas), akkor tudnom kell igazolni:

  • Kockazatkezelesi intezkedeseket az IT rendszereidre
  • Incidenseszlelest es jelentest (24 ora korai figyelmeztetesre, 72 ora teljes jelentesre)
  • Ellatasilancbiztonsagot
  • Uzletfolytonossagi tervezest
  • Audit logolast megorzesi idovel

A Kubernetes mindegyiket erinti, ugyhogy vegigmegyek rajtuk egyenkent.

1. Network Policy-k: a lateralis mozgas megallitasa

Alapertelmezetten minden pod beszelhet minden mas poddal egy Kubernetes klaszterben. Ezt en compliance oldalrol konkretan vallalhatatlannak latom. A NIS2 halozati szegmentalast es hozzaferes-vezerlest kovetel meg.

En mindig egy default-deny szaballyal kezdek minden namespace-ben:

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

Utana explicit engedelyezem, aminek tenyleg kommunikalnia kell:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080

Azt is mindig leellenorzom, hogy a szabaly tenyleg ervenyesul:

# Gyors teszt - ennek timeout-olnia kell, ha a deny-all mukodik
kubectl run test-pod --rm -it --image=busybox --restart=Never \
  -n production -- wget -qO- --timeout=3 http://api:8080

Arra kulon figyelek, hogy a CNI tenyleg tamogassa a NetworkPolicy-t. A Flannel nem ervenyesiti, a Calico, Cilium es Weave igen.

2. RBAC audit: ki mit csinalhat

A NIS2 hozzaferes-vezerlest es legkisebb jogosultsag elvet var el. Kubernetesben ez nalam rendszeres RBAC auditot jelent.

Tulterjeszkedett service accountok keresese:

# Cluster-admin jogosultsagu ClusterRoleBinding-ok listazasa
kubectl get clusterrolebindings -o json | \
  jq -r '.items[] | select(.roleRef.name=="cluster-admin") |
  .metadata.name + " -> " + (.subjects[]? | .kind + "/" + .name)'

Kockazatos jogosultsagok keresese:

# Olyan role-ok keresese, amelyek exec-et engednek podokba
kubectl get roles,clusterroles -A -o json | \
  jq -r '.items[] | select(.rules[]? |
  .resources[]? == "pods/exec") | .metadata.name'

Mindig keszitsen egy dedikalt RBAC audit scriptet es havonta futtasd:

#!/bin/bash
echo "=== Cluster Admin Binding-ok ==="
kubectl get clusterrolebindings -o json | \
  jq -r '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name'

echo -e "\n=== Wildcard jogosultsagok ==="
kubectl get clusterroles -o json | \
  jq -r '.items[] | select(.rules[]? |
  (.verbs[]? == "*") or (.resources[]? == "*")) | .metadata.name'

echo -e "\n=== Secret-ekhez fero Service Accountok ==="
kubectl get roles,clusterroles -A -o json | \
  jq -r '.items[] | select(.rules[]? |
  .resources[]? == "secrets") |
  .metadata.namespace + "/" + .metadata.name'

3. Image scanning Trivy-vel

Az ellatasilancbiztonsag a NIS2 egyik fo pillere. Nekem tudnom kell, mi van az image-ekben, es a sebezhetosegeket meg produkcio elott szeretnem megfogni.

Telepitsd a Trivy-t es scanneld az image-eket:

# Egy adott image scannelese
trivy image --severity HIGH,CRITICAL your-registry.io/app:latest

# Minden jelenleg futo image scannelese a klaszterben
kubectl get pods -A -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.image}{"\n"}{end}{end}' | \
  sort -u | while read img; do
    echo "Scanneles: $img"
    trivy image --severity HIGH,CRITICAL --quiet "$img"
  done

Folyamatos scannelehez telepitsd a Trivy Operatort:

helm repo add aqua https://aquasecurity.github.io/helm-charts/
helm install trivy-operator aqua/trivy-operator \
  --namespace trivy-system \
  --create-namespace \
  --set trivy.severity="HIGH,CRITICAL"

Ez VulnerabilityReport CRD-ket hoz letre minden workloadhoz:

# Sebezhetosegi reportok megtekintese
kubectl get vulnerabilityreports -A \
  -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}: Critical={.report.summary.criticalCount} High={.report.summary.highCount}{"\n"}{end}'

4. Runtime biztonsag Falco-val

A NIS2 valos ideju fenyegeteseszlelest kovetel. En erre Falco-t rakok fel, mert rendszerhivas szinten figyel es gyorsan jelez, ha valami gyanus.

Falco telepitese Helm-mel:

helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco \
  --namespace falco \
  --create-namespace \
  --set falcosidekick.enabled=true \
  --set falcosidekick.config.slack.webhookurl="https://hooks.slack.com/services/YOUR/WEBHOOK" \
  --set driver.kind=ebpf

A Falco jo alapertelmezettsegekkel jon, de en szoktam hozzaadni egyedi szabalyokat NIS2-specifikus helyzetekre:

# custom-rules.yaml
- rule: Sensitive File Access in Container
  desc: Erzekeny fajlok olvasasanak eszlelese, ami adatlopasra utalhat
  condition: >
    container and open_read and
    (fd.name startswith /etc/shadow or
     fd.name startswith /etc/passwd or
     fd.name startswith /run/secrets)    
  output: >
    Erzekeny fajl megnyitva konterben
    (file=%fd.name user=%user.name container=%container.name
     image=%container.image.repository pod=%k8s.pod.name ns=%k8s.ns.name)    
  priority: WARNING
  tags: [nis2, data_access]

- rule: Unexpected Outbound Connection
  desc: Kontener varatlan kulso IP-re csatlakozik
  condition: >
    container and evt.type=connect and fd.typechar=4 and
    fd.ip != "0.0.0.0" and not fd.snet in (rfc_1918_addresses)    
  output: >
    Varatlan kimeno kapcsolat
    (dest=%fd.name user=%user.name container=%container.name
     pod=%k8s.pod.name ns=%k8s.ns.name)    
  priority: NOTICE
  tags: [nis2, network]

5. Policy enforcement Kyverno-val

Szukseg van olyan vedokorlatokra, amik mar admission idoben megfogjak a rossz konfiguraciokat. En Kyverno-t hasznalok, mert sima Kubernetes YAML-lel lehet dolgozni, nem kell hozza uj policy nyelv.

Telepites:

helm repo add kyverno https://kyverno.github.io/kyverno/
helm install kyverno kyverno/kyverno \
  --namespace kyverno \
  --create-namespace

Ezeket a szabalyokat ervenyesitem NIS2 megfeleleshez:

# Non-root kontenerek kovetelmenye
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-non-root
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-non-root
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Root-kent valo futtatás nem engedelyezett NIS2 megfelelesseg miatt"
        pattern:
          spec:
            containers:
              - securityContext:
                  runAsNonRoot: true
---
# Csak jovahagyott registry-kbol lehessen image-et huzni
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: restrict-image-registries
spec:
  validationFailureAction: Enforce
  rules:
    - name: validate-registries
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Az image-eknek jovahagyott registry-bol kell szarmazniuk"
        pattern:
          spec:
            containers:
              - image: "your-registry.io/*"
---
# Resource limitek kovetelmenye (zajos szomszed DoS megelozese)
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-limits
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "Resource limitek megadasa kotelezo"
        pattern:
          spec:
            containers:
              - resources:
                  limits:
                    memory: "?*"
                    cpu: "?*"

6. Audit logolas es megorzesi ido

A NIS2 megkoveteli, hogy legyenek visszanezheto logok incidensvizsgalathoz. A Kubernetes audit logok pontosan ezt adjak, latom bennuk, ki mit es mikor csinalt.

Keszits audit policy-t:

# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  # Pod, deployment, secret valtozasok logolasa
  - level: RequestResponse
    resources:
      - group: ""
        resources: ["pods", "secrets", "configmaps"]
      - group: "apps"
        resources: ["deployments", "statefulsets", "daemonsets"]
    verbs: ["create", "update", "patch", "delete"]

  # Hitelesitesi dontesek logolasa
  - level: Metadata
    resources:
      - group: "authentication.k8s.io"

  # RBAC valtozasok logolasa
  - level: RequestResponse
    resources:
      - group: "rbac.authorization.k8s.io"

  # Zajos csak-olvasasi keresek kihagyasa
  - level: None
    verbs: ["get", "list", "watch"]
    resources:
      - group: ""
        resources: ["events"]

Engedelyezd az API szerveren (kubeadm klaszterenel add hozza a /etc/kubernetes/manifests/kube-apiserver.yaml-hoz):

spec:
  containers:
    - command:
        - kube-apiserver
        - --audit-policy-file=/etc/kubernetes/audit-policy.yaml
        - --audit-log-path=/var/log/kubernetes/audit.log
        - --audit-log-maxage=90
        - --audit-log-maxbackup=10
        - --audit-log-maxsize=100

Centralizalt logolashoz kuldd tovabb a SIEM-edbe. En Fluent Bit-et hasznalok:

helm repo add fluent https://fluent.github.io/helm-charts
helm install fluent-bit fluent/fluent-bit \
  --namespace logging \
  --create-namespace \
  --set config.outputs="[OUTPUT]\n    Name  es\n    Match *\n    Host  elasticsearch.logging.svc\n    Port  9200\n    Index k8s-audit\n    Retry_Limit 5"

A NIS2 nem ad meg pontos megorzesi idot, de a legtobb nemzeti implementacio legalabb 12-18 honapot ker. En ennek megfeleloen allitom be az Elasticsearch ILM policy-t.

7. Incidenskezeles: a 24/72 oras hataridok betartasa

A NIS2 szigoru jelentesi hataridoket ir elo:

  • 24 ora: Korai figyelmeztetes a nemzeti CSIRT-nek, miutan tudomast szerzek egy jelentos incidensrol
  • 72 ora: Teljes incidensjelentes kezdeti ertekelssel
  • 1 honap: Zarojelentes

Ehhez olyan riasztasi folyamat kell, ami tenyleg gyorsan jelez. Nalam igy van osszekotve a Falco az incidenskezelesi pipeline-nal:

# falcosidekick values incidensriasztashoz
config:
  slack:
    webhookurl: "https://hooks.slack.com/services/YOUR/WEBHOOK"
    minimumpriority: "warning"
  webhook:
    address: "https://your-incident-api.internal/falco"
    minimumpriority: "critical"
  pagerduty:
    routingkey: "YOUR_ROUTING_KEY"
    minimumpriority: "critical"

Prometheus alerteket is beallitok klaszterszintu anomaliakra:

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: nis2-security-alerts
  namespace: monitoring
spec:
  groups:
    - name: nis2-compliance
      rules:
        - alert: UnauthorizedAPIAccess
          expr: |
            sum(rate(apiserver_audit_event_total{verb=~"create|update|delete",code=~"4.."}[5m])) > 10            
          for: 2m
          labels:
            severity: critical
            compliance: nis2
          annotations:
            summary: "Magas aranyú jogosulatlan API hivasok eszlelve"
            runbook: "Ellenorizd az audit logokat, NIS2 24 oras ertesites szukseges lehet"

        - alert: PodSecurityViolation
          expr: |
            sum(increase(falco_events{priority=~"Critical|Emergency"}[10m])) > 0            
          for: 1m
          labels:
            severity: critical
            compliance: nis2
          annotations:
            summary: "Falco kritikus biztonsagi esemenyt eszlelt"

A folyamatot dokumentalom, es rendszeresen vegigvesszuk a csapattal, ki mit csinal riasztas eseten. A korai figyelmeztetes sablont is automatizalom, hogy kritikus esetben 24 oran belul ki lehessen kuldeni.

8. Ellatasilancbiztonsag: SBOM-ok es alairásas image-ek

A NIS2 konkretan kiterjed az ellatasilancbiztonsag kockazatkezelesere. Konteneres workloadoknal ez nalam ket dolgot jelent: tudom, mi van az image-ben (SBOM), es igazolom, hogy nem nyultak hozza (alairas).

SBOM generlas Syft-tel

# SBOM generaals egy image-hez
syft your-registry.io/app:latest -o spdx-json > app-sbom.spdx.json

# SBOM csatolasa az image-hez a registry-ben
cosign attach sbom --sbom app-sbom.spdx.json your-registry.io/app:latest

Image alairas Cosign/Sigstore-ral

# Kulcspar generalas (egyszer csinalod, a privat kulcsot tarold biztonságosan)
cosign generate-key-pair

# Image alairas build utan
cosign sign --key cosign.key your-registry.io/app:latest

# Alairas ellenorzese
cosign verify --key cosign.pub your-registry.io/app:latest

Kulcs nelkuli alairashoz (ajanlott CI/CD-hez) hasznald a Sigstore Fulcio-jat:

# CI pipeline-ban - OIDC identitassal ir ala, nem kell kulcsokat kezelni
cosign sign your-registry.io/app:latest

Alairas ellenorzes ervenyesitese Kyverno-val:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signatures
spec:
  validationFailureAction: Enforce
  rules:
    - name: check-signature
      match:
        any:
          - resources:
              kinds:
                - Pod
      verifyImages:
        - imageReferences:
            - "your-registry.io/*"
          attestors:
            - entries:
                - keys:
                    publicKeys: |-
                      -----BEGIN PUBLIC KEY-----
                      YOUR_COSIGN_PUBLIC_KEY_HERE
                      -----END PUBLIC KEY-----                      

Megfelelessegi checklista

Itt a tomoritett checklistam. En ezt szoktam vegigvinni minden erintett klaszteren:

  • Default-deny NetworkPolicy-k minden namespace-ben
  • RBAC audit elvegezve, nincs felesleges wildcard cluster-admin
  • Image scanning a CI/CD pipeline-ban (Trivy)
  • Folyamatos scanning a klaszterben (Trivy Operator)
  • Runtime eszleles telepitve (Falco)
  • Admission policy-k ervenyesitve (Kyverno vagy OPA Gatekeeper)
  • Kubernetes audit logolas bekapcsolva 12+ honapos megorzesi idovel
  • Centralizalt logolas Fluent Bit-tel vagy hasonloval
  • Riasztasi pipeline ugyeletes rotacioval
  • Incidenskezelesi runbook NIS2 jelentesi sablonokkal
  • SBOM generaals minden production image-hez
  • Image alairas a CI/CD-ben
  • Alairas ellenorzes az admission controlban
  • Rendszeres penetracios tesztek (legalabb evente)

Osszefoglalas

A NIS2 megfeleles nekem nem egyetlen tool, es nem is egy egyszeri pipa. Ez folyamatos hardening, monitorozas es reagalas. A jo oldala az, hogy Kubernetesben mar ott vannak az eszkozok, tobbnyire fegyelmezett konfiguraciorol van szo, nem nagy egyedi fejlesztesrol.

En mindig a legnagyobb hatasu lepesekkel kezdek: network policy-k, RBAC audit es image scanning. Erre jon ra a runtime eszleles es a policy enforcement. Utana zarom le a temat audit logolassal es stabil incidenskezelesi folyamattal.

A 24 oras jelentesi hatarido az, ami a legtobb csapatot meglepi. Emiatt a riasztasi pipeline-t erdemes most rendbe rakni, nem akkor, amikor mar tenyleges incidens van.

Ha van sajat tapasztalatod NIS2 es Kubernetes teren, szivesen osszevetem az enyemmel. Ebben a temaban en is folyamatosan tanulok.