
Wcześniej czy później w działaniu dowolnego systemu pojawia się kwestia bezpieczeństwa: zapewnienie uwierzytelnienia, rozdział uprawnień, audyt i inne zadania. Już stworzony dla Kubernetes , które pozwalają osiągnąć zgodność ze standardami nawet w bardzo wymagających środowiskach... Ten sam materiał poświęcony jest podstawowym aspektom bezpieczeństwa realizowanym w ramach wbudowanych mechanizmów K8s. Przede wszystkim przyda się osobom rozpoczynającym przygodę z Kubernetesem – jako punkt wyjścia do studiowania zagadnień związanych z bezpieczeństwem.
Uwierzytelnianie
W Kubernetesie istnieją dwa typy użytkowników:
- Konta usług — konta zarządzane przez Kubernetes API;
- użytkownicy — „zwykli” użytkownicy zarządzani przez zewnętrzne, niezależne usługi.
Główna różnica między tymi typami polega na tym, że dla kont usług istnieją specjalne obiekty w Kubernetes API (nazywa się je tak - ServiceAccounts), które są powiązane z przestrzenią nazw i zestawem danych autoryzacyjnych przechowywanych w klastrze w obiektach typu Secrets. Tacy użytkownicy (Konta Usług) służą przede wszystkim do zarządzania prawami dostępu do Kubernetes API procesów uruchomionych w klastrze Kubernetes.
Zwykli Użytkownicy nie mają wpisów w Kubernetes API: muszą być zarządzani przez zewnętrzne mechanizmy. Przeznaczone są dla osób lub procesów żyjących poza klastrem.
Każde żądanie API jest powiązane z Kontem Usługi, Użytkownikiem lub jest uznawane za anonimowe.
Dane uwierzytelniające użytkownika obejmują:
- Nazwa użytkownika — nazwa użytkownika (wielkość liter ma znaczenie!);
- NIP (VAT) - ciąg identyfikacyjny użytkownika nadający się do odczytu maszynowego, który jest „bardziej spójny i niepowtarzalny niż nazwa użytkownika”;
- Grupy — lista grup, do których należy użytkownik;
- Extra — dodatkowe pola, które może wykorzystać mechanizm autoryzacyjny.
Kubernetes może korzystać z dużej liczby mechanizmów uwierzytelniania: certyfikatów X509, tokenów okaziciela, uwierzytelniającego proxy, podstawowego uwierzytelniania HTTP. Korzystając z tych mechanizmów, można zaimplementować dużą liczbę schematów autoryzacji: od statycznego pliku z hasłami po OpenID OAuth2.
Ponadto istnieje możliwość jednoczesnego korzystania z kilku schematów uprawnień. Domyślnie klaster używa:
- tokeny do kont serwisowych – dla Kont serwisowych;
- X509 - dla Użytkowników.
Pytanie o zarządzanie ServiceAccounts wykracza poza zakres tego artykułu, ale dla tych, którzy chcą zapoznać się z tym zagadnieniem bardziej szczegółowo, polecam zacząć od . Przyjrzymy się bliżej zagadnieniu działania certyfikatów X509.
Certyfikaty dla użytkowników (X.509)
Klasyczny sposób pracy z certyfikatami polega na:
- generacja klucza:
mkdir -p ~/mynewuser/.certs/ openssl genrsa -out ~/.certs/mynewuser.key 2048 - generowanie żądania certyfikatu:
openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company" - przetworzenie żądania certyfikatu przy użyciu kluczy CA klastra Kubernetes, uzyskanie certyfikatu użytkownika (w celu uzyskania certyfikatu należy skorzystać z konta mającego dostęp do klucza CA klastra Kubernetes, który domyślnie znajduje się w
/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 - utworzenie pliku konfiguracyjnego:
- opis klastra (podaj adres i lokalizację pliku certyfikatu CA dla konkretnej instalacji klastra):
kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443 - albo jak niezalecana opcja - nie musisz podawać certyfikatu głównego (wtedy kubectl nie będzie sprawdzał poprawności serwera api klastra):
kubectl config set-cluster kubernetes --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443 - dodanie użytkownika do pliku konfiguracyjnego:
kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt --client-key=.certs/mynewuser.key - dodanie kontekstu:
kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser - domyślne przypisanie kontekstu:
kubectl config use-context mynewuser-context
- opis klastra (podaj adres i lokalizację pliku certyfikatu CA dla konkretnej instalacji klastra):
Po powyższych manipulacjach w pliku .kube/config zostanie utworzona taka konfiguracja:
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.keyAby ułatwić przenoszenie konfiguracji pomiędzy kontami a serwerami warto edytować wartości następujących kluczy:
-
certificate-authority -
client-certificate -
client-key
W tym celu możesz zakodować określone w nich pliki za pomocą base64 i zarejestrować je w configu, dodając końcówkę do nazwy kluczy -data, tj. otrzymawszy certificate-authority-data itd.
Certyfikaty z kubeadm
Wraz z wydaniem praca z certyfikatami stała się znacznie łatwiejsza dzięki wersji alfa jej obsługi w . Na przykład tak może teraz wyglądać generowanie pliku konfiguracyjnego z kluczami użytkownika:
kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200 NB: Wymagany adres reklamowy można znaleźć w konfiguracji serwera api, która domyślnie znajduje się w /etc/kubernetes/manifests/kube-apiserver.yaml.
Wynikowa konfiguracja zostanie wyprowadzona na standardowe wyjście. Trzeba to zapisać w ~/.kube/config koncie użytkownika lub do pliku określonego w zmiennej środowiskowej KUBECONFIG.
Kop głębiej
Dla chcących dokładniej zrozumieć opisane zagadnienia:
- o pracy z certyfikatami w oficjalnej dokumentacji Kubernetesa;
- , w którym kwestia certyfikatów została poruszona od strony praktycznej.
- podczas uwierzytelniania w Kubernetesie.
autoryzacja
Domyślne autoryzowane konto nie ma uprawnień do działania w klastrze. Aby nadać uprawnienia, Kubernetes implementuje mechanizm autoryzacji.
Przed wersją 1.6 Kubernetes używał typu autoryzacji o nazwie ABAK (Kontrola dostępu oparta na atrybutach). Szczegóły na ten temat można znaleźć w . To podejście jest obecnie uważane za starsze, ale nadal można go używać razem z innymi typami uwierzytelniania.
Obecny (i bardziej elastyczny) sposób podziału praw dostępu do klastra nazywa się RBAC (). Od wersji uznano ją za stabilną . RBAC wdraża model praw, w którym wszystko, co nie jest wyraźnie dozwolone, jest zabronione.
Aby włączyć funkcję RBAC, musisz uruchomić serwer API Kubernetes z parametrem --authorization-mode=RBAC. Parametry ustawiane są w manifeście wraz z konfiguracją serwera API, która domyślnie znajduje się wzdłuż ścieżki /etc/kubernetes/manifests/kube-apiserver.yaml, w sekcji command. Jednak funkcja RBAC jest już domyślnie włączona, więc najprawdopodobniej nie powinieneś się tym martwić: możesz to sprawdzić na podstawie wartości authorization-mode (we wspomnianym już kube-apiserver.yaml). Nawiasem mówiąc, wśród jego znaczeń mogą istnieć inne rodzaje autoryzacji (node, webhook, always allow), ale ich rozważania pozostawimy poza zakresem materiału.
Nawiasem mówiąc, już opublikowaliśmy z dość szczegółowym opisem zasad i cech pracy z RBAC, więc dalej ograniczę się do krótkiego zestawienia podstaw i przykładów.
Do kontroli dostępu w Kubernetes za pośrednictwem RBAC służą następujące encje API:
-
RoleиClusterRole— role służące do opisu praw dostępu: -
Rolepozwala na opisanie praw w obrębie przestrzeni nazw; -
ClusterRole- w ramach klastra, w tym do obiektów specyficznych dla klastra, takich jak węzły, adresy URL niebędące zasobami (tj. niezwiązane z zasobami Kubernetesa - np./version,/logs,/api*); -
RoleBindingиClusterRoleBinding- służy do wiązaniaRoleиClusterRoledo użytkownika, grupy użytkowników lub konta usługi.
Jednostki Role i RoleBinding są ograniczone przestrzenią nazw, tj. muszą znajdować się w tej samej przestrzeni nazw. Jednak RoleBinding może odwoływać się do ClusterRole, co umożliwia utworzenie zestawu ogólnych uprawnień i kontrolowanie dostępu przy ich użyciu.
Role opisują uprawnienia za pomocą zestawów reguł zawierających:
- Grupy API - patrz przez apiGroups i dane wyjściowe
kubectl api-resources; - zasoby (zasoby:
pod,namespace,deploymenti tak dalej.); - Czasowniki (czasowniki:
set,updateitp.). - nazwy zasobów (
resourceNames) - w przypadku, gdy trzeba zapewnić dostęp do konkretnego zasobu, a nie do wszystkich zasobów tego typu.
Bardziej szczegółową analizę autoryzacji w Kubernetesie znajdziesz na stronie . Zamiast tego (a raczej oprócz tego) podam przykłady ilustrujące jej twórczość.
Przykłady podmiotów RBAC
Proste Role, co pozwala uzyskać listę i status podów oraz monitorować je w przestrzeni nazw 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"] Przykład ClusterRole, co pozwala uzyskać listę i status podów oraz monitorować je w całym klastrze:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# секции "namespace" нет, так как ClusterRole задействует весь кластер
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"] Przykład RoleBinding, co pozwala użytkownikowi mynewuser „czytaj” kapsuły w przestrzeni nazw 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.ioAudyt wydarzenia
Schematycznie architekturę Kubernetes można przedstawić w następujący sposób:

Kluczowym komponentem Kubernetes odpowiedzialnym za przetwarzanie żądań jest serwer API. Wszystkie operacje na klastrze przechodzą przez niego. Więcej o tych wewnętrznych mechanizmach przeczytasz w artykule „".
Inspekcja systemu to interesująca funkcja w Kubernetesie, która jest domyślnie wyłączona. Umożliwia rejestrowanie wszystkich wywołań Kubernetes API. Jak można się domyślić, wszystkie akcje związane z monitorowaniem i zmianą stanu klastra realizowane są poprzez to API. Dobry opis jego możliwości można (jak zwykle) znaleźć w K8. Następnie postaram się przedstawić temat prostszym językiem.
W ten sposób aby umożliwić audyt, musimy przekazać trzy wymagane parametry do kontenera w api-server, które opisano bardziej szczegółowo poniżej:
-
--audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml -
--audit-log-path=/var/log/kube-audit/audit.log -
--audit-log-format=json
Oprócz tych trzech niezbędnych parametrów istnieje wiele dodatkowych ustawień związanych z audytem: od rotacji logów po opisy webhooków. Przykład parametrów rotacji dziennika:
-
--audit-log-maxbackup=10 -
--audit-log-maxsize=100 -
--audit-log-maxage=7
Ale nie będziemy się nad nimi rozwodzić bardziej szczegółowo - wszystkie szczegóły znajdziesz w .
Jak już wspomniano, wszystkie parametry są ustawiane w manifeście wraz z konfiguracją serwera api (domyślnie /etc/kubernetes/manifests/kube-apiserver.yaml), w sekcji command. Wróćmy do 3 wymaganych parametrów i przeanalizujmy je:
-
audit-policy-file— ścieżka do pliku YAML opisującego politykę audytu. Do jego zawartości wrócimy później, ale na razie zaznaczę, że plik musi być czytelny dla procesu api-server. Dlatego konieczne jest zamontowanie go wewnątrz kontenera, dla którego w odpowiednich sekcjach konfiguracji możesz dodać następujący kod:volumeMounts: - mountPath: /etc/kubernetes/policies name: policies readOnly: true volumes: - hostPath: path: /etc/kubernetes/policies type: DirectoryOrCreate name: policies -
audit-log-path— ścieżka do pliku dziennika. Ścieżka musi być dostępna także dla procesu serwera api, dlatego jej montaż opisujemy w ten sam sposób:volumeMounts: - mountPath: /var/log/kube-audit name: logs readOnly: false volumes: - hostPath: path: /var/log/kube-audit type: DirectoryOrCreate name: logs -
audit-log-format— format dziennika audytu. Wartość domyślna tojson, ale dostępny jest także starszy format tekstowy (legacy).
Polityka audytu
Teraz o wspomnianym pliku opisującym politykę logowania. Pierwszą koncepcją polityki audytu jest level, poziom logowania. Są one następujące:
-
None- nie loguj się; -
Metadata— metadane żądania logowania: użytkownik, czas żądania, zasób docelowy (pod, przestrzeń nazw itp.), typ akcji (czasownik) itp.; -
Request— metadane dziennika i treść żądania; -
RequestResponse— metadane dziennika, treść żądania i treść odpowiedzi.
Ostatnie dwa poziomy (Request и RequestResponse) nie rejestruj żądań, które nie korzystały z zasobów (dostępy do tzw. adresów URL innych niż zasoby).
Wszystkie prośby również zostają zrealizowane Kilka etapów:
-
RequestReceived— etap, na którym wniosek zostaje odebrany przez podmiot przetwarzający i nie został jeszcze przekazany dalej w łańcuchu podmiotów przetwarzających; -
ResponseStarted— nagłówki odpowiedzi są wysyłane, ale przed wysłaniem treści odpowiedzi. Generowane dla długotrwałych zapytań (na przykładwatch); -
ResponseComplete— treść odpowiedzi została wysłana, dalsze informacje nie będą przesyłane; -
Panic— zdarzenia są generowane w przypadku wykrycia sytuacji nienormalnej.
Aby pominąć dowolne kroki, których możesz użyć omitStages.
W pliku polityki możemy opisać kilka sekcji o różnych poziomach rejestrowania. Zastosowana zostanie pierwsza pasująca reguła znaleziona w opisie polisy.
Demon kubelet monitoruje zmiany w manifeście za pomocą konfiguracji api-server i, jeśli zostaną wykryte, ponownie uruchamia kontener za pomocą api-server. Ale jest ważny szczegół: zmiany w pliku zasad zostaną przez niego zignorowane. Po wprowadzeniu zmian w pliku zasad konieczne będzie ręczne zrestartowanie serwera API. Ponieważ serwer API jest uruchamiany jako , zespół kubectl delete nie spowoduje jego ponownego uruchomienia. Będziesz musiał to zrobić ręcznie docker stop na kube-masters, gdzie zmieniono politykę audytu:
docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')Włączając audyt, należy o tym pamiętać wzrasta obciążenie kube-apiserver. W szczególności wzrasta zużycie pamięci do przechowywania kontekstu żądania. Rejestrowanie rozpoczyna się dopiero po wysłaniu nagłówka odpowiedzi. Obciążenie zależy również od konfiguracji zasad inspekcji.
Przykłady polityk
Przyjrzyjmy się strukturze plików polityk na przykładach.
Oto prosty plik policyaby rejestrować wszystko na poziomie Metadata:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata W profilu możesz określić listę użytkowników (Users и ServiceAccounts) i grupy użytkowników. Przykładowo w ten sposób będziemy ignorować użytkowników systemu, a wszystko inne rejestrować na poziomie 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: RequestMożliwe jest również opisanie celów:
- przestrzenie nazw (
namespaces); - Czasowniki (czasowniki:
get,update,deletei inni); - zasoby (zasobyW następujący sposób:
pod,configmapsitp.) i grupy zasobów (apiGroups).
Uwaga! Zasoby i grupy zasobów (grupy API, czyli apiGroups), a także ich wersje zainstalowane w klastrze można uzyskać za pomocą poleceń:
kubectl api-resources
kubectl api-versionsPoniższa polityka audytu została przedstawiona jako demonstracja najlepszych praktyk w zakresie :
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: MetadataInnym dobrym przykładem polityki audytu jest .
Aby szybko reagować na zdarzenia audytowe, jest to możliwe opisz webhooka. Zagadnienie to zostało omówione w , pozostawię to poza zakresem tego artykułu.
Wyniki
W artykule omówiono podstawowe mechanizmy bezpieczeństwa w klastrach Kubernetes, które pozwalają na tworzenie spersonalizowanych kont użytkowników, oddzielanie ich uprawnień i rejestrowanie ich działań. Mam nadzieję, że będzie przydatna dla tych, którzy w teorii lub w praktyce stają przed takimi zagadnieniami. Polecam także zapoznać się z listą innych materiałów na temat bezpieczeństwa w Kubernetesie, która jest podana w „PS” – być może wśród nich znajdziesz niezbędne szczegóły dotyczące istotnych dla Ciebie problemów.
PS
Przeczytaj także na naszym blogu:
- «";
- «";
- «";
- «";
- «".
Źródło: www.habr.com
