„Kubernetes“ saugumo ABC: autentifikavimas, įgaliojimas, auditas

„Kubernetes“ saugumo ABC: autentifikavimas, įgaliojimas, auditas

Anksčiau ar vėliau bet kurios sistemos veikimo metu iškyla saugumo klausimas: autentifikavimo užtikrinimas, teisių atskyrimas, auditas ir kitos užduotys. Jau sukurta Kubernetes daug sprendimų, kurios leidžia pasiekti standartų laikymąsi net ir labai reiklioje aplinkoje... Ta pati medžiaga skirta pagrindiniams saugumo aspektams, įgyvendinamiems K8s integruotuose mechanizmuose. Visų pirma, tai bus naudinga pradedantiesiems susipažinti su Kubernetes – kaip atspirties tašku nagrinėjant su saugumu susijusias problemas.

Autentifikavimas

„Kubernetes“ yra dviejų tipų vartotojai:

  • Paslaugų sąskaitos — Kubernetes API valdomos paskyros;
  • vartotojai — „paprasti“ vartotojai, valdomi išorinių, nepriklausomų paslaugų.

Pagrindinis skirtumas tarp šių tipų yra tas, kad paslaugų paskyroms Kubernetes API yra specialūs objektai (jie vadinami taip - ServiceAccounts), kurios yra susietos su vardų erdve ir prieigos duomenų rinkiniu, saugomu klasteryje paslapčių tipo objektuose. Tokie vartotojai (paslaugų abonementai) pirmiausia skirti valdyti Kubernetes klasteryje veikiančių procesų prieigos teises prie Kubernetes API.

Paprasti vartotojai neturi įrašų Kubernetes API: juos turi valdyti išoriniai mechanizmai. Jie skirti žmonėms ar procesams, gyvenantiems už klasterio ribų.

Kiekviena API užklausa susieta su paslaugos paskyra, vartotoju arba laikoma anonimiška.

Vartotojo autentifikavimo duomenys apima:

  • Vartotojo vardas — vartotojo vardas (skiriamos didžiosios ir mažosios raidės!);
  • UID - mašininiu būdu nuskaitoma vartotojo identifikavimo eilutė, kuri yra „nuoseklesnė ir unikalesnė nei vartotojo vardas“;
  • Grupės — grupių, kurioms priklauso vartotojas, sąrašas;
  • papildomai — papildomi laukai, kuriuos gali naudoti autorizacijos mechanizmas.

„Kubernetes“ gali naudoti daugybę autentifikavimo mechanizmų: X509 sertifikatus, nešiklio prieigos raktus, autentifikavimo tarpinį serverį, HTTP pagrindinį autentifikavimą. Naudodamiesi šiais mechanizmais galite įdiegti daugybę autorizacijos schemų: nuo statinio failo su slaptažodžiais iki OpenID OAuth2.

Be to, vienu metu galima naudoti kelias autorizavimo schemas. Pagal numatytuosius nustatymus klasteris naudoja:

  • paslaugų sąskaitų žetonai – paslaugų sąskaitoms;
  • X509 – vartotojams.

Klausimas apie „ServiceAccounts“ valdymą nepatenka į šio straipsnio taikymo sritį, tačiau tiems, kurie nori išsamiau susipažinti su šia problema, rekomenduoju pradėti nuo oficialiuose dokumentacijos puslapiuose. Mes atidžiau pažvelgsime į klausimą, kaip veikia X509 sertifikatai.

Sertifikatai naudotojams (X.509)

Klasikinis darbo su sertifikatais būdas apima:

  • raktų generavimas:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • sugeneruoti sertifikato užklausą:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • sertifikato užklausos apdorojimas naudojant Kubernetes klasterio CA raktus, vartotojo sertifikato gavimas (norėdami gauti sertifikatą, turite naudoti paskyrą, turinčią prieigą prie Kubernetes klasterio CA rakto, kuris pagal numatytuosius nustatymus yra /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
  • sukurti konfigūracijos failą:
    • klasterio aprašas (nurodykite konkretaus klasterio diegimo CA sertifikato failo adresą ir vietą):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • arba kaip nerekomenduojama parinktis - jums nereikia nurodyti šakninio sertifikato (tada kubectl nepatikrins klasterio api serverio teisingumo):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • pridėti vartotoją prie konfigūracijos failo:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • pridėti kontekstą:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • numatytasis konteksto priskyrimas:
      kubectl config use-context mynewuser-context

Po pirmiau minėtų manipuliacijų, faile .kube/config bus sukurta tokia konfigūracija:

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

Kad būtų lengviau perkelti konfigūraciją tarp paskyrų ir serverių, naudinga redaguoti šių raktų reikšmes:

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

Norėdami tai padaryti, galite užkoduoti juose nurodytus failus naudodami base64 ir užregistruoti juos konfigūracijoje, pridėdami priesagą prie raktų pavadinimo -data, t.y. gavęs certificate-authority-data ir tt

Sertifikatai su kubeadm

Su išleidimu Kubernetas 1.15 dirbti su sertifikatais tapo daug lengviau dėl jo palaikymo alfa versijos kubeadm įrankis. Pavyzdžiui, taip dabar gali atrodyti konfigūracijos failo su vartotojo raktais generavimas:

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

NB: Reikalingas reklamuoti adresą galima rasti api-serverio konfigūracijoje, kuri pagal numatytuosius nustatymus yra /etc/kubernetes/manifests/kube-apiserver.yaml.

Gauta konfigūracija bus išvesta į stdout. Jį reikia išsaugoti ~/.kube/config vartotojo abonementą arba failą, nurodytą aplinkos kintamajame KUBECONFIG.

Įsigilinkite

Tiems, kurie nori išsamiau suprasti aprašytas problemas:

Leidimas

Numatytoji įgaliotoji paskyra neturi teisių veikti klasteryje. Kad suteiktų leidimus, Kubernetes įdiegia autorizacijos mechanizmą.

Iki 1.6 versijos Kubernetes naudojo prieigos tipą, vadinamą ABAC (Prieigos valdymas atributais). Išsamią informaciją apie tai galite rasti oficialius dokumentus. Šis metodas šiuo metu laikomas pasenusiu, tačiau vis tiek galite jį naudoti kartu su kitais autentifikavimo tipais.

Dabartinis (ir lankstesnis) prieigos teisių į klasterį padalijimo būdas vadinamas RBAC (Vaidmenimis pagrįsta prieigos kontrolė). Jis paskelbtas stabiliu nuo versijos Kubernetas 1.8. RBAC įgyvendina teisių modelį, kuriame viskas, kas nėra aiškiai leidžiama, yra draudžiama.
Norėdami įjungti RBAC, turite paleisti Kubernetes api-server su parametru --authorization-mode=RBAC. Parametrai apraše nustatomi naudojant api serverio konfigūraciją, kuri pagal numatytuosius nustatymus yra kelyje /etc/kubernetes/manifests/kube-apiserver.yaml, skyriuje command. Tačiau RBAC jau įjungtas pagal numatytuosius nustatymus, todėl greičiausiai neturėtumėte dėl to jaudintis: galite tai patikrinti pagal vertę authorization-mode (jau minėtame kube-apiserver.yaml). Beje, tarp jo reikšmių gali būti ir kitų tipų įgaliojimų (node, webhook, always allow), tačiau jų svarstymą paliksime už medžiagos taikymo srities.

Beje, mes jau paskelbėme straipsnis su gana išsamiu darbo su RBAC principų ir ypatybių aprašymu, todėl toliau apsiribosiu trumpu pagrindų ir pavyzdžių sąrašu.

Šie API objektai naudojami prieigai Kubernetes valdyti per RBAC:

  • Role и ClusterRole — vaidmenys, kuriais apibūdinamos prieigos teisės:
  • Role leidžia apibūdinti teises vardų erdvėje;
  • ClusterRole – klasteryje, įskaitant konkrečiam klasteriui būdingus objektus, tokius kaip mazgai, ne išteklių URL (t. y. nesusiję su Kubernetes ištekliais, pvz., /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - naudojamas įrišimui Role и ClusterRole vartotojui, vartotojų grupei arba ServiceAccount.

Role ir RoleBinding subjektai yra ribojami vardų erdvės, t.y. turi būti toje pačioje vardų erdvėje. Tačiau RoleBinding gali nurodyti ClusterRole, kuris leidžia sukurti bendrųjų leidimų rinkinį ir valdyti prieigą naudojant juos.

Vaidmenys apibūdina teises naudojant taisyklių rinkinius, kuriuose yra:

  • API grupės – žr oficialius dokumentus pagal apiGroups ir išvestį kubectl api-resources;
  • ištekliai (ištekliai: pod, namespace, deployment ir taip toliau.);
  • Veiksmažodžiai (veiksmažodžiai: set, update ir pan.).
  • išteklių pavadinimai (resourceNames) - tuo atveju, kai reikia suteikti prieigą prie konkretaus šaltinio, o ne prie visų tokio tipo išteklių.

Išsamesnę Kubernetes autorizavimo analizę galite rasti puslapyje oficialius dokumentus. Vietoj to (tiksliau, be to), pateiksiu pavyzdžių, iliustruojančių jos darbą.

RBAC objektų pavyzdžiai

Paprasta Role, kuri leidžia gauti ankščių sąrašą ir būseną bei stebėti juos vardų erdvėje 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"]

Pavyzdys ClusterRole, kuri leidžia gauti ankščių sąrašą ir būseną bei stebėti juos visame klasteryje:

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

Pavyzdys RoleBinding, kuri leidžia vartotojui mynewuser „skaityti“ ankštis vardų erdvėje 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

Renginio auditas

Schematiškai Kubernetes architektūra gali būti pavaizduota taip:

„Kubernetes“ saugumo ABC: autentifikavimas, įgaliojimas, auditas

Pagrindinis Kubernetes komponentas, atsakingas už užklausų apdorojimą, yra api serveris. Per jį atliekamos visos klasterio operacijos. Daugiau apie šiuos vidinius mechanizmus galite perskaityti straipsnyje “Kas nutinka Kubernetes, kai paleidžiate kubectl run?".

Sistemos auditas yra įdomi „Kubernetes“ funkcija, kuri pagal numatytuosius nustatymus yra išjungta. Tai leidžia registruoti visus Kubernetes API skambučius. Kaip jau galima spėti, visi veiksmai, susiję su klasterio būsenos stebėjimu ir keitimu, atliekami per šią API. Gerą jo galimybių aprašymą (kaip įprasta) galite rasti oficialius dokumentus K8s. Toliau pabandysiu temą pateikti paprastesne kalba.

tokiu būdu, kad būtų galima atlikti auditą, turime perduoti tris būtinus parametrus į konteinerį api-serveryje, kurie išsamiau aprašyti toliau:

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

Be šių trijų būtinų parametrų, yra daug papildomų nustatymų, susijusių su auditu: nuo žurnalo pasukimo iki webhook aprašymų. Žurnalo sukimosi parametrų pavyzdys:

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

Tačiau plačiau apie juos nesigilinsime – visą informaciją rasite čia kube-apiserver dokumentacija.

Kaip jau minėta, visi parametrai apraše nustatomi naudojant api serverio konfigūraciją (pagal numatytuosius nustatymus /etc/kubernetes/manifests/kube-apiserver.yaml), skyriuje command. Grįžkime prie 3 būtinų parametrų ir išanalizuokime juos:

  1. audit-policy-file — kelias į YAML failą, kuriame aprašoma audito politika. Prie jo turinio grįšime vėliau, tačiau kol kas pažymėsiu, kad failą turi nuskaityti api serverio procesas. Todėl būtina jį sumontuoti konteinerio viduje, kuriam galite pridėti šį kodą į atitinkamas konfigūracijos dalis:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path - kelias į žurnalo failą. Kelias taip pat turi būti pasiekiamas api serverio procesui, todėl jo montavimą aprašome taip pat:
      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 — audito žurnalo formatas. Numatytasis yra json, bet galimas ir pasenęs teksto formatas (legacy).

Audito politika

Dabar apie minėtą failą, aprašantį registravimo politiką. Pirmoji audito politikos samprata yra level, registravimo lygis. Jie yra tokie:

  • None - neprisijungti;
  • Metadata — žurnalo užklausos metaduomenys: vartotojas, užklausos laikas, tikslinis išteklius (pod, vardų erdvė ir kt.), veiksmo tipas (veiksmažodis) ir kt.;
  • Request — žurnalo metaduomenys ir užklausos turinys;
  • RequestResponse — žurnalo metaduomenys, užklausos turinys ir atsakymo turinys.

Paskutiniai du lygiai (Request и RequestResponse) neregistruokite užklausų, kurios nepasiekė išteklių (prieiga prie vadinamųjų ne išteklių URL).

Taip pat visi prašymai yra vykdomi keli etapai:

  • RequestReceived — etapas, kai užklausą gauna duomenų tvarkytojas ir ji dar nebuvo perduota toliau procesorių grandinėje;
  • ResponseStarted — siunčiamos atsakymo antraštės, bet prieš siunčiant atsakymo turinį. Sukurta ilgai vykdomoms užklausoms (pvz., watch);
  • ResponseComplete — atsakymo institucija išsiųsta, daugiau informacijos nebus siunčiama;
  • Panic — įvykiai generuojami, kai aptinkama neįprasta situacija.

Jei norite praleisti bet kokius veiksmus, kuriuos galite naudoti omitStages.

Politikos faile galime aprašyti keletą skyrių su skirtingais registravimo lygiais. Bus pritaikyta pirmoji politikos apraše rasta atitikties taisyklė.

Kubelet demonas stebi manifesto pakeitimus naudodamas api serverio konfigūraciją ir, jei tokių aptinkama, iš naujo paleidžia konteinerį su api serveriu. Tačiau yra svarbi detalė: Tai nepaisys politikos failo pakeitimų. Atlikę politikos failo pakeitimus, turėsite rankiniu būdu iš naujo paleisti api serverį. Kadangi api serveris paleistas kaip statinis ankštis, komanda kubectl delete neprivers jo paleisti iš naujo. Turėsite tai padaryti rankiniu būdu docker stop kube-masters, kur buvo pakeista audito politika:

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

Įgalinant auditą, svarbu tai atsiminti kube-apiserver apkrova didėja. Visų pirma didėja atminties sąnaudos užklausos kontekstui saugoti. Registravimas pradedamas tik išsiuntus atsakymo antraštę. Apkrova taip pat priklauso nuo audito politikos konfigūracijos.

Politikos pavyzdžiai

Pažvelkime į politikos failų struktūrą naudodami pavyzdžius.

Čia yra paprastas failas policyregistruoti viską lygiu Metadata:

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

Politikoje galite nurodyti vartotojų sąrašą (Users и ServiceAccounts) ir vartotojų grupės. Pavyzdžiui, taip ignoruosime sistemos vartotojus, o visa kita registruosime lygiu 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

Taip pat galima apibūdinti tikslus:

  • vardų erdvės (namespaces);
  • Veiksmažodžiai (veiksmažodžiai: get, update, delete ir kiti);
  • ištekliai (ištekliai, Išvardyta toliau: pod, configmaps ir tt) ir išteklių grupės (apiGroups).

Pastaba! Išteklius ir išteklių grupes (API grupes, t. y. apiGroups), taip pat jų versijas, įdiegtas klasteryje, galima gauti naudojant komandas:

kubectl api-resources
kubectl api-versions

Ši audito politika pateikiama kaip geriausios praktikos pavyzdys „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

Kitas geras audito politikos pavyzdys yra GCE naudojamas profilis.

Greitai reaguoti į audito įvykius galima apibūdinti webhook. Šis klausimas aptariamas oficialius dokumentus, paliksiu tai už šio straipsnio ribų.

rezultatai

Straipsnyje apžvelgiami pagrindiniai Kubernetes klasterių saugos mechanizmai, leidžiantys kurti personalizuotas vartotojų paskyras, atskirti jų teises ir fiksuoti jų veiksmus. Tikiuosi, kad tai bus naudinga tiems, kurie teoriškai ar praktiškai susiduria su tokiomis problemomis. Taip pat rekomenduoju perskaityti kitos medžiagos „Kubernetes“ saugumo tema sąrašą, pateiktą „PS“ - galbūt tarp jų rasite reikiamos informacijos apie jums aktualias problemas.

PS

Taip pat skaitykite mūsų tinklaraštyje:

Šaltinis: www.habr.com

Добавить комментарий