ABC zabezpečení v Kubernetes: ověřování, autorizace, auditování

ABC zabezpečení v Kubernetes: ověřování, autorizace, auditování

Dříve nebo později se při provozu jakéhokoli systému objeví otázka bezpečnosti: zajištění autentizace, oddělení práv, audit a další úkoly. Již vytvořeno pro Kubernetes mnoho řešení, které umožňují dosáhnout shody se standardy i ve velmi náročných prostředích... Stejný materiál je věnován základním bezpečnostním aspektům implementovaným v rámci vestavěných mechanismů K8s. V první řadě se bude hodit těm, kteří se s Kubernetes začínají seznamovat – jako výchozí bod pro studium otázek souvisejících s bezpečností.

Ověřování

V Kubernetes existují dva typy uživatelů:

  • Servisní účty - účty spravované rozhraním Kubernetes API;
  • uživatelé - "normální" uživatelé spravovaní externími nezávislými službami.

Hlavní rozdíl mezi těmito typy spočívá v tom, že v Kubernetes API existují speciální objekty pro servisní účty (nazývají se takto - ServiceAccounts), které jsou vázány na jmenný prostor a sadu autorizačních dat uložených v clusteru v objektech typu Secrets. Takoví uživatelé (servisní účty) jsou určeny především ke správě přístupových práv k rozhraní Kubernetes API procesů běžících v clusteru Kubernetes.

Na druhou stranu běžní uživatelé nemají položky v Kubernetes API: musí být spravovány externími mechanismy. Jsou určeny lidem nebo procesům žijícím mimo klastr.

Každý požadavek API je vázán buď na servisní účet nebo na uživatele, nebo je považován za anonymní.

Ověřovací údaje uživatele zahrnují:

  • Uživatelské jméno — uživatelské jméno (rozlišují se malá a velká písmena!);
  • UID - strojově čitelný identifikační řetězec uživatele, který je „konzistentnější a jedinečný než uživatelské jméno“;
  • Skupiny — seznam skupin, do kterých uživatel patří;
  • extra - další pole, která mohou být použita mechanismem autorizace.

Kubernetes může používat velké množství ověřovacích mechanismů: certifikáty X509, tokeny nosiče, ověřovací proxy, HTTP Basic Auth. Pomocí těchto mechanismů můžete implementovat velké množství autorizačních schémat: od statického souboru hesel až po OpenID OAuth2.

Kromě toho lze současně používat více autorizačních schémat. Ve výchozím nastavení cluster používá:

  • tokeny servisních účtů - pro servisní účty;
  • X509 - pro uživatele.

Otázka správy ServiceAccounts přesahuje rámec tohoto článku a těm, kteří se chtějí o této problematice dozvědět více, doporučuji začít s stránky oficiální dokumentace. Na problematiku certifikátů X509 se podíváme blíže.

Certifikáty pro uživatele (X.509)

Klasický způsob práce s certifikáty zahrnuje:

  • generace klíčů:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • vygenerování žádosti o certifikát:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • zpracování žádosti o certifikát pomocí klíčů CA clusteru Kubernetes, získání uživatelského certifikátu (k získání certifikátu je třeba použít účet, který má přístup ke klíči CA clusteru Kubernetes, který se standardně nachází 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
  • vytvoření konfiguračního souboru:
    • popis clusteru (uveďte adresu a umístění souboru certifikátu CA konkrétní instalace clusteru):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • nebo jak nedoporučená možnost - nemůžete zadat kořenový certifikát (pak kubectl nebude kontrolovat správnost clusteru api-server):
      kubectl config set-cluster kubernetes  --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443
    • přidání uživatele do konfiguračního souboru:
      kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt  --client-key=.certs/mynewuser.key
    • přidání kontextu:
      kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser
    • výchozí přiřazení kontextu:
      kubectl config use-context mynewuser-context

Po výše uvedených manipulacích v souboru .kube/config vytvoří se konfigurace zobrazení:

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

Pro usnadnění přenosu konfigurace mezi účty a servery je užitečné upravit hodnoty následujících klíčů:

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

Chcete-li to provést, můžete zakódovat soubory v nich uvedené pomocí base64 a zaregistrovat je v konfiguraci přidáním přípony k názvu klíčů -data, tj. přijaté certificate-authority-data atd.

Certifikáty s kubeadm

S uvolněním Kubernetes 1.15 práce s certifikáty se výrazně zjednodušila díky alfa verzi jeho podpory v nástroj kubeadm. Například takto může nyní vypadat generování konfiguračního souboru s uživatelskými klíči:

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

NB: Požadované inzerovat adresu lze zobrazit v konfiguraci api-server, která je ve výchozím nastavení umístěna v /etc/kubernetes/manifests/kube-apiserver.yaml.

Výsledná konfigurace bude vytištěna na stdout. Musí to být uchováno ~/.kube/config uživatelského účtu nebo do souboru zadaného v proměnné prostředí KUBECONFIG.

Kopej hlouběji

Pro ty, kteří se chtějí blíže podívat na popsané problémy:

Povolení

Autorizovaný účet ve výchozím nastavení nemá práva jednat s clusterem. Pro udělení oprávnění implementuje Kubernetes mechanismus autorizace.

Před verzí 1.6 používal Kubernetes typ autorizace nazvaný ABAC (Řízení přístupu založené na atributech). Podrobnosti o něm najdete v oficiální dokumentace. Tento přístup je v současné době považován za zastaralý, ale stále jej můžete používat současně s jinými typy oprávnění.

Skutečný (a flexibilnější) způsob oddělení přístupových práv ke clusteru se nazývá RBAC (Řízení přístupu na základě rolí). Od verze je prohlášen za stabilní Kubernetes 1.8. RBAC implementuje model práv, který zakazuje vše, co není výslovně povoleno.
Chcete-li povolit RBAC, musíte spustit Kubernetes api-server s parametrem --authorization-mode=RBAC. Parametry se nastavují v manifestu s konfigurací api-server, která je ve výchozím nastavení umístěna podél cesty /etc/kubernetes/manifests/kube-apiserver.yaml, v sekci command. Ve výchozím nastavení je však RBAC již povolen, takže byste si s tím pravděpodobně neměli dělat starosti: můžete to ověřit pomocí hodnoty authorization-mode (v již zmíněném kube-apiserver.yaml). Mimochodem, mezi jeho hodnotami mohou být i jiné typy oprávnění (node, webhook, always allow), ale jejich zvážení ponecháme nad rámec materiálu.

Mimochodem, už jsme publikovali Článek s poměrně podrobným příběhem o principech a vlastnostech práce s RBAC, takže se dále omezím na stručný výčet základů a příkladů.

Následující entity API se používají k řízení přístupu ke Kubernetes přes RBAC:

  • Role и ClusterRole - role, které slouží k popisu přístupových práv:
  • Role umožňuje popsat práva v rámci jmenného prostoru;
  • ClusterRole - v rámci clusteru, včetně objektů specifických pro cluster, jako jsou uzly, adresy URL bez zdrojů (tj. nesouvisející se zdroji Kubernetes - například, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - slouží k vázání Role и ClusterRole uživateli, skupině uživatelů nebo servisnímu účtu.

Entity Role a RoleBinding jsou vázané na jmenný prostor, tzn. musí být ve stejném jmenném prostoru. RoleBinding však může odkazovat na ClusterRole, která vám umožňuje vytvořit sadu obecných oprávnění a řídit s nimi přístup.

Role popisují práva pomocí sad pravidel obsahujících:

  • Skupiny API - viz oficiální dokumentace pomocí apiGroups a výstupu kubectl api-resources;
  • zdroje (zdroje: pod, namespace, deployment a tak dále.);
  • Slovesa (slovesa: set, update atd.).
  • názvy zdrojů (resourceNames) - pro případ, kdy potřebujete poskytnout přístup ke konkrétnímu zdroji, a ne ke všem zdrojům tohoto typu.

Podrobnější rozpis autorizace v Kubernetes najdete na stránce oficiální dokumentace. Místo toho (nebo spíše kromě toho) uvedu příklady, které ilustrují jeho práci.

Příklady entit RBAC

Jednoduché Role, která vám umožňuje získat seznam a stav podů a sledovat je ve jmenném 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"]

příklad ClusterRole, která vám umožňuje získat seznam a stav podů a sledovat je v celém clusteru:

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

příklad RoleBinding, která uživateli umožňuje mynewuser „čtení“ podů ve jmenném 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

Audit událostí

Schematicky lze architekturu Kubernetes znázornit takto:

ABC zabezpečení v Kubernetes: ověřování, autorizace, auditování

Klíčovou komponentou Kubernetes odpovědnou za zpracování požadavků je − api-server. Procházejí jím všechny operace na clusteru. Více o těchto vnitřních mechanismech si můžete přečíst v článku "Co se stane v Kubernetes, když spustíte kubectl run?".

Systémový audit je zajímavá funkce v Kubernetes, která je ve výchozím nastavení zakázána. Umožňuje vám protokolovat všechna volání do Kubernetes API. Jak asi tušíte, všechny akce související s ovládáním a změnou stavu clusteru se provádějí prostřednictvím tohoto API. Dobrý popis jeho schopností lze (jako obvykle) nalézt v oficiální dokumentace K8s. V následujícím se pokusím téma vysvětlit jednodušším způsobem.

To znamená, pro umožnění auditu, potřebujeme předat kontejneru v api-serveru tři požadované parametry, které jsou podrobněji popsány níže:

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

Kromě těchto tří požadovaných parametrů existuje mnoho dalších nastavení souvisejících s auditováním: od rotace protokolů po popisy webhooku. Příklad parametrů rotace protokolu:

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

Ale nebudeme se jim podrobněji věnovat - všechny podrobnosti najdete v dokumentace kube-apiserver.

Jak již bylo zmíněno, všechny parametry jsou nastaveny v manifestu s konfigurací api-server (ve výchozím nastavení /etc/kubernetes/manifests/kube-apiserver.yaml), v sekci command. Vraťme se ke 3 požadovaným parametrům a analyzujeme je:

  1. audit-policy-file - cesta k souboru YAML s popisem politiky (politiky) auditu. Vrátíme se k jeho obsahu, ale prozatím poznamenám, že soubor musí být čitelný procesem api-server. Proto jej musíte připojit do kontejneru, pro který můžete do příslušných částí konfigurace přidat následující kód:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path - cesta k souboru protokolu. Cesta musí být dostupná také procesu api-server, takže její připojení popisujeme stejným způsobem:
      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 — formát protokolu auditu. Výchozí nastavení je json, ale je k dispozici i starší textový formát (legacy).

Zásady auditu

Nyní o zmíněném souboru s popisem logovací politiky. Prvním konceptem auditní politiky je level, úroveň protokolování. Jsou následující:

  • None - nepřihlašovat se;
  • Metadata — logovací metadata požadavku: uživatel, čas požadavku, cílový zdroj (pod, jmenný prostor atd.), typ akce (sloveso) atd.;
  • Request - logovat metadata a tělo požadavku;
  • RequestResponse - metadata protokolu, tělo požadavku a tělo odpovědi.

Poslední dvě úrovněRequest и RequestResponse) nezaznamenávat požadavky, které nepřistupovaly ke zdrojům (odkazy na tzv. non-resources url).

Také všechny žádosti projdou několik fází:

  • RequestReceived - fáze, kdy uživatel obdrží žádost a ještě nebyla předána dále v řetězci zpracovatelů;
  • ResponseStarted - Záhlaví odpovědi jsou odeslána, ale před odesláním těla odpovědi. Generováno pro dlouhotrvající dotazy (např. watch);
  • ResponseComplete - tělo odpovědi bylo odesláno, nebudou zasílány žádné další informace;
  • Panic — Události jsou generovány, když je detekována abnormální situace.

Chcete-li přeskočit jakékoli fáze, můžete použít omitStages.

V souboru zásad můžeme popsat několik sekcí s různými úrovněmi protokolování. Bude použito první odpovídající pravidlo nalezené v popisu zásady.

Démon kubelet naslouchá změnám v manifestu s konfigurací api-serveru a pokud existuje, restartuje kontejner api-serveru. Ale je tu důležitý detail: změny v souboru zásad budou ignorovány. Po provedení změn v souboru zásad budete muset restartovat api-server ručně. Protože api-server je spuštěn jako statický pod, tým kubectl delete nebude restartovat. Bude to muset udělat ručně docker stop na kube-masters, kde byly změněny zásady auditu:

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

Při povolování auditování je důležité na to pamatovat zatížení se zvyšuje na kube-apiserver. Zejména se zvyšuje spotřeba paměti pro ukládání kontextu dotazu. Protokolování se spustí až po odeslání hlavičky odpovědi. Zatížení také závisí na konfiguraci zásady auditu.

Příklady zásad

Pojďme analyzovat strukturu souborů zásad pomocí příkladů.

Zde je jednoduchý soubor policyzaznamenat vše na úrovni Metadata:

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

V zásadách můžete zadat seznam uživatelů (Users и ServiceAccounts) a skupiny uživatelů. Například takto budeme ignorovat systémové uživatele, ale vše ostatní logujeme na úrovni 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

Je také možné popsat cíl:

  • jmenné prostory (namespaces);
  • Slovesa (slovesa: get, update, delete a další);
  • zdroje (zdroje, Se mění takto: pod, configmaps atd.) a skupiny zdrojů (apiGroups).

Dávejte pozor! Prostředky a skupiny prostředků (skupiny API, tj. apiGroups), stejně jako jejich verze nainstalované v clusteru, lze získat pomocí příkazů:

kubectl api-resources
kubectl api-versions

Následující zásady auditu jsou uvedeny jako ukázka osvědčených postupů v Dokumentace 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

Dalším dobrým příkladem zásady auditu je profil používaný v GCE.

Pro rychlou reakci na události auditu je možné popsat webhook. Tato otázka je pokryta v oficiální dokumentaceNechám to mimo rámec tohoto článku.

Výsledky

Tento článek poskytuje přehled základních bezpečnostních mechanismů v clusterech Kubernetes, které umožňují vytvářet personalizované uživatelské účty, oddělovat jejich práva a protokolovat jejich akce. Doufám, že to bude užitečné pro ty, kteří se s takovými problémy teoreticky nebo již v praxi potýkají. Doporučuji také, abyste se seznámili se seznamem dalších materiálů na téma bezpečnosti v Kubernetes, který je uveden v „PS“, možná mezi nimi najdete potřebné podrobnosti o problémech, které se vás týkají.

PS

Přečtěte si také na našem blogu:

Zdroj: www.habr.com

Přidat komentář