Abeceda sigurnosti u Kubernetesu: autentifikacija, autorizacija, revizija

Abeceda sigurnosti u Kubernetesu: autentifikacija, autorizacija, revizija

рано ili kasnije u radu bilo kojeg sustava postavlja se pitanje sigurnosti: osiguravanje autentifikacije, razdvajanje prava, revizija i drugih zadataka. Za Kubernetes već je stvoreno mnogo rješenja, koja omogućuju postizanje usklađenosti sa standardima čak i u vrlo zahtjevnim okruženjima… Ovaj materijal posvećen je osnovnim aspektima sigurnosti, implementiranim u okviru ugrađenih mehanizama K8s. Prije svega, bit će koristan onima koji se počinju upoznavati s Kubernetesom, kao polazna točka za proučavanje pitanja vezanih za sigurnost.

Autentifikacija

U Kubernetesu postoje dvije vrste korisnika:

  • Računi servisa — računi kojima upravlja Kubernetes API;
  • Korisnici — „normalni“ korisnici kojima upravljaju vanjske, neovisne usluge.

Osnovna razlika između ovih tipova je u tome što za račune servisa postoje posebni objekti u Kubernetes API (oni se tako i nazivaju — ServiceAccounts), koji su vezani za prostor imena i skup autorizacijskih podataka pohranjenih u klasteru u objektima tipa Secrets. Takvi korisnici (računi servisa) su prvenstveno namijenjeni upravljanju pravima pristupa Kubernetes API procesima koji rade unutar Kubernetes klastera.

Obični korisnici nemaju zapise u Kubernetes API: njihovo upravljanje mora se provoditi vanjskim mehanizmima. Oni su namijenjeni ljudima ili procesima koji žive izvan klastera.

Svaki zahtjev prema API-ju vezan je ili za račun servisa, ili za korisnika, ili se smatra anonimnim.

Autentifikacijski podaci korisnika uključuju:

  • Korisničko ime — ime korisnika (ovisno o registru!);
  • UID — strojno čitljiva oznaka identifikacije korisnika koja je „dosljednija i jedinstvenija od imena korisnika“;
  • Grupe — popis grupa kojima korisnik pripada;
  • Dodatno — dodatna polja koja se mogu koristiti u mehanizmu autorizacije.

Kubernetes može koristiti veliki broj mehanizama autentifikacije: X509 certifikate, Bearer tokene, autentifikacijske proksije, HTTP Basic Auth. Pomoću ovih mehanizama može se implementirati mnoštvo shema autorizacije: od statične datoteke s lozinkama do OpenID OAuth2.

Štoviše, dopušteno je korištenje više shema autorizacije istovremeno. Po defaultu u klasteru se koriste:

  • tokeni računa servisa — za račune servisa;
  • X509 — za korisnike.

Pitanje upravljanja ServiceAccountima izlazi iz okvira ovog članka, a svima koji žele detaljnije upoznati s ovom temom preporučam da započnu s stranicom službene dokumentacije. Mi ćemo detaljnije razmotriti pitanje rada sa X509 certifikatima.

Certifikati za korisnike (X.509)

Klasični način rada s certifikatima podrazumijeva:

  • generisanje ključa:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • generisanje zahtjeva za certifikat:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • obrada zahtjeva za certifikat uz pomoć ključeva CA klastera Kubernetes, dobijanje certifikata korisnika (za dobijanje certifikata potrebno je koristiti račun koji ima pristup ključu centra za certifikaciju klastera Kubernetes, koji je po defaultu smješten /etc/kubernetes/pki/ca.key):
    openssl x509 -req -in ~/.certs/mynewuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ~/.certs/mynewuser.crt -days 500
  • kreiranje konfiguracijske datoteke:
    • opis klastera (navedite adresu i lokaciju datoteke certifikata CA konkretne instalacije klastera):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • ili — kao nepreporučeni način — nije potrebno navoditi korijenski certifikat (tada kubectl neće provjeravati ispravnost api-servera klastera):
      kubectl config set-cluster kubernetes --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • dodavanje korisnika u konfiguracijsku datoteku:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt --client-key=.certs/mynewuser.key
    • dodavanje konteksta:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • postavljanje konteksta po zadanim postavkama:
      kubectl config use-context mynewuser-context

Nakon gore navedenih radnji, u datoteci .kube/config bit će kreiran konfiguracijski oblik:

apiVersion: v1
clusters:
- cluster:
    certificate-authority: /etc/kubernetes/pki/ca.crt
    server: https://192.168.100.200:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    namespace: target-namespace
    user: mynewuser
  name: mynewuser-context
current-context: mynewuser-context
kind: Config
preferences: {}
users:
- name: mynewuser
  user:
    client-certificate: /home/mynewuser/.certs/mynewuser.crt
    client-key: /home/mynewuser/.certs/mynewuser.key

Za olakšavanje premještanja konfiguracije između računa i servera, korisno je urediti vrijednosti sljedećih ključeva:

  • certificate-authority
  • client-certificate
  • client-key

Za to se navedene datoteke mogu kodirati pomoću base64 i upisati ih u konfiguraciju, dodajući sufiks -data, tj. dobijajući certificate-authority-data itd.

Certifikati s kubeadm

S izdanjem Kubernetes 1.15 rad sa certifikatima postao je znatno lakši zahvaljujući alpha verziji njegove podrške u alatki kubeadm. Na primjer, ovako može izgledati generacija konfiguracijske datoteke s korisničkim ključevima:

kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200

NB: Potrebna advertise address može se vidjeti u konfiguraciji api-servera, koja je po defaultu smještena u /etc/kubernetes/manifests/kube-apiserver.yaml.

Rezultantna konfiguracija bit će ispisana u stdout. Potrebno ju je pohraniti u ~/kube/config korisnički račun ili u datoteku navedenu u varijabli okruženja KUBECONFIG.

Zaviriti dublje

Za one koji žele detaljnije proučiti opisane teme:

Autorizacija

Defaultni autorizirani korisnički račun nema prava na radnje u klasteru. Za dodjelu dozvola u Kubernetes-u implementiran je mehanizam autorizacije.

Do verzije 1.6 u Kubernetes-u koristio se tip autorizacije nazvan ABAC (Kontrola pristupa temeljenog na atributima). Detalje o njemu možete pronaći u službene dokumentacije. Trenutno se ovaj pristup smatra zastarjelim (legacy), međutim i dalje ga možete koristiti zajedno s drugim tipovima autorizacije.

Aktualni (i fleksibilniji) način podjele prava pristupa klasteru naziva se RBAC (Kontrola pristupa temeljenog na ulozi). Proglašen je stabilnim od verzije Kubernetes 1.8. RBAC implementira model prava u kojem je sve zabranjeno što nije izričito dozvoljeno.
Da biste omogućili RBAC, potrebno je pokrenuti Kubernetes api-server s parametrima --authorization-mode=RBAC. Parametri se postavljaju u manifest s konfiguracijom api-servera, koji se po defaultu nalazi na putu /etc/kubernetes/manifests/kube-apiserver.yaml, u sekciji naredba. Ipak, RBAC je po defaultu već uključen, stoga se vjerojatno ne morate brinuti o tome: možete se uvjeriti u to prema vrijednosti authorization-mode (u već spomenutom kube-apiserver.yaml). Usput, među njegovim vrijednostima mogu se naći i drugi tipovi autorizacije (čvor, webhook, always allow), ali ćemo njihovo razmatranje ostaviti izvan okvira ovog materijala.

U međuvremenu, već smo objavili članak dovoljno detaljno izlaganje principa i osobitosti rada s RBAC-om, tako da ću se dalje ograničiti na kratak popis osnova i primjera.

Za upravljanje pristupom u Kubernetes-u putem RBAC-a koriste se sljedeće API entitete:

  • Uloga i ClusterRole — uloge koje služe za opisivanje prava pristupa:
  • Uloga omogućuje opisivanje prava unutar imenskog prostora;
  • ClusterRole — unutar klastera, uključujući klaster-specifične objekte poput čvorova, non-resources url-ova (tj. onih koji nisu povezani s resursima Kubernetes — kao što su /version, /logs, /api*);
  • RoleBinding i ClusterRoleBinding — služi za povezivanje Uloga i ClusterRole s korisnikom, grupom korisnika ili ServiceAccount-om.

Entiteti Role i RoleBinding su ograničeni imenskim prostorom, tj. moraju se nalaziti unutar jednog imenskog prostora. Međutim, RoleBinding može referencirati ClusterRole, što omogućava stvaranje seta standardnih dozvola i upravljanje pristupom putem njih.

Uloge opisuju prava pomoću skupova pravila koja sadrže:

  • grupe API — vidi službenu dokumentaciju o apiGroups i izlazu kubectl api-resources;
  • resurse (resources: pod, namespace, deployment itd.);
  • glagole (verbs: set, update itd.).
  • imena resursa (resourceNames) — u slučaju kada je potrebno omogućiti pristup određenom resursu, a ne svim resursima tog tipa.

Detaljnije razmatranje autorizacije u Kubernetesu može se pronaći na stranici službene dokumentacije. Umjesto toga (a točnije — kao dodatak tome) dajem primjere koji ilustriraju njen rad.

Primjeri entiteta RBAC

Jednostavan Uloga, koji omogućava dobivanje popisa i statusa podova i njihovo praćenje u imenskom prostoru target-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: target-namespace
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Primjer ClusterRole, što omogućava dobivanje popisa i statusa podova i njihovo praćenje u cijelom klasteru:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # nema sekcije "namespace", jer ClusterRole obuhvaća cijeli klaster
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

Primjer RoleBinding, što omogućava korisniku mynewuser "čitati" podove u imenskom prostoru my-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: target-namespace
subjects:
- kind: User
  name: mynewuser # ime korisnika ovisno o velikim i malim slovima!
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # ovdje mora biti “Role” ili “ClusterRole”
  name: pod-reader # ime Role, koja se nalazi u istom namespace,
                   # ili ime ClusterRole koju
                   # želimo omogućiti korisniku
  apiGroup: rbac.authorization.k8s.io

Revizija događaja

Shematski se arhitektura Kubernetesa može predstaviti na sljedeći način:

Abeceda sigurnosti u Kubernetesu: autentifikacija, autorizacija, revizija

Ključna komponenta Kubernetesa, odgovorna za obradu zahtjeva, — api-server. Sve operacije na klasteru prolaze kroz njega. Više o ovim unutarnjim mehanizmima možete pročitati u članku „Što se događa u Kubernetesu prilikom pokretanja kubectl run?».

Revizija sustava — zanimljiva značajka u Kubernetesu koja je prema zadanim postavkama isključena. Omogućuje bilježenje svih zahtjeva na Kubernetes API. Kao što se može lako pretpostaviti, putem ovog API-aja izvršavaju se sve radnje povezane s kontrolom i promjenom stanja klastera. Dobar opis njenih mogućnosti možete (kao obično) pronaći u službene dokumentacije K8s. U nastavku ću pokušati izložiti temu jednostavnijim jezikom.

Dakle, da uključimo reviziju, trebamo proslijediti kontejneru u api-server tri obvezna parametra, o kojima je više detalja navedeno u nastavku:

  • --audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml
  • --audit-log-path=/var/log/kube-audit/audit.log
  • --audit-log-format=json

Osim ovih triju obveznih parametara, postoji mnogo dodatnih postavki vezanih uz reviziju: od rotacije logova do opisa webhooka. Primjer parametara rotacije logova:

  • --audit-log-maxbackup=10
  • --audit-log-maxsize=100
  • --audit-log-maxage=7

Ali nećemo se previše zadržavati na njima — sve detalje možete pronaći u dokumentaciji za kube-apiserver..

Kao što je već spomenuto, svi parametri postavljaju se u manifest s konfiguracijom api-servera (po zadanim postavkama /etc/kubernetes/manifests/kube-apiserver.yaml), u sekciji naredba. Vratimo se na tri obvezna parametra i razmotrimo ih:

  1. audit-policy-file — put do YAML datoteke s opisom politike (policy) revizije. O njenom sadržaju još ćemo se vratiti, a za sada napominjem da datoteka mora biti dostupna procesu api-servera. Stoga je potrebno montirati je unutar kontejnera, a za to možete dodati sljedeći kod u odgovarajuće sekcije konfiguracije:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — put do datoteke loga. Put također mora biti dostupan procesu api-servera, stoga ga također opisujemo na sličan način:
      volumeMounts:
        - mountPath: /var/log/kube-audit
          name: logs
          readOnly: false
      volumes:
      - hostPath:
          path: /var/log/kube-audit
          type: DirectoryOrCreate
        name: logs
  3. audit-log-format — format loga revizije. Prema zadanim postavkama to je json, ali dostupan je i zastarjeli tekstualni format (legacy).

Politika revizije

Sada o spomenutoj datoteci s opisom politike bilježenja. Prvo pojmove audit policy — to je level, razina bilježenja. One mogu biti sljedeće:

  • Nema — ne bilježiti;
  • Metadata — bilježenje metapodataka zahtjeva: korisnika, vrijeme zahtjeva, ciljani resurs (pod, namespace itd.), tip akcije (verb) itd.;
  • Request — bilježenje metapodataka i tijela zahtjeva;
  • RequestResponse — bilježenje metapodataka, tijela zahtjeva i tijela odgovora.

Posljednja dva nivoa (Request i RequestResponse) ne bilježe zahtjeve koji nisu pozivali resurse (pozive na takozvane non-resources urls).

Također, svi zahtjevi prolaze kroz nekoliko faza:

  • RequestReceived — faza kada je zahtjev primljen od strane obraditelja i još nije proslijeđen dalje kroz lanac obraditelja;
  • ResponseStarted — glava odgovora je poslana, ali prije slanja tijela odgovora. Generira se za dugotrajne zahtjeve (na primjer, watch);
  • ResponseComplete — tijelo odgovora je poslano, više informacija neće biti poslane;
  • Panic — događaji se generiraju kada se otkrije izvanredna situacija.

Za preskakanje bilo kojih faza može se koristiti omitStages.

U datoteci politike možemo opisati nekoliko sekcija sa različitim nivoima bilježenja. Primijenit će se prvo odgovarajuće pravilo pronađeno u opisu politike.

Demon kubelet prati promjene manifesta s konfiguracijom api-servera i kada ih otkrije, ponovno pokreće kontejner s api-serverom. No postoji važna sitnica: promjene u datoteci politike će se ignorirati. Nakon unosa promjena u datoteku politike potrebno je ručno ponovno pokrenuti api-server. Budući da je api-server pokrenut kao static pod, tim kubectl delete neće dovesti do njegovog ponovnog pokretanja. Trebat će ručno izvršiti docker stop na kube-masterima, gdje je politika audita promijenjena:

docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')

Pri uključivanju audita važno je zapamtiti da na kube-apiserveru opterećenje raste. Konkretno, povećava se potrošnja memorije za pohranu konteksta zahtjeva. Bilježenje u log počinje samo nakon slanja glave odgovora. Također, opterećenje ovisi o konfiguraciji politike audita.

Primjeri politika

Razmotrit ćemo strukturu datoteka politike na primjerima.

Evo jednostavne datoteke policy, kako bismo bilježili sve na nivou Metadata:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

U politici se može navesti popis korisnika (Korisnici i ServiceAccounts) i grupi korisnika. Na primjer, ovako ćemo ignorirati sistemske korisnike, ali bilježiti sve ostalo na nivou Request:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: None
    userGroups:
      - "system:serviceaccounts"
      - "system:nodes"
    users:
      - "system:anonymous"
      - "system:apiserver"
      - "system:kube-controller-manager"
      - "system:kube-scheduler"
  - level: Request

Također postoji mogućnost opisivanja ciljeva:

  • imenskih prostora (imena prostora);
  • glagole (verbs: preuzmi, update, izbriši i ostalih);
  • resurse (resources, odnosno: pod, configmaps i slično) i grupe resursa (apiGrupe).

Obratite pažnju! Resursi i grupe resursa (grupe API, tj. apiGrupe), kao i njihove verzije instalirane u klasteru, mogu se dobiti pomoću naredbi:

kubectl api-resources
kubectl api-versions

Sljedeća audit politika navedena je kao demonstracija najboljih praksi u dokumentaciji Alibaba Cloud:

apiVersion: audit.k8s.io/v1beta1
kind: Policy
# Ne bilježi fazu RequestReceived
omitStages:
  - "RequestReceived"
rules:
  # Ne bilježi događaje koji se smatraju beznačajnima i ne opasnim:
  - level: None
    users: ["system:kube-proxy"]
    verbs: ["watch"]
    resources:
      - group: "" # ovo je api grupa s praznim imenom, kojoj pripadaju
                  # osnovni resursi Kubernetes-a, nazvani “core”
        resources: ["endpoints", "services"]
  - level: None
    users: ["system:unsecured"]
    namespaces: ["kube-system"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["configmaps"]
  - level: None
    users: ["kubelet"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["nodes"]
  - level: None
    userGroups: ["system:nodes"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["nodes"]
  - level: None
    users:
      - system:kube-controller-manager
      - system:kube-scheduler
      - system:serviceaccount:kube-system:endpoint-controller
    verbs: ["get", "update"]
    namespaces: ["kube-system"]
    resources:
      - group: "" # core
        resources: ["endpoints"]
  - level: None
    users: ["system:apiserver"]
    verbs: ["get"]
    resources:
      - group: "" # core
        resources: ["namespaces"]
  # Ne bilježi pristupe read-only URL-ovima:
  - level: None
    nonResourceURLs:
      - /healthz*
      - /version
      - /swagger*
  # Ne bilježi poruke vezane uz tip resursa “događaji”:
  - level: None
    resources:
      - group: "" # core
        resources: ["events"]
  # Resursi tipa Secret, ConfigMap i TokenReview mogu sadržavati tajne podatke,
  # zato bilježimo samo metapodatke povezanih s njima zahtjeva
  - level: Metadata
    resources:
      - group: "" # core
        resources: ["secrets", "configmaps"]
      - group: authentication.k8s.io
        resources: ["tokenreviews"]
  # Radnje tipa get, list i watch mogu biti resursno intenzivne; ne bilježimo ih
  - level: Request
    verbs: ["get", "list", "watch"]
    resources:
      - group: "" # core
      - group: "admissionregistration.k8s.io"
      - group: "apps"
      - group: "authentication.k8s.io"
      - group: "authorization.k8s.io"
      - group: "autoscaling"
      - group: "batch"
      - group: "certificates.k8s.io"
      - group: "extensions"
      - group: "networking.k8s.io"
      - group: "policy"
      - group: "rbac.authorization.k8s.io"
      - group: "settings.k8s.io"
      - group: "storage.k8s.io"
  # Zahtev za bilježenje po defaultu za standardne API resurse
  - level: RequestResponse
    resources:
      - group: "" # core
      - group: "admissionregistration.k8s.io"
      - group: "apps"
      - group: "authentication.k8s.io"
      - group: "authorization.k8s.io"
      - group: "autoscaling"
      - group: "batch"
      - group: "certificates.k8s.io"
      - group: "extensions"
      - group: "networking.k8s.io"
      - group: "policy"
      - group: "rbac.authorization.k8s.io"
      - group: "settings.k8s.io"
      - group: "storage.k8s.io"
  # Default nivo logovanja za sve ostale zahteve
  - level: Metadata

Drugi dobar primjer audit policy-a — profil korišten u GCE.

Za brze reakcije na audit događaje postoji mogućnost opisati webhook. Ovo pitanje je obrađeno u službene dokumentacije, ostavit ću ga izvan okvira ovog članka.

Zaključci

U članku je dan pregled mehanizama osnovnog osiguranja u Kubernetes klasterima, koji omogućuju stvaranje personaliziranih korisničkih računa, razdjeljivanje njihovih prava i registraciju njihovih aktivnosti. Nadam se da će biti koristan onima koji su se suočili s takvim pitanjima u teoriji ili su ih već iskusili u praksi. Preporučujem vam da se također upoznate s popisom drugih materijala o sigurnosti u Kubernetesu navedenim u "P.S." — možda ćete među njima pronaći potrebne detalje o problemima koji su vam važni.

P.S.

Pročitajte i na našem blogu:

Izvor: habr.com

Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere 🔥 Kupite pouzdan hosting za web stranice s DDoS zaštitom, VPS VDS servere | ProHoster