ABC varnosti v Kubernetesu: avtentikacija, avtorizacija, revizija

ABC varnosti v Kubernetesu: avtentikacija, avtorizacija, revizija

Prej ali slej se pri delovanju vsakega sistema pojavi vprašanje varnosti: zagotavljanje avtentikacije, ločevanje pravic, revizija in druge naloge. Že ustvarjeno za Kubernetes veliko rešitev, ki vam omogočajo doseganje skladnosti s standardi tudi v zelo zahtevnih okoljih... Enako gradivo je posvečeno osnovnim vidikom varnosti, implementiranim v okviru vgrajenih mehanizmov K8s. Najprej bo koristno tistim, ki se začenjajo seznanjati s Kubernetesom - kot izhodišče za preučevanje vprašanj, povezanih z varnostjo.

Preverjanje pristnosti

V Kubernetesu obstajata dve vrsti uporabnikov:

  • Računi storitev — računi, ki jih upravlja Kubernetes API;
  • uporabniki — »normalni« uporabniki, ki jih upravljajo zunanje, neodvisne storitve.

Glavna razlika med temi vrstami je, da za storitvene račune obstajajo posebni objekti v Kubernetes API (imenujejo se tako - ServiceAccounts), ki so vezani na imenski prostor in nabor avtorizacijskih podatkov, shranjenih v gruči v objektih tipa Secrets. Takšni uporabniki (Service Accounts) so v prvi vrsti namenjeni upravljanju pravic dostopa do API-ja Kubernetes za procese, ki se izvajajo v gruči Kubernetes.

Navadni uporabniki nimajo vnosov v Kubernetes API: upravljati jih morajo zunanji mehanizmi. Namenjeni so ljudem ali procesom, ki živijo izven grozda.

Vsaka zahteva API je povezana z računom storitve, uporabnikom ali pa se šteje za anonimno.

Podatki za preverjanje pristnosti uporabnikov vključujejo:

  • Uporabniško ime — uporabniško ime (razlikuje med velikimi in malimi črkami!);
  • UID - strojno berljiv identifikacijski niz uporabnika, ki je "bolj dosleden in edinstven kot uporabniško ime";
  • skupine — seznam skupin, ki jim uporabnik pripada;
  • extra — dodatna polja, ki jih lahko uporabi avtorizacijski mehanizem.

Kubernetes lahko uporablja veliko število mehanizmov za preverjanje pristnosti: potrdila X509, nosilne žetone, proxy za preverjanje pristnosti, osnovno preverjanje pristnosti HTTP. Z uporabo teh mehanizmov lahko implementirate veliko število avtorizacijskih shem: od statične datoteke z gesli do OpenID OAuth2.

Poleg tega je možno uporabljati več avtorizacijskih shem hkrati. Privzeto gruča uporablja:

  • žetoni storitvenih računov - za storitvene račune;
  • X509 - za uporabnike.

Vprašanje o upravljanju ServiceAccounts presega obseg tega članka, vendar za tiste, ki se želijo podrobneje seznaniti s tem vprašanjem, priporočam, da začnete z uradne strani z dokumentacijo. Podrobneje si bomo ogledali vprašanje delovanja certifikatov X509.

Potrdila za uporabnike (X.509)

Klasičen način dela s certifikati vključuje:

  • generacija ključev:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • generiranje zahteve za potrdilo:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • obdelava zahteve za potrdilo z uporabo ključev CA gruče Kubernetes, pridobitev uporabniškega certifikata (za pridobitev potrdila morate uporabiti račun, ki ima dostop do ključa CA gruče Kubernetes, ki se privzeto nahaja 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 gruče (podajte naslov in lokacijo datoteke potrdila CA za določeno namestitev gruče):
      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 - ni vam treba določiti korenskega potrdila (takrat kubectl ne bo preverjal pravilnosti api-strežnika gruče):
      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
    • privzeta dodelitev konteksta:
      kubectl config use-context mynewuser-context

Po zgornjih manipulacijah v datoteki .kube/config ustvarjena bo takšna 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

Za lažji prenos konfiguracije med računi in strežniki je koristno urediti vrednosti naslednjih ključev:

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

Če želite to narediti, lahko datoteke, navedene v njih, kodirate z uporabo base64 in jih registrirate v konfiguraciji ter imenu ključev dodate pripono -data, tj. ob prejemu certificate-authority-data itd

Certifikati s kubeadm

S sprostitvijo Kubernetes 1.15 delo s certifikati je zaradi alfa različice podpore v pripomoček kubeadm. Na primer, takole bi lahko izgledalo ustvarjanje konfiguracijske datoteke z uporabniškimi ključi:

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

NB: obvezno naslov za oglaševanje lahko najdete v konfiguraciji strežnika api, ki se privzeto nahaja v /etc/kubernetes/manifests/kube-apiserver.yaml.

Nastala konfiguracija bo izhodna v stdout. Treba ga je shraniti v ~/.kube/config uporabniški račun ali v datoteko, določeno v spremenljivki okolja KUBECONFIG.

Koplji globje

Za tiste, ki želijo podrobneje razumeti opisano problematiko:

Dovoljenje

Privzeti pooblaščeni račun nima pravic za delovanje v gruči. Za dodelitev dovoljenj Kubernetes implementira avtorizacijski mehanizem.

Pred različico 1.6 je Kubernetes uporabljal vrsto avtorizacije, imenovano ABAC (Nadzor dostopa na podlagi atributov). Podrobnosti o tem najdete v uradna dokumentacija. Ta pristop trenutno velja za podedovanega, vendar ga lahko še vedno uporabljate poleg drugih vrst preverjanja pristnosti.

Sedanji (in bolj prilagodljiv) način delitve pravic dostopa do gruče se imenuje RBAC (Nadzor dostopa na podlagi vlog). Od različice naprej je bil razglašen za stabilen Kubernetes 1.8. RBAC izvaja model pravic, v katerem je vse, kar ni izrecno dovoljeno, prepovedano.
Če želite omogočiti RBAC, morate zagnati Kubernetes api-strežnik s parametrom --authorization-mode=RBAC. Parametri so nastavljeni v manifestu s konfiguracijo strežnika api, ki se privzeto nahaja vzdolž poti /etc/kubernetes/manifests/kube-apiserver.yaml, v razdelku command. Vendar je RBAC že privzeto omogočen, zato najverjetneje ne bi smeli skrbeti: to lahko preverite z vrednostjo authorization-mode (v že omenjenem kube-apiserver.yaml). Mimogrede, med njegovimi pomeni so lahko druge vrste pooblastil (node, webhook, always allow), vendar bomo njihovo obravnavo pustili izven obsega gradiva.

Mimogrede, smo že objavili статью z dokaj podrobnim opisom načel in značilnosti dela z RBAC, zato se bom v nadaljevanju omejil na kratek seznam osnov in primerov.

Za nadzor dostopa v Kubernetesu prek RBAC se uporabljajo naslednje entitete API-ja:

  • Role и ClusterRole — vloge, ki služijo za opis pravic dostopa:
  • Role vam omogoča, da opišete pravice znotraj imenskega prostora;
  • ClusterRole - znotraj gruče, vključno s predmeti, specifičnimi za gručo, kot so vozlišča, URL-ji, ki niso viri (tj. niso povezani z viri Kubernetes - na primer, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - uporablja se za vezavo Role и ClusterRole uporabniku, uporabniški skupini ali ServiceAccountu.

Entiteti Role in RoleBinding sta omejeni z imenskim prostorom, tj. mora biti znotraj istega imenskega prostora. Vendar pa se RoleBinding lahko sklicuje na ClusterRole, kar vam omogoča, da ustvarite niz generičnih dovoljenj in nadzorujete dostop z njihovo uporabo.

Vloge opisujejo pravice z uporabo nizov pravil, ki vsebujejo:

  • API skupine - glej uradna dokumentacija z apiGroups in izhod kubectl api-resources;
  • viri (sredstva: pod, namespace, deployment in tako naprej.);
  • Glagoli (glagoli: set, update itd.).
  • imena virov (resourceNames) - za primer, ko morate zagotoviti dostop do določenega vira in ne do vseh virov te vrste.

Podrobnejšo analizo avtorizacije v Kubernetesu najdete na strani uradna dokumentacija. Namesto tega (oziroma poleg tega) bom navedel primere, ki ponazarjajo njeno delo.

Primeri entitet RBAC

Preprosto Role, ki vam omogoča, da dobite seznam in status podov ter jih spremljate 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, ki vam omogoča, da dobite seznam in stanje sklopov ter jih spremljate v celotni gruči:

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

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

Revizija dogodkov

Shematično lahko arhitekturo Kubernetes predstavimo na naslednji način:

ABC varnosti v Kubernetesu: avtentikacija, avtorizacija, revizija

Ključna komponenta Kubernetes, odgovorna za obdelavo zahtev, je api-strežnik. Skozi njega potekajo vse operacije v gruči. Več o teh notranjih mehanizmih si lahko preberete v članku “Kaj se zgodi v Kubernetesu, ko zaženete kubectl run?".

Revizija sistema je zanimiva funkcija v Kubernetesu, ki je privzeto onemogočena. Omogoča vam beleženje vseh klicev v Kubernetes API. Kot morda ugibate, se vsa dejanja, povezana s spremljanjem in spreminjanjem stanja gruče, izvajajo prek tega API-ja. Dober opis njegovih zmogljivosti lahko (kot običajno) najdete v uradna dokumentacija K8s. V nadaljevanju bom poskušal predstaviti temo v preprostejšem jeziku.

Torej, omogočiti revizijo, moramo vsebniku v api-strežniku posredovati tri zahtevane parametre, ki so podrobneje opisani 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 potrebnih parametrov obstaja veliko dodatnih nastavitev, povezanih z nadzorom: od rotacije dnevnika do opisov webhook. Primer parametrov rotacije dnevnika:

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

Vendar se o njih ne bomo podrobneje ukvarjali - vse podrobnosti najdete v dokumentacija kube-apiserver.

Kot že omenjeno, so vsi parametri nastavljeni v manifestu s konfiguracijo strežnika api (privzeto /etc/kubernetes/manifests/kube-apiserver.yaml), v razdelku command. Vrnimo se k 3 zahtevanim parametrom in jih analiziramo:

  1. audit-policy-file — pot do datoteke YAML, ki opisuje politiko revizije. K njeni vsebini se bomo vrnili kasneje, vendar bom za zdaj opozoril, da mora biti datoteka berljiva s procesom strežnika api. Zato ga je potrebno namestiti znotraj vsebnika, za kar lahko v ustrezne razdelke konfiguracije dodate naslednjo kodo:
      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 dnevnika. Pot mora biti dostopna tudi procesu api-strežnika, zato njeno namestitev opišemo na enak 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 — oblika revizijskega dnevnika. Privzeto je json, vendar je na voljo tudi stari format besedila (legacy).

Politika revizije

Zdaj o omenjeni datoteki, ki opisuje politiko beleženja. Prvi koncept revizijske politike je level, raven beleženja. So naslednji:

  • None - ne prijavljaj se;
  • Metadata — metapodatki zahteve za dnevnik: uporabnik, čas zahteve, ciljni vir (pod, imenski prostor itd.), vrsta dejanja (glagol) itd.;
  • Request — metapodatki dnevnika in telo zahteve;
  • RequestResponse — metapodatki dnevnika, telo zahteve in telo odgovora.

Zadnji dve ravni (Request и RequestResponse) ne beležite zahtev, ki niso dostopale do virov (dostopi do tako imenovanih URL-jev brez virov).

Tudi vse zahteve gredo skozi več stopenj:

  • RequestReceived — stopnja, ko obdelovalec prejme zahtevo in še ni bila posredovana naprej po verigi obdelovalcev;
  • ResponseStarted — glave odgovora so poslane, vendar pred pošiljanjem telesa odgovora. Ustvarjeno za dolgotrajne poizvedbe (npr. watch);
  • ResponseComplete — odgovorni organ je bil poslan, več informacij ne bo poslano;
  • Panic — dogodki se ustvarijo, ko se odkrije neobičajna situacija.

Če želite preskočiti vse korake, ki jih lahko uporabite omitStages.

V datoteki pravilnika lahko opišemo več razdelkov z različnimi nivoji beleženja. Uporabljeno bo prvo ujemajoče se pravilo, najdeno v opisu pravilnika.

Demon kubelet spremlja spremembe v manifestu s konfiguracijo strežnika api in, če jih zazna, znova zažene vsebnik s strežnikom api. Vendar obstaja pomembna podrobnost: spremembe v datoteki pravilnika bodo prezrte. Ko spremenite datoteko pravilnika, boste morali ročno znova zagnati strežnik api. Ker se api-strežnik zažene kot statični pod, ekipa kubectl delete ne bo povzročil ponovnega zagona. To boste morali narediti ročno docker stop na kube-masters, kjer je bila spremenjena revizijska politika:

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

Ko omogočate revizijo, si je pomembno zapomniti to obremenitev kube-apiserverja se poveča. Zlasti se poveča poraba pomnilnika za shranjevanje konteksta zahteve. Beleženje se začne šele, ko je poslana glava odgovora. Obremenitev je odvisna tudi od konfiguracije pravilnika revizije.

Primeri politik

Oglejmo si strukturo datotek pravilnika na primerih.

Tukaj je preprosta datoteka policyda se vse zabeleži na ravni Metadata:

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

V pravilniku lahko določite seznam uporabnikov (Users и ServiceAccounts) in uporabniške skupine. Na primer, tako bomo ignorirali sistemske uporabnike, vse ostalo pa beležili na ravni 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

Cilje je mogoče opisati tudi:

  • imenski prostori (namespaces);
  • Glagoli (glagoli: get, update, delete in drugi);
  • viri (sredstva, in sicer: pod, configmaps itd.) in skupine virov (apiGroups).

Bodite pozorni! Vire in skupine virov (API skupine, t.i. apiGroups) ter njihove različice, nameščene v gruči, lahko pridobite z ukazi:

kubectl api-resources
kubectl api-versions

Naslednja revizijska politika je podana kot predstavitev najboljših praks v Dokumentacija 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

Drug dober primer revizijske politike je profil, uporabljen v GCE.

Za hiter odziv na revizijske dogodke je to mogoče opišite webhook. To vprašanje je zajeto v uradna dokumentacija, ga bom pustil zunaj obsega tega članka.

Rezultati

Članek ponuja pregled osnovnih varnostnih mehanizmov v gručah Kubernetes, ki vam omogočajo ustvarjanje personaliziranih uporabniških računov, ločevanje njihovih pravic in beleženje njihovih dejanj. Upam, da bo koristilo tistim, ki se v teoriji ali praksi srečujejo s tovrstnimi težavami. Priporočam tudi, da preberete seznam drugih gradiv na temo varnosti v Kubernetesu, ki je naveden v "PS" - morda boste med njimi našli potrebne podrobnosti o težavah, ki so pomembne za vas.

PS

Preberite tudi na našem blogu:

Vir: www.habr.com

Dodaj komentar