Abeceda sigurnosti u Kubernetesu: autentifikacija, autorizacija, revizija

Abeceda sigurnosti u Kubernetesu: autentifikacija, autorizacija, revizija

Prej ko ali kasneje se v delovanju vsakega sistema postavi vprašanje varnosti: zagotavljanje avtentikacije, razdeljevanje pravic, revizije in drugih nalog. Za Kubernetes je že ustvarjenih številne rešitve, ki omogočajo dosego skladnosti s standardi tudi v zelo zahtevnih okoljih... Ta material je posvečen osnovnim vidikom varnosti, uveljavljenim v okviru vgrajenih mehanizmov K8s. Predvsem bo koristen tistim, ki se začenjajo spoznavati s Kubernetesom, - kot izhodiščna točka za preučevanje vprašanj, povezanih z varnostjo.

Autentifikacija

V Kubernetesu obstajata dva tipa uporabnikov:

  • Service Accounts — računi, ki jih upravlja Kubernetes API;
  • Uporabniki — 'običajni' uporabniki, ki jih upravljajo zunanje, neodvisne storitve.

Glavna razlika med tema tipoma je, da za Service Accounts obstajajo posebni objekti v Kubernetes API (ti se imenujejo - ServiceAccounts), ki so vezani na prostor imen in niz avtorizacijskih podatkov, shranjenih v gručah v objektih tipa Secrets. Takšni uporabniki (Service Accounts) so namenjeni predvsem upravljanju pravic dostopa do Kubernetes API procesov, ki delujejo v Kubernetes gručah.

Običajni uporabniki pa nimajo zapisov v Kubernetes API: upravljanje z njimi mora potekati preko zunanjih mehanizmov. Namenjeni so osebam ali procesom, ki živijo zunaj gruče.

Vsak zahtevek k API je povezan bodisi s Service Account bodisi z uporabnikom bodisi velja za anonimnega.

Avtentikacijski podatki uporabnika vključujejo:

  • Uporabniško ime — uporabniško ime (odvisno od malih in velikih črk!);
  • UID — strojno berljiva identifikacijska vrstica uporabnika, ki je 'bolj dosledna in edinstvena kot uporabniško ime';
  • Skupine — seznam skupin, za katere se šteje uporabnik;
  • Dodatno — dodatna polja, ki jih lahko uporabi mehanizem avtorizacije.

Kubernetes lahko uporablja veliko število mehanizmov avtentikacije: certifikati X509, Bearer žetoni, avtentikacijski proxy, HTTP Basic Auth. S pomočjo teh mehanizmov je mogoče uresničiti veliko število shem avtorizacije: od statičnega datoteke s gesli do OpenID OAuth2.

Poleg tega je dovoljena uporaba več shem avtorizacije hkrati. Privzeto se v gruči uporabljajo:

  • žetoni službenih računov — za Service Accounts;
  • X509 — za uporabnike.

Vprašanje o upravljanju ServiceAccounts presega obseg tega članka, zato tistim, ki želijo podrobneje spoznati to temo, priporočam, da začnejo s strani uradne dokumentacije. Mi pa bomo podrobneje obravnavali vprašanje delovanja certifikatov X509.

Certifikati za uporabnike (X.509)

Klasičen način dela s certifikati predvideva:

  • generacijo ključa:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/..certs/mynewuser.key 2048
  • generacijo zahteve za certifikat:
    openssl req -new -key ~/..certs/mynewuser.key -out ~/..certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • obdelavo zahteve za certifikat s pomočjo ključev CA grozda Kubernetes, pridobitev certifikata uporabnika (za pridobitev certifikata morate uporabiti račun, ki ima dostop do ključa certifikacijske agencije grozda Kubernetes, ki je privzeto v /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
  • ustvarjanje konfiguracijske datoteke:
    • opis grozda (navedite naslov in lokacijo datoteke certifikata CA konkretne namestitve grozda):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • ali — kako nepriporočena možnost — lahko ne navedete koreninskega certifikata (takrat kubectl ne bo preverjal pravilnosti api-serverja grozda):
      kubectl config set-cluster kubernetes --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • dodajanje uporabnika v konfiguracijsko datoteko:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt --client-key=.certs/mynewuser.key
    • dodajanje konteksta:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • določitvi privzetega konteksta:
      kubectl config use-context mynewuser-context

Po zgoraj navedenih postopkih bo v datoteki .kube/config ustvarjena konfiguracija v obliki:

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 lažje prenašanje konfiguracije med računi in strežniki je koristno urediti vrednosti naslednjih ključev:

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

Za to lahko kodirate navedene datoteke s pomočjo base64 in jih vnesete v konfiguracijo, tako da dodate pripono -data, torej pridobite certificate-authority-data itd.

Certifikati s kubeadm

Z izdajo Kubernetes 1.15 Delo s sertifikatami postalo znatno lažje zahvaljujoč alfa različici njene podpore v orodju kubeadm. Na primer, tako lahko zdaj izgleda generacija konfiguracijske datoteke s korisniškimi ključi:

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

NB: Zahtevana advertise address lahko si ogledate v konfiguraciji api-server, ki je privzeto locirana v /etc/kubernetes/manifests/kube-apiserver.yaml.

Končni konfiguracij bo izpisan v stdout. Shraniti ga je treba v ~/.kube/config uporabniški račun ali pa v datoteko, določeno v okoljski spremenljivki KUBECONFIG.

Poglejmo podrobneje

Za tiste, ki želijo bolj temeljito razumeti obravnavane teme:

Avtorizacija

Avtoriziran uporabniški račun po privzetku nima pravic za delo v klastru. Za dodelitev dovoljenj v Kubernetesu je bil uveden mehanizem avtorizacije.

Do različice 1.6 se je v Kubernetesu uporabljal tip avtorizacije, imenovan ABAC (Attribute-based access control). Podrobnosti o njem lahko najdete v uradni dokumentaciji. Ta pristop se trenutno šteje za zastarelega (legacy), vendar ga še vedno lahko uporabljate hkrati z drugimi tipi avtorizacije.

Trenutni (in bolj prilagodljiv) način razdeljevanja pravic dostopa do klastru se imenuje RBAC (Role-based access control). Bil je razglašen za stabilnega od različice Kubernetes 1.8. RBAC uveljavlja model pravic, v katerem je vse, kar ni izrecno dovoljeno, prepovedano.
Da bi omogočili RBAC, morate zagnati Kubernetes api-server s parametrom --authorization-mode=RBAC. Parametri se nastavijo v manifestu s konfiguracijo api-server, ki je privzeto na poti /etc/kubernetes/manifests/kube-apiserver.yaml, v razdelku ukaz. Pravzaprav je RBAC po privzetku že vključen, zato verjetno ni razloga za skrb: preveriti to je mogoče po vrednosti authorization-mode (v že omenjenem kube-apiserver.yaml). Mimogrede, med njegovimi vrednostmi so lahko tudi drugi tipi avtorizacije (node, webhook, always allow), vendar tovrstno obravnavo prepustimo drugim virom.

Mimogrede, že smo objavili članak z dovolj podrobnim opisom načel in značilnosti dela z RBAC, zato se bom nadalje omejil na kratko naštevanje osnov in primerov.

Za upravljanje dostopa v Kubernetes preko RBAC se uporabljajo naslednje entitete API:

  • Role in ClusterRole — vloge, ki se uporabljajo za opis pravic dostopa:
  • Role omogoča opisovanje pravic v okviru imenskega prostora;
  • ClusterRole — v okviru gruče, vključno s gručnimi specifičnimi objekti, kot so vozli, URL-ji brez virov (tj. niso povezani z viri Kubernetes — na primer, /version, /logs, /api*);
  • RoleBinding in ClusterRoleBinding — služi za vezavo Role in ClusterRole na uporabnika, skupino uporabnikov ali ServiceAccount.

Entitete Role in RoleBinding so omejene na imenski prostor, tj. morajo biti v okviru enega samega imenskega prostora. Vendar pa lahko RoleBinding sklicuje na ClusterRole, kar omogoča ustvarjanje naborov standardnih dovoljenj in upravljanje dostopa z njimi.

Vloge opisujejo pravice s pomočjo naborov pravil, ki vsebujejo:

  • skupine API — glej uradno dokumentacijo po apiGroups in izhodu kubectl api-resources;
  • viri (resources: pod, namespace, deployment itd.);
  • glagoli (verbs: set, update itd.).
  • imena virov (resourceNames) — v primeru, ko je potrebno omogočiti dostop do določenega vira, ne pa do vseh virov te vrste.

Podrobnejšo analizo avtorizacije v Kubernetes lahko najdete na strani uradni dokumentaciji. Namesto tega (natančneje — v dodatku k temu) bom navedel primere, ki ponazarjajo njeno delovanje.

Primeri entitet RBAC

Jednostavno Role, ki omogoča pridobivanje seznama in statusa podov ter spremljanje le-teh v imenskem 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"]

Primer ClusterRole, kar omogoča pridobitev seznama in statusa podov ter spremljanje le-teh v celotnem grozdu:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # sekcije "namespace" ni, saj ClusterRole deluje v celotnem grozdu
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

Primer RoleBinding, kar uporabniku mynewuser omogoča «branje» podov v imenskem prostoru my-namespace:

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: target-namespace
subjects:
- kind: User
  name: mynewuser # ime uporabnika je občutljivo na velikost črk!
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # tukaj mora biti “Role” ali “ClusterRole”
  name: pod-reader # ime Role, ki se nahaja v istem imenskem prostoru,
                   # ali ime ClusterRole, katere uporabo
                   # želimo dovoliti uporabniku
  apiGroup: rbac.authorization.k8s.io

Revizija dogodkov

Arhitekturo Kubernetes lahko shematično predstavimo takole:

Abeceda sigurnosti u Kubernetesu: autentifikacija, autorizacija, revizija

Ključna komponenta Kubernetes, odgovorna za obdelavo zahtevkov, — api-server. Vse operacije nad grozdom potekajo preko njega. Več o teh notranjih mehanizmih lahko preberete v članku «Kaj se zgodi v Kubernetes pri zagonu kubectl run?».

Avtomatska revizija sistema je zanimiva funkcija v Kubernetesu, ki je privzeto izključena. Omogoča beleženje vseh dostopov do Kubernetes API. Kot lahko ugibate, preko tega API se izvajajo vse akcije, povezane s kontrolo in spremembo stanja klasterja. Dober opis njenih zmožnosti lahko (kot ponavadi) najdete v uradni dokumentaciji K8s. Nadalje bom poskušal tematiko predstaviti bolj preprosto.

Dakle, Da bi omogočili revizijo, moramo api-serverju posredovati tri obvezne parametre, o katerih bomo podrobneje govorili spodaj:

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

Poleg teh treh obveznih parametrov obstaja še vrsta dodatnih nastavitev, ki se nanašajo na revizijo: od rotacije logov do opisov webhookov. Primer parametrov rotacije logov:

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

Vendar se ne bomo podrobneje ukvarjali z njimi — vse podrobnosti lahko najdete v dokumentaciji za kube-apiserver..

Kot je bilo že omenjeno, se vsi parametri nastavijo v manifestu z konfiguracijo api-serverja (privzeto /etc/kubernetes/manifests/kube-apiserver.yaml), v razdelku ukaz. Vrnimo se k trem obveznim parametrom in jih razčlenimo:

  1. audit-policy-file — pot do YAML datoteke z opisom politike (policy) revizije. K njeni vsebini se bomo še vrnili, zaenkrat pa naj poudarim, da mora biti datoteka dostopna za branje procesu api-serverja. Zato ji je treba pritrditi v znotraj posode, za kar lahko dodate naslednjo kodo v ustrezne razdelke konfiguracije:
      volumeMounts:
        - mountPath: \/etc\/kubernetes\/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: \/etc\/kubernetes\/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — pot do datoteke loga. Pot mora biti tudi dostopna procesu api-serverja, zato je priporočen postopek montaže:
      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 revizijskega loga. Privzeto je to json, vendar je na voljo tudi zastarela besedilna oblika (legacy).

Politika revizije

Zdaj se osredotočimo na omenjeno datoteko z opisom politike beleženja. Prvi pojem audit policy je level, nivo beleženja. Lahko so naslednji:

  • Noben — ne beleži;
  • Metadata — beleži metapodatke poizvedbe: uporabnika, čas poizvedbe, ciljni vir (pod, namespace itd.), tip dejanja (verb) itd.;
  • Request — beleži metapodatke in telo poizvedbe;
  • RequestResponse — beleži metapodatke, telo poizvedbe in telo odgovora.

Zadnja dva nivoa (Request in RequestResponse) ne beleže zahteve koji se ne upućuju resursima (upiti na tzv. non-resources urls).

Takođe, svi zahtevi prolaze kroz nekoliko faza:

  • RequestReceived — faza kada je zahtev primljen od strane obradnika i još nije prosleđen dalje u lancu obradnika;
  • ResponseStarted — zaglavlja odgovora su poslata, ali pre nego što se pošalje telo odgovora. Generiše se za dugotrajne zahteve (na primer, watch);
  • ResponseComplete — telo odgovora je poslato, više informacija neće biti poslato;
  • Panic — događaji se generišu kada se otkrije vanredna situacija.

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

U fajlu politike možemo opisati nekoliko sekcija sa različitim nivoima logovanja. Primenjivaće se prvo pogodna pravila, pronađena u opisu politike.

Demon kubelet prati promene manifesta sa konfiguracijom api-server-a i prilikom otkrivanja takvih ponovo pokreće kontejner sa api-server-om. Ali postoji važan detalj: promene u fajlu politike će se ignorisati. Nakon izmene fajla politike, potrebno je ručno ponovo pokrenuti api-server. Pošto je api-server pokrenut kao static pod, komanda kubectl delete neće dovesti do njegovog ponovnog pokretanja. Moraćemo ručno uraditi docker stop na kube-master-ima gde je politika audita promenjena:

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

Prilikom uključivanja audita, važno je zapamtiti da na kube-apiserver-u raste opterećenje. Konkretno, povećava se potrošnja memorije za skladištenje konteksta zahteva. Zapisivanje u log počinje tek nakon slanja zaglavlja odgovora. Takođe, opterećenje zavisi od konfiguracije politike audita.

Primeri politika

Razradićemo strukturu fajlova politike na primerima.

Evo jednostavnog fajla policy, da logujemo sve na nivou Metadata:

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

U politici se može navesti spisak korisnika (Uporabniki in ServiceAccounts) i grupa korisnika. Na primer, ovako ćemo ignorisati sistemske korisnike, ali logovati 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đe postoji mogućnost opisivanja ciljeva:

  • imenici (namespaces);
  • glagoli (verbs: pridobi, update, izbriši i slično);
  • viri (resources, a to su: pod, configmaps i sl.) i grupe resursa (apiGroups).

Obratite pažnju! Viri in skupine virov (skupine API, torej apiGroups) ter njihove različice, nameščene v gručah, je mogoče pridobiti z naslednjimi ukazi:

kubectl api-resources
kubectl api-versions

Naslednja politika revizije je navedena kot prikaz najboljših praks v dokumentaciji Alibaba Cloud:

apiVersion: audit.k8s.io/v1beta1
kind: Policy
# Не логировать стадию RequestReceived
omitStages:
  - "RequestReceived"
rules:
  # Не логировать события, считающиеся малозначительными и не опасными:
  - level: None
    users: ["system:kube-proxy"]
    verbs: ["watch"]
    resources:
      - group: "" # это api group с пустым именем, к которому относятся
                  # базовые ресурсы Kubernetes, называемые “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"]
  # Не логировать обращения к read-only URLs:
  - level: None
    nonResourceURLs:
      - /healthz*
      - /version
      - /swagger*
  # Не логировать сообщения, относящиеся к типу ресурсов “события”:
  - level: None
    resources:
      - group: "" # core
        resources: ["events"]
  # Ресурсы типа Secret, ConfigMap и TokenReview могут содержать  секретные данные,
  # поэтому логируем только метаданные связанных с ними запросов
  - level: Metadata
    resources:
      - group: "" # core
        resources: ["secrets", "configmaps"]
      - group: authentication.k8s.io
        resources: ["tokenreviews"]
  # Действия типа get, list и watch могут быть ресурсоёмкими; не логируем их
  - 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"
  # Уровень логирования по умолчанию для стандартных ресурсов API
  - 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"
  # Уровень логирования по умолчанию для всех остальных запросов
  - level: Metadata

Другой хороший пример политики аудита — профиль, используемый в GCE.

Для оперативного реагирования на события аудита есть возможность описать webhook. Этот вопрос раскрыт в uradni dokumentaciji, pustim ga izvan okvira ovog članka.

Zaključki

Članak pruža pregled mehanizama osnovne bezbednosti u Kubernetes klasterima, koji omogućavaju kreiranje personalizovanih korisničkih naloga, deljenje prava, kao i evidentiranje njihovih aktivnosti. Nadam se da će koristiti onima koji su se susreli s ovim pitanjima, bilo teoretski ili u praksi. Takođe preporučujem da pogledate spisak drugih materijala o bezbednosti u Kubernetesu naveden u "P.S.", možda među njima pronađete potrebne detalje koji su vam bitni.

P.S.

Preberite tudi na našem blogu:

Izvor: habr.com

Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki 🔥 Kupite zanesljivo gostovanje za spletne strani z zaščito pred DDoS, VPS VDS strežniki | ProHoster