Abeceda sigurnosti u Kubernetesu: autentifikacija, autorizacija, revizija

Abeceda sigurnosti u Kubernetesu: autentifikacija, autorizacija, revizija

Prije ili kasnije, u radu bilo kojeg sistema, postavlja se pitanje sigurnosti: osiguravanje autentifikacije, razdvajanja prava, revizije i drugih zadataka. Već kreiran za Kubernetes mnoga rješenja, koji vam omogućavaju da postignete usaglašenost sa standardima čak iu vrlo zahtjevnim okruženjima... Isti materijal posvećen je osnovnim aspektima sigurnosti implementiranih u okviru ugrađenih mehanizama K8s. Prije svega, bit će korisno onima koji počinju da se upoznaju sa Kubernetesom - kao polaznom tačkom za proučavanje sigurnosnih pitanja.

Autentifikacija

Postoje dvije vrste korisnika u Kubernetesu:

  • Servisni računi — nalozi kojima upravlja Kubernetes API;
  • korisnici — „normalni“ korisnici kojima upravljaju eksterni, nezavisni servisi.

Glavna razlika između ovih tipova je u tome što za račune usluge postoje posebni objekti u Kubernetes API-ju (tako se zovu - ServiceAccounts), koji su vezani za imenski prostor i skup autorizacijskih podataka pohranjenih u klasteru u objektima tipa Secrets. Takvi korisnici (nalozi usluge) prvenstveno su namijenjeni upravljanju pravima pristupa Kubernetes API-ju procesa koji se pokreću u Kubernetes klasteru.

Obični korisnici nemaju unose u Kubernetes API: njima moraju upravljati eksterni mehanizmi. Namijenjeni su ljudima ili procesima koji žive izvan klastera.

Svaki API zahtjev povezan je ili sa servisnim računom, korisnikom ili se smatra anonimnim.

Podaci za autentifikaciju korisnika uključuju:

  • Korisničko — korisničko ime (razlikuje velika i mala slova!);
  • UID - mašinski čitljiv identifikacioni niz korisnika koji je „dosledniji i jedinstveniji od korisničkog imena“;
  • Grupe — lista grupa kojima korisnik pripada;
  • ekstra — dodatna polja koja se mogu koristiti od strane mehanizma autorizacije.

Kubernetes može koristiti veliki broj mehanizama za autentifikaciju: X509 certifikate, tokene nosioca, proxy za autentifikaciju, HTTP Basic Auth. Koristeći ove mehanizme, možete implementirati veliki broj šema autorizacije: od statične datoteke sa lozinkama do OpenID OAuth2.

Štaviše, moguće je koristiti nekoliko šema autorizacije istovremeno. Klaster podrazumevano koristi:

  • tokeni servisnih računa - za račune usluge;
  • X509 - za korisnike.

Pitanje o upravljanju servisnim računima je izvan okvira ovog članka, ali za one koji se žele detaljnije upoznati s ovim problemom, preporučujem da počnu s zvanične stranice dokumentacije. Pobliže ćemo pogledati pitanje kako X509 certifikati funkcioniraju.

Certifikati za korisnike (X.509)

Klasičan način rada sa sertifikatima podrazumeva:

  • generacija ključeva:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • generiranje zahtjeva za certifikat:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • obrada zahtjeva za certifikatom pomoću CA ključeva Kubernetes klastera, pribavljanje korisničkog certifikata (da biste dobili certifikat, morate koristiti račun koji ima pristup CA ključu Kubernetes klastera, koji se po defaultu nalazi u /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 CA certifikata za određenu instalaciju klastera):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • ili kako nepreporučena opcija - ne morate specificirati root certifikat (tada kubectl neće provjeriti ispravnost api-servera klastera):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • dodavanje korisnika u konfiguracijski fajl:
      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
    • zadani kontekst dodjela:
      kubectl config use-context mynewuser-context

Nakon gore navedenih manipulacija, u datoteci .kube/config kreiraće se ovakva konfiguracija:

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

Da biste olakšali prijenos konfiguracije između računa i servera, korisno je urediti vrijednosti sljedećih ključeva:

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

Da biste to učinili, možete kodirati datoteke navedene u njima koristeći base64 i registrirati ih u konfiguraciji, dodajući sufiks imenu ključeva -data, tj. primivši certificate-authority-data i slično.

Certifikati sa kubeadm

Sa izdanjem Kubernetes 1.15 rad sa sertifikatima je postao mnogo lakši zahvaljujući alfa verziji njegove podrške u kubeadm uslužni program. Na primjer, ovako bi sada moglo izgledati generiranje konfiguracijske datoteke s korisničkim ključevima:

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

NB: Obavezno reklamirati adresu može se naći u konfiguraciji api-servera, koja se po defaultu nalazi u /etc/kubernetes/manifests/kube-apiserver.yaml.

Rezultirajuća konfiguracija će biti izlazna na stdout. Treba ga sačuvati ~/.kube/config korisnički račun ili u datoteku specificiranu u varijabli okruženja KUBECONFIG.

Dig Deeper

Za one koji žele da razumiju detaljnije opisane probleme:

Autorizacija

Zadani ovlašteni račun nema prava za rad na klasteru. Da bi dao dozvole, Kubernetes implementira mehanizam autorizacije.

Prije verzije 1.6, Kubernetes je koristio tip autorizacije pod nazivom ABAC (Kontrola pristupa zasnovana na atributima). Detalje o tome možete pronaći u službena dokumentacija. Ovaj pristup se trenutno smatra naslijeđenim, ali ga i dalje možete koristiti zajedno s drugim tipovima provjere autentičnosti.

Trenutni (i fleksibilniji) način podjele prava pristupa klasteru se zove RBAC (Kontrola pristupa zasnovana na ulogama). Od verzije je proglašen stabilnim Kubernetes 1.8. RBAC implementira model prava u kojem je zabranjeno sve što nije izričito dozvoljeno.
Da biste omogućili RBAC, potrebno je da pokrenete Kubernetes api-server sa parametrom --authorization-mode=RBAC. Parametri se postavljaju u manifestu sa konfiguracijom api-servera, koji se po defaultu nalazi duž putanje /etc/kubernetes/manifests/kube-apiserver.yaml, u odjeljku command. Međutim, RBAC je već uključen prema zadanim postavkama, tako da najvjerovatnije ne biste trebali brinuti o tome: to možete provjeriti pomoću vrijednosti authorization-mode (u već pomenutom kube-apiserver.yaml). Usput, među njegovim značenjima mogu biti i druge vrste ovlaštenja (node, webhook, always allow), ali ćemo njihovo razmatranje ostaviti van okvira materijala.

Inače, već smo objavili članak sa prilično detaljnim opisom principa i karakteristika rada sa RBAC-om, pa ću se dalje ograničiti na kratko navođenje osnova i primera.

Sljedeći API entiteti se koriste za kontrolu pristupa u Kubernetes putem RBAC-a:

  • Role и ClusterRole — uloge koje služe za opisivanje prava pristupa:
  • Role omogućava vam da opišete prava unutar imenskog prostora;
  • ClusterRole - unutar klastera, uključujući objekte specifične za klaster kao što su čvorovi, url-ovi koji nisu resursi (tj. nisu povezani s Kubernetes resursima - na primjer, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - koristi se za vezivanje Role и ClusterRole na korisnika, korisničku grupu ili servisni račun.

Entiteti Role i RoleBinding ograničeni su prostorom imena, tj. mora biti unutar istog imenskog prostora. Međutim, RoleBinding može referencirati ClusterRole, što vam omogućava da kreirate skup generičkih dozvola i kontrolišete pristup koristeći ih.

Uloge opisuju prava koristeći skupove pravila koja sadrže:

  • API grupe - vidi službena dokumentacija po apiGrupama i izlazu kubectl api-resources;
  • resursi (sredstva: pod, namespace, deployment itd.);
  • Glagoli (glagoli: set, update i slično).
  • nazivi resursa (resourceNames) - za slučaj kada trebate omogućiti pristup određenom resursu, a ne svim resursima ove vrste.

Detaljniju analizu autorizacije u Kubernetesu možete pronaći na stranici službena dokumentacija. Umjesto toga (ili bolje rečeno, pored ovoga) navest ću primjere koji ilustruju njen rad.

Primjeri RBAC entiteta

Jednostavno Role, koji vam omogućava da dobijete listu i status podova i nadgledate ih 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 vam omogućava da dobijete listu i status podova i nadgledate ih u cijelom klasteru:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # секции "namespace" нет, так как ClusterRole задействует весь кластер
  name: secret-reader
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "watch", "list"]

Primjer: RoleBinding, što omogućava korisniku mynewuser "čitaj" 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 # имя пользователя зависимо от регистра!
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role # здесь должно быть “Role” или “ClusterRole”
  name: pod-reader # имя Role, что находится в том же namespace,
                   # или имя ClusterRole, использование которой
                   # хотим разрешить пользователю
  apiGroup: rbac.authorization.k8s.io

Revizija događaja

Šematski, Kubernetes arhitektura se može predstaviti na sljedeći način:

Abeceda sigurnosti u Kubernetesu: autentifikacija, autorizacija, revizija

Ključna Kubernetes komponenta odgovorna za obradu zahtjeva je api-server. Sve operacije na klasteru prolaze kroz njega. Više o ovim internim mehanizmima možete pročitati u članku “Šta se dešava u Kubernetesu kada pokrenete kubectl run?".

Revizija sistema je zanimljiva karakteristika u Kubernetesu, koja je podrazumevano onemogućena. Omogućava vam da evidentirate sve pozive na Kubernetes API. Kao što možete pretpostaviti, sve radnje vezane za praćenje i promjenu stanja klastera izvode se preko ovog API-ja. Dobar opis njegovih mogućnosti može se (kao i obično) naći u službena dokumentacija K8s. Zatim ću pokušati da predstavim temu jednostavnijim jezikom.

Tako da se omogući revizija, moramo prenijeti tri potrebna parametra u kontejner u api-serveru, koji su detaljnije opisani u nastavku:

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

Pored ova tri neophodna parametra, postoje mnoge dodatne postavke vezane za reviziju: od rotacije dnevnika do opisa webhooka. Primjer parametara rotacije dnevnika:

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

Ali nećemo se detaljnije zadržavati na njima - sve detalje možete pronaći u kube-apiserver dokumentacija.

Kao što je već spomenuto, svi parametri su postavljeni u manifestu sa konfiguracijom api-servera (podrazumevano /etc/kubernetes/manifests/kube-apiserver.yaml), u odjeljku command. Vratimo se na 3 potrebna parametra i analiziramo ih:

  1. audit-policy-file — putanja do YAML datoteke koja opisuje politiku revizije. Kasnije ćemo se vratiti na njegov sadržaj, ali za sada ću napomenuti da fajl mora biti čitljiv od strane procesa api-servera. Stoga ga je potrebno montirati unutar kontejnera, za šta možete dodati sljedeći kod u odgovarajuće dijelove konfiguracije:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — putanja do datoteke evidencije. Putanja također mora biti dostupna procesu api-servera, tako da opisujemo njegovo montiranje na isti 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 dnevnika revizije. Podrazumevano je json, ali je dostupan i naslijeđeni tekstualni format (legacy).

Politika revizije

Sada o pomenutom fajlu koji opisuje politiku evidentiranja. Prvi koncept politike revizije je level, nivo evidentiranja. One su sljedeće:

  • None - ne logovati;
  • Metadata — zabilježite metapodatke zahtjeva: korisnik, vrijeme zahtjeva, ciljni resurs (pod, imenski prostor, itd.), tip radnje (glagol) itd.;
  • Request — metapodatke dnevnika i tijelo zahtjeva;
  • RequestResponse — metapodatke dnevnika, tijelo zahtjeva i tijelo odgovora.

Posljednja dva nivoa (Request и RequestResponse) ne evidentirajte zahtjeve koji nisu pristupili resursima (pristupi tzv. neresursnim URL-ovima).

Također svi zahtjevi prolaze nekoliko faza:

  • RequestReceived — faza kada je zahtjev primljen od strane procesora i još nije proslijeđen dalje duž lanca procesora;
  • ResponseStarted — šalju se zaglavlja odgovora, ali prije slanja tijela odgovora. Generirano za dugotrajne upite (na primjer, watch);
  • ResponseComplete — tijelo za odgovor je poslano, više informacija neće biti poslano;
  • Panic — događaji se generiraju kada se otkrije nenormalna situacija.

Da biste preskočili sve korake koje možete koristiti omitStages.

U datoteci politike možemo opisati nekoliko sekcija sa različitim nivoima evidentiranja. Biće primijenjeno prvo podudarno pravilo pronađeno u opisu politike.

Kubelet daemon prati promjene u manifestu s konfiguracijom api-servera i, ako ih otkrije, ponovo pokreće kontejner s api-serverom. Ali postoji jedan važan detalj: promjene u datoteci politike će biti zanemarene. Nakon unošenja izmjena u datoteku politike, morat ćete ručno ponovo pokrenuti api-server. Pošto je api-server pokrenut kao static pod, tim kubectl delete neće uzrokovati ponovno pokretanje. Morat ćete to učiniti ručno docker stop na kube-masters, gdje je promijenjena politika revizije:

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

Prilikom omogućavanja revizije, važno je to zapamtiti povećava se opterećenje na kube-apiserveru. Posebno se povećava potrošnja memorije za pohranjivanje konteksta zahtjeva. Zapisivanje počinje tek nakon što se pošalje zaglavlje odgovora. Opterećenje također ovisi o konfiguraciji politike revizije.

Primjeri politika

Pogledajmo strukturu datoteka politika koristeći primjere.

Evo jednostavne datoteke policyda se sve evidentira na nivou Metadata:

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

U politici možete odrediti listu korisnika (Users и ServiceAccounts) i grupe korisnika. Na primjer, ovako ćemo zanemariti korisnike sistema, ali ćemo sve ostalo evidentirati 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 je moguće opisati ciljeve:

  • imenski prostori (namespaces);
  • Glagoli (glagoli: get, update, delete i drugi);
  • resursi (sredstva, i to: pod, configmaps itd.) i grupe resursa (apiGroups).

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

kubectl api-resources
kubectl api-versions

Sljedeća politika revizije je data kao demonstracija najboljih praksi u Alibaba Cloud dokumentacija:

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

Još jedan dobar primjer politike revizije je profil koji se koristi u GCE.

Moguće je brzo odgovoriti na događaje revizije opišite webhook. Ovo pitanje je pokriveno u službena dokumentacija, ostavit ću to izvan okvira ovog članka.

Ishodi

Članak daje pregled osnovnih sigurnosnih mehanizama u Kubernetes klasterima, koji vam omogućavaju da kreirate personalizovane korisničke naloge, odvojite njihova prava i zabeležite njihove radnje. Nadam se da će biti od koristi onima koji se susreću sa ovakvim problemima u teoriji ili praksi. Takođe preporučujem da pročitate spisak drugih materijala na temu sigurnosti u Kubernetesu, koji je dat u “PS” – možda među njima pronađete potrebne detalje o problemima koji su vam relevantni.

PS

Pročitajte i na našem blogu:

izvor: www.habr.com

Dodajte komentar