ABC-ul securității în Kubernetes: autentificare, autorizare, auditare

ABC-ul securității în Kubernetes: autentificare, autorizare, auditare

Mai devreme sau mai târziu, în funcționarea oricărui sistem, se pune problema securității: asigurarea autentificării, separarea drepturilor, auditarea și alte sarcini. Deja creat pentru Kubernetes multe solutii, care vă permit să atingeți conformitatea cu standardele chiar și în medii foarte solicitante... Același material este dedicat aspectelor de bază ale securității implementate în cadrul mecanismelor încorporate ale K8-urilor. În primul rând, va fi util celor care încep să se familiarizeze cu Kubernetes - ca punct de plecare pentru studierea problemelor legate de securitate.

autentificare

Există două tipuri de utilizatori în Kubernetes:

  • Conturi de servicii — conturi gestionate de API-ul Kubernetes;
  • Utilizatori — utilizatori „normali” gestionați de servicii externe, independente.

Principala diferență dintre aceste tipuri este că pentru Conturile de serviciu există obiecte speciale în API-ul Kubernetes (se numesc așa - ServiceAccounts), care sunt legate de un spațiu de nume și un set de date de autorizare stocate în cluster în obiecte de tip Secrets. Astfel de utilizatori (Conturi de servicii) sunt destinate în primul rând să gestioneze drepturile de acces la API-ul Kubernetes al proceselor care rulează în clusterul Kubernetes.

Utilizatorii obișnuiți nu au intrări în API-ul Kubernetes: trebuie gestionați prin mecanisme externe. Sunt destinate persoanelor sau proceselor care trăiesc în afara clusterului.

Fiecare solicitare API este asociată fie unui cont de serviciu, fie unui utilizator, fie este considerată anonimă.

Datele de autentificare a utilizatorului includ:

  • Nume de utilizator — nume de utilizator (se face distincția între majuscule și minuscule!);
  • UID - un șir de identificare a utilizatorului care poate fi citit de mașină, care este „mai consecvent și unic decât numele de utilizator”;
  • grupuri — lista grupurilor din care face parte utilizatorul;
  • în plus — câmpuri suplimentare care pot fi utilizate de mecanismul de autorizare.

Kubernetes poate folosi un număr mare de mecanisme de autentificare: certificate X509, jetoane Bearer, proxy de autentificare, HTTP Basic Auth. Folosind aceste mecanisme, puteți implementa un număr mare de scheme de autorizare: de la un fișier static cu parole la OpenID OAuth2.

Mai mult, este posibilă utilizarea simultană a mai multor scheme de autorizare. În mod implicit, clusterul utilizează:

  • jetoane de cont de serviciu - pentru Conturile de serviciu;
  • X509 - pentru utilizatori.

Întrebarea despre gestionarea ServiceAccounts depășește sfera acestui articol, dar pentru cei care doresc să se familiarizeze mai detaliat cu această problemă, recomand să înceapă cu paginile de documentație oficială. Vom arunca o privire mai atentă asupra modului în care funcționează certificatele X509.

Certificate pentru utilizatori (X.509)

Modul clasic de lucru cu certificate presupune:

  • generare cheie:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • generarea unei cereri de certificat:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • procesarea unei cereri de certificat folosind cheile CA cluster Kubernetes, obținerea unui certificat de utilizator (pentru a obține un certificat, trebuie să utilizați un cont care are acces la cheia CA cluster Kubernetes, care se află în mod implicit în /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
  • crearea unui fișier de configurare:
    • descrierea clusterului (specificați adresa și locația fișierului de certificat CA pentru o anumită instalare a clusterului):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • sau cum nuopțiune recomandată - nu trebuie să specificați certificatul rădăcină (atunci kubectl nu va verifica corectitudinea serverului api al clusterului):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • adăugarea unui utilizator la fișierul de configurare:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • adăugarea contextului:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • atribuirea implicită a contextului:
      kubectl config use-context mynewuser-context

După manipulările de mai sus, în dosar .kube/config se va crea o configurație ca aceasta:

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

Pentru a facilita transferul configurației între conturi și servere, este util să editați valorile următoarelor chei:

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

Pentru a face acest lucru, puteți codifica fișierele specificate în ele folosind base64 și le puteți înregistra în config, adăugând sufixul la numele cheilor -data, adică primind certificate-authority-data etc

Certificate cu kubeadm

Odată cu eliberarea Kubernetes 1.15 lucrul cu certificate a devenit mult mai ușor datorită versiunii alfa a suportului său în utilitarul kubeadm. De exemplu, așa ar putea arăta acum generarea unui fișier de configurare cu chei de utilizator:

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

NB: Necesar adresa de publicitate poate fi găsit în configurația api-server, care se află implicit în /etc/kubernetes/manifests/kube-apiserver.yaml.

Configurația rezultată va fi trimisă la stdout. Trebuie salvat în ~/.kube/config cont de utilizator sau la un fișier specificat într-o variabilă de mediu KUBECONFIG.

Sapă mai adânc

Pentru cei care doresc să înțeleagă problemele descrise mai detaliat:

autorizare

Contul autorizat implicit nu are drepturi de a opera pe cluster. Pentru a acorda permisiuni, Kubernetes implementează un mecanism de autorizare.

Înainte de versiunea 1.6, Kubernetes folosea un tip de autorizare numit ABAC (Controlul accesului bazat pe atribute). Detalii despre acesta pot fi găsite în documentație oficială. Această abordare este considerată în prezent moștenire, dar o puteți utiliza în continuare alături de alte tipuri de autentificare.

Se numește modul actual (și mai flexibil) de împărțire a drepturilor de acces la un cluster RBAC (Controlul accesului bazat pe roluri). A fost declarat stabil de la versiune Kubernetes 1.8. RBAC implementează un model de drepturi în care tot ceea ce nu este permis în mod explicit este interzis.
Pentru a activa RBAC, trebuie să porniți serverul api Kubernetes cu parametrul --authorization-mode=RBAC. Parametrii sunt setați în manifest cu configurația api-server, care în mod implicit se află de-a lungul căii /etc/kubernetes/manifests/kube-apiserver.yaml, in sectiune command. Cu toate acestea, RBAC este deja activat în mod implicit, așa că cel mai probabil nu ar trebui să vă faceți griji: puteți verifica acest lucru după valoarea authorization-mode (în cele deja menționate kube-apiserver.yaml). Apropo, printre semnificațiile sale pot exista și alte tipuri de autorizare (node, webhook, always allow), dar vom lăsa considerația lor în afara domeniului materialului.

Apropo, am publicat deja статью cu o descriere destul de detaliată a principiilor și caracteristicilor de lucru cu RBAC, așa că în continuare mă voi limita la o scurtă listă a elementelor de bază și a exemplelor.

Următoarele entități API sunt utilizate pentru a controla accesul în Kubernetes prin RBAC:

  • Role и ClusterRole — roluri care servesc pentru a descrie drepturile de acces:
  • Role vă permite să descrieți drepturile într-un spațiu de nume;
  • ClusterRole - în cadrul clusterului, inclusiv la obiecte specifice cluster-ului, cum ar fi noduri, URL-uri non-resurse (adică nu sunt legate de resurse Kubernetes - de exemplu, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - folosit pentru legare Role и ClusterRole către un utilizator, un grup de utilizatori sau un ServiceAccount.

Entitățile Role și RoleBinding sunt limitate de spațiu de nume, de exemplu. trebuie să fie în același spațiu de nume. Cu toate acestea, un RoleBinding poate face referire la un ClusterRole, ceea ce vă permite să creați un set de permisiuni generice și să controlați accesul folosindu-le.

Rolurile descriu drepturile folosind seturi de reguli care conțin:

  • Grupuri API - vezi documentație oficială de apiGroups și de ieșire kubectl api-resources;
  • resurse (resurse: pod, namespace, deployment și așa mai departe.);
  • Verbe (verbe: set, update etc).
  • nume de resurse (resourceNames) - pentru cazul în care trebuie să oferiți acces la o anumită resursă și nu la toate resursele de acest tip.

O analiză mai detaliată a autorizării în Kubernetes poate fi găsită pe pagină documentație oficială. În schimb (sau mai bine zis, pe lângă aceasta), voi da exemple care ilustrează munca ei.

Exemple de entități RBAC

simplu Role, care vă permite să obțineți o listă și starea podurilor și să le monitorizați în spațiul de nume 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"]

Exemplu ClusterRole, care vă permite să obțineți o listă și starea podurilor și să le monitorizați în întregul cluster:

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

Exemplu RoleBinding, care permite utilizatorului mynewuser „citește” pod-uri în spațiul de nume 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

Auditul evenimentului

Schematic, arhitectura Kubernetes poate fi reprezentată după cum urmează:

ABC-ul securității în Kubernetes: autentificare, autorizare, auditare

Componenta cheie Kubernetes responsabilă de procesarea cererilor este api-server. Toate operațiunile de pe cluster trec prin el. Puteți citi mai multe despre aceste mecanisme interne în articolul „Ce se întâmplă în Kubernetes când rulați kubectl run?".

Auditul sistemului este o caracteristică interesantă în Kubernetes, care este dezactivată implicit. Vă permite să înregistrați toate apelurile în API-ul Kubernetes. După cum ați putea ghici, toate acțiunile legate de monitorizarea și modificarea stării clusterului sunt efectuate prin acest API. O descriere bună a capabilităților sale poate fi găsită (ca de obicei) în documentație oficială K8s. În continuare, voi încerca să prezint subiectul într-un limbaj mai simplu.

Astfel, pentru a permite auditul, trebuie să transmitem trei parametri necesari containerului din api-server, care sunt descriși mai detaliat mai jos:

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

Pe lângă acești trei parametri necesari, există multe setări suplimentare legate de auditare: de la rotația jurnalului până la descrierile webhook. Exemplu de parametri de rotație a jurnalului:

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

Dar nu ne vom opri asupra lor în detaliu - puteți găsi toate detaliile în documentația kube-apserver.

După cum sa menționat deja, toți parametrii sunt setați în manifest cu configurația api-server (în mod implicit /etc/kubernetes/manifests/kube-apiserver.yaml), in sectiune command. Să revenim la cei 3 parametri necesari și să-i analizăm:

  1. audit-policy-file — calea către fișierul YAML care descrie politica de audit. Vom reveni la conținutul său mai târziu, dar deocamdată voi reține că fișierul trebuie să fie citit de procesul api-server. Prin urmare, este necesar să-l montați în interiorul containerului, pentru care puteți adăuga următorul cod la secțiunile corespunzătoare ale configurației:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — calea către fișierul jurnal. Calea trebuie să fie accesibilă și procesului api-server, așa că descriem montarea ei în același mod:
      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 — formatul jurnalului de audit. Valoarea implicită este json, dar este disponibil și formatul de text vechi (legacy).

Politica de audit

Acum despre fișierul menționat care descrie politica de înregistrare. Primul concept al politicii de audit este level, nivelul de înregistrare. Acestea sunt după cum urmează:

  • None - nu vă logați;
  • Metadata — metadatele cererii de jurnal: utilizator, timpul solicitării, resursa țintă (pod, spațiu de nume etc.), tip de acțiune (verb), etc.;
  • Request — metadatele jurnalului și corpul cererii;
  • RequestResponse — metadatele jurnalului, corpul cererii și corpul răspunsului.

Ultimele două niveluri (Request и RequestResponse) nu înregistrați cererile care nu au accesat resurse (accesuri la așa-numitele URL-uri non-resources).

De asemenea, toate cererile trec mai multe etape:

  • RequestReceived — etapa în care cererea este primită de către procesator și nu a fost încă transmisă mai departe de-a lungul lanțului de procesatori;
  • ResponseStarted — sunt trimise antetele răspunsului, dar înainte ca corpul răspunsului să fie trimis. Generat pentru interogări de lungă durată (de exemplu, watch);
  • ResponseComplete — corpul de răspuns a fost trimis, nu se vor mai trimite informații;
  • Panic — evenimentele sunt generate atunci când este detectată o situație anormală.

Pentru a sări peste orice pași pe care îi puteți folosi omitStages.

Într-un fișier de politică, putem descrie mai multe secțiuni cu niveluri diferite de înregistrare. Se va aplica prima regulă de potrivire găsită în descrierea politicii.

Daemonul kubelet monitorizează modificările din manifest cu configurația api-server și, dacă este detectat, repornește containerul cu api-server. Dar există un detaliu important: modificările din fișierul de politici vor fi ignorate de acesta. După ce faceți modificări în fișierul de politică, va trebui să reporniți manual serverul api. Deoarece api-server este pornit ca pod statică, echipa kubectl delete nu va determina repornirea acestuia. Va trebui să o faci manual docker stop pe kube-masters, unde politica de audit a fost modificată:

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

Când activați auditul, este important să rețineți că sarcina pe kube-apiserver crește. În special, consumul de memorie pentru stocarea contextului cererii crește. Înregistrarea începe numai după ce antetul răspunsului este trimis. Încărcarea depinde și de configurația politicii de audit.

Exemple de politici

Să ne uităm la structura fișierelor de politici folosind exemple.

Iată un fișier simplu policypentru a înregistra totul la nivel Metadata:

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

În politică puteți specifica o listă de utilizatori (Users и ServiceAccounts) și grupuri de utilizatori. De exemplu, așa vom ignora utilizatorii sistemului, dar vom înregistra orice altceva la nivel 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

De asemenea, se pot descrie obiectivele:

  • spații de nume (namespaces);
  • Verbe (verbe: get, update, delete si altii);
  • resurse (resurse, După cum urmează: pod, configmaps etc.) și grupuri de resurse (apiGroups).

Acorde o atenție! Resurse și grupuri de resurse (grupuri API, adică apiGroups), precum și versiunile lor instalate în cluster, pot fi obținute folosind comenzile:

kubectl api-resources
kubectl api-versions

Următoarea politică de audit este oferită ca o demonstrație a celor mai bune practici în Documentația 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

Un alt exemplu bun de politică de audit este profil utilizat în GCE.

Pentru a răspunde rapid la evenimentele de audit, este posibil descrie webhook. Această problemă este acoperită în documentație oficială, îl voi lăsa în afara domeniului de aplicare al acestui articol.

Rezultatele

Articolul oferă o prezentare generală a mecanismelor de securitate de bază din clusterele Kubernetes, care vă permit să creați conturi de utilizator personalizate, să le separați drepturile și să le înregistrați acțiunile. Sper că va fi de folos celor care se confruntă cu astfel de probleme în teorie sau în practică. De asemenea, vă recomand să citiți lista altor materiale pe tema securității în Kubernetes, care este dată în „PS” - poate că printre ele veți găsi detaliile necesare despre problemele care sunt relevante pentru dvs.

PS

Citește și pe blogul nostru:

Sursa: www.habr.com

Adauga un comentariu