
Рано или късно в експлоатацията на всяка система възниква въпросът за сигурността: осигуряване на автентикация, разделение на правата, одит и други задачи. За Kubernetes вече са създадени , които позволяват постигане на съответствие със стандартите дори в много изискващи среди… Този материал е посветен на основните аспекти на сигурността, реализирани в рамките на вградените механизми на K8s. Най-вече той ще бъде полезен на тези, които започват да се запознават с Kubernetes, — като отправна точка за изучаване на въпросите, свързани със сигурността.
Аутентификация
В Kubernetes има два типа потребители:
- Service Accounts — акаунти, управлявани от Kubernetes API;
- Потребители — „нормални“ потребители, управлявани от външни, независими услуги.
Основната разлика между тези типове е, че за Service Accounts съществуват специални обекти в Kubernetes API (те така и се наричат — ServiceAccounts), които са свързани с пространство от имена и набор от авторизационни данни, съхранявани в клъстера в обекти от тип Secrets. Тези потребители (Service Accounts) са предназначени основно за управление на правата за достъп до Kubernetes API на процеси, работещи в клъстера Kubernetes.
Обикновените потребители нямат записи в Kubernetes API: управлението им трябва да се извършва от външни механизми. Те са предназначени за хора или процеси, живеещи извън клъстера.
Всеки запитване към API е свързано или с Service Account, или с User, или се счита за анонимно.
Аутентификационните данни на потребителя включват:
- Потребителско име — име на потребителя (зависи от регистра!);
- UID — машинно-читаема низ идентификация на потребителя, която е „по-последователна и уникална от името на потребителя“;
- Groups — списък с групи, към които принадлежи потребителят;
- Extra — допълнителни полета, които могат да бъдат използвани от механизма за авторизация.
Kubernetes може да използва множество механизми за аутентификация: X509 сертификати, Bearer токени, аутентифициращи проксита, HTTP Basic Auth. С тези механизми могат да се реализират различни схеми за авторизация: от статичен файл с пароли до OpenID OAuth2.
Още повече, разрешава се използването на няколко схеми за авторизация едновременно. По подразбиране в клъстера се използват:
- service account tokens — за Service Accounts;
- X509 — за потребители.
Въпросът за управлението на ServiceAccounts излиза извън обсега на тази статия, а за желаещите да се запознаят по-подробно с този въпрос, препоръчвам да започнат от . Ние ще разгледаме по-подробно въпроса за работата на сертификатите X509.
Сертификати за потребители (X.509)
Класическият начин на работа с сертификати предполага:
- генериране на ключ:
mkdir -p ~/mynewuser/.certs/ openssl genrsa -out ~/mynewuser.key 2048 - генериране на искане за сертификат:
openssl req -new -key ~/mynewuser.key -out ~/mynewuser.csr -subj "/CN=mynewuser/O=company" - обработка на искането за сертификат с помощта на ключовете на CA на кластера Kubernetes, получаване на сертификат за потребителя (за получаване на сертификата трябва да се използва акаунт, който има достъп до ключа на централата на сертификата на кластера Kubernetes, който по подразбиране се намира в
/etc/kubernetes/pki/ca.key):openssl x509 -req -in ~/mynewuser.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out ~/mynewuser.crt -days 500 - създаване на конфигурационен файл:
- описание на кластера (посочете адреса и местоположението на файла на сертификата CA за конкретната инсталация на кластера):
kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443 - или — като непрепоръчителният вариант — можете да не посочвате кореновия сертификат (тогава kubectl няма да проверява правилността на api-server на кластера):
kubectl config set-cluster kubernetes --insecure-skip-tls-verify=true --server=https://192.168.100.200:6443 - добавяне на потребител в конфигурационния файл:
kubectl config set-credentials mynewuser --client-certificate=.certs/mynewuser.crt --client-key=.certs/mynewuser.key - добавяне на контекст:
kubectl config set-context mynewuser-context --cluster=kubernetes --namespace=target-namespace --user=mynewuser - назначаване на контекста по подразбиране:
kubectl config use-context mynewuser-context
- описание на кластера (посочете адреса и местоположението на файла на сертификата CA за конкретната инсталация на кластера):
След горепосочените манипулации, в файла .kube\/config ще бъде създаден конфигурационен файл от типа:
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За улесняване на прехвърлянето на конфигурацията между акаунти и сървъри, полезно е да се редактират стойностите на следните ключове:
-
certificate-authority -
client-certificate -
client-key
За целта можете да кодирате посочените в тях файлове с помощта на base64 и да ги запишете в конфигурацията, добавяйки суфикс -data, т.е. да получите certificate-authority-data и т.н.
Сертификати с kubeadm
С изданието работата с сертификати стана значително по-лесна благодарение на алфа версията на поддръжката в . Например, ето как може да изглежда генерирането на конфигурационен файл с потребителски ключове:
kubeadm alpha kubeconfig user --client-name=mynewuser --apiserver-advertise-address 192.168.100.200 NB: Изискван advertise address може да бъде видян в конфигурационния файл на api-server, който по подразбиране се намира в /etc/kubernetes/manifests/kube-apiserver.yaml.
Резултатният конфиг ще бъде изведен в stdout. Трябва да бъде запазен в ~/kube/config потребителската сметка или в файла, посочен в променливата на средата KUBECONFIG.
Пробийте по-дълбоко
За желаещите да се запознаят по-подробно с описаните въпроси:
- относно работа с сертификати в официалната документация на Kubernetes;
- , в която освен всичко друго е разгледан въпросът за сертификатите от практическа гледна точка.
- за автентикация в Kubernetes.
Авторизация
Авторизираният акаунт по подразбиране няма права за действия в кластера. За предоставяне на разрешения в Kubernetes е реализиран механизъм за авторизация.
Преди версия 1.6 в Kubernetes се прилаган тип авторизация, наречен ABAC (контрол на достъпа на база атрибути). Подробности за него можете да намерите в . В момента този подход се счита за остарял (legacy), но все пак можете да го използвате паралелно с други типове авторизация.
Актуалният (и по-гъвкав) начин за разделяне на правата за достъп до кластера се нарича RBAC (). Той бе обявен за стабилен с версия . RBAC реализира модел на права, при който е забранено всичко, което не е разрешено изрично.
За да активирате RBAC, трябва да стартирате Kubernetes api-server с параметър --authorization-mode=RBAC. Параметрите се задават в манифеста с конфигурацията на api-server, който по подразбиране се намира по пътя /etc/kubernetes/manifests/kube-apiserver.yaml, в секцията command. Все пак, по подразбиране RBAC е включен, така че вероятно не е необходимо да се притеснявате за това: можете да се уверите в това по стойността на authorization-mode (в вече споменатия kube-apiserver.yaml). Между другото, сред неговите стойности може да се окажат и други типове авторизация (node, webhook, always allow), но тяхното разглеждане оставяме извън обсега на материала.
Между другото, вече публикувахме с достатъчно подробен разказ за принципите и особеностите на работа с RBAC, така че по-нататък ще се огранича до кратко изброяване на основите и примери.
За управление на достъпа в Kubernetes чрез RBAC се използват следните API ентитети:
-
RoleиClusterRole— роли, които служат за описание на правата за достъп: -
Roleпозволява да се опишат правата в рамките на пространството имена; -
ClusterRole— в рамките на клъстера, включително към клъстер-специфични обекти като възли, non-resources urls (т.е. не свързани с ресурсите на Kubernetes — например,/version,/logs,/api*); -
RoleBindingиClusterRoleBinding— служи за привързванеRoleиClusterRoleк потребител, група потребители или ServiceAccount.
Съществата Role и RoleBinding са ограничени до namespace, т.е. трябва да бъдат в рамките на едно пространство на имена. Въпреки това, RoleBinding може да се позовава на ClusterRole, което позволява да се създаде набор от типични разрешения и да се управлява достъпът с тяхна помощ.
Ролите описват правата чрез набори от правила, съдържащи:
- групи API — виж. от apiGroups и извеждане
kubectl api-resources; - ресурси (resources:
pod,namespace,deploymentи т.н.); - глаголи (verbs:
set,актуализиранеи т.н.). - имена на ресурси (
resourceNames) — за случай, когато е нужно да се предостави достъп до конкретен ресурс, а не до всички ресурси от този тип.
По-подробно разглеждане на авторизацията в Kubernetes можете да намерите на страницата . Вместо това (или по-точно — в допълнение към това) ще дам примери, които илюстрират нейната работа.
Примери за съществата RBAC
Прост Role, позволяваща да се получи списък и статус на pod-ове и да се следят в пространството на имената 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"] Пример ClusterRole, което позволява да се получи списък и статус на pod-ове и да се следят в целия клъстер:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
# секцията "namespace" няма, тъй като ClusterRole обхваща целия клъстер
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "watch", "list"] Пример RoleBinding, което позволява на потребителя mynewuser да «чете» pod-ове в пространството на имената 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, което е в същото пространство на имената,
# или името на ClusterRole, използването на която
# искаме да разрешим на потребителя
apiGroup: rbac.authorization.k8s.ioАудит на събитията
Схематично архитектурата на Kubernetes може да бъде представена по следния начин:

Ключовият компонент на Kubernetes, който отговаря за обработката на заявки, е api-server. Всички операции с клъстера преминават през него. По-подробно за тези вътрешни механизми можете да прочетете в статията «».
Аудит на системата е интересна функция в Kubernetes, която по подразбиране е деактивирана. Тя позволява логването на всички заявки към Kubernetes API. Както лесно може да се предположи, чрез този API се извършват всички действия, свързани с контрола и промените в състоянието на клъстера. Добро описание на възможностите й може да се намери в K8s. Впоследствие ще се опитам да изложа темата по-просто.
И така, За да активираме аудита,трябва да предадем на контейнера в api-server три задължителни параметъра, за които по-подробно ще разкажа по-долу:
-
--audit-policy-file=/etc/kubernetes/policies/audit-policy.yaml -
--audit-log-path=/var/log/kube-audit/audit.log -
--audit-log-format=json
Освен тези три основни параметъра, съществуват множество допълнителни настройки, свързани с аудита: от ротацията на логовете до описания на webhook. Пример за параметри за ротация на логовете:
-
--audit-log-maxbackup=10 -
--audit-log-maxsize=100 -
--audit-log-maxage=7
Но няма да се спираме на тях в подробности – всички детайли могат да бъдат намерени в .
Както вече споменахме, всички параметри се задават в манифеста с конфигурацията на api-server (по подразбиране /etc/kubernetes/manifests/kube-apiserver.yaml), в секцията command. Нека се върнем към трите задължителни параметъра и да ги разгледаме:
-
audit-policy-fileе пътят до YAML файла с описание на политиката (policy) на аудита. Ще се върнем към съдържанието му по-късно, но засега отбелязвам, че файлът трябва да бъде достъпен за четене от процеса на api-server. Затова е необходимо да се монтира вътре в контейнера, за което можете да добавите следния код в съответните секции на конфигурацията:volumeMounts: - mountPath: /etc/kubernetes/policies name: policies readOnly: true volumes: - hostPath: path: /etc/kubernetes/policies type: DirectoryOrCreate name: policies -
audit-log-pathе пътят до файла на логовете. Пътят също трябва да бъде достъпен за процеса на api-server, затова аналогично описваме неговото монтиране:volumeMounts: - mountPath: /var/log/kube-audit name: logs readOnly: false volumes: - hostPath: path: /var/log/kube-audit type: DirectoryOrCreate name: logs -
audit-log-formatе формата на логовете за аудита. По подразбиране това еjson, но е наличен и остарелият текстов формат (legacy).
Политика на аудита
Сега относно споменатия файл с описание на политиката за логване. Първото понятие на audit policy е level, ниво на логване. Те могат да бъдат следните:
-
Няма— не логвай; -
Metadata— логвай метаданните на заявката: потребителя, времето на заявката, целевия ресурс (pod, namespace и т.н.), типа на действието (verb) и т.н.; -
Request— логвай метаданните и тялото на заявката; -
RequestResponse— логвай метаданните, тялото на заявката и тялото на отговора.
Последните два нива (Request и RequestResponse) не логват заявки, които не са насочени към ресурси (обаждания към т.н. non-resources urls).
Също така всички заявки преминават през няколко етапа:
-
RequestReceived— етап, когато заявката е получена от обработчика и все още не е предадена нататък в веригата от обработчици; -
ResponseStarted— заглавките на отговора са изпратени, но преди да бъде изпратено тялото на отговора. Генерира се за дълготрайни заявки (например,watch); -
ResponseComplete— тялото на отговора е изпратено, допълнителна информация няма да бъде изпратена; -
Panic— събитията се генерират, когато се открие неправилна ситуация.
За пропускане на някои етапи може да се използва omitStages.
В политиката можем да описваме няколко секции с различни нива на логване. Прилага се първото подходящо правило, намерено в описанието на policy.
Демонът kubelet следи промените в манифеста с конфигурацията на api-server и при откриването на такива рестартира контейнера с api-server. Но има важен детайл: промените в файла на политиката ще бъдат игнорирани от него. След промени в файла на политиката ще е необходимо ръчно да се рестартира api-server. Тъй като api-server е стартиран като , командата kubectl delete няма да доведе до неговото рестартиране. Налага се ръчно да се направи docker stop на kube-master-ите, където е променена политиката за одит:
docker stop $(docker ps | grep k8s_kube-apiserver | awk '{print $1}')При включване на одита е важно да се помни, че върху kube-apiserver натоварването нараства. В частност, увеличава се потреблението на памет за съхранение на контекста на заявките. Записването в журнала започва едва след изпращането на заглавката на отговора. Също така натоварването зависи от конфигурацията на политиката за одит.
Примери за политики
Нека разгледаме структурата на файловете на политиките с примери.
Ето един прост файл policy, за да регистрира всичко на ниво Metadata:
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata В политиката могат да се посочват списъци с потребители (Потребители и ServiceAccounts) и групи от потребители. Например, по този начин ще игнорираме системните потребители, но ще логваме всичко останало на ниво 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Също така има възможност да се описват целеви:
- пространства от имена (
namespaces); - глаголи (verbs:
get,актуализиране,изтрийи др.); - ресурси (resources, именно:
pod,configmapsи т.н.) и групи ресурси (apiGroups).
Обърнете внимание! Ресурсите и групите ресурси (групи на API, т.е. apiGroups), както и техните версии, инсталирани в клъстера, могат да бъдат получени с помощта на командите:
kubectl api-resources
kubectl api-versionsСледната политика за проверка е представена като демонстрация на добри практики в :
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Друг добър пример за политика на одит е .
За бързо реагиране на събития от одита, можете да опишете webhook. Този въпрос е разгледан в , ще го оставя извън обсега на тази статия.
Резюме
В статията се представя преглед на механизми за основна сигурност в Kubernetes клъстери, които позволяват създаването на персонализирани потребителски акаунти, разделяне на правата им и записване на действията им. Надявам се, той да е полезен за тези, които се сблъскват с такива въпроси в теорията или на практика. Препоръчвам също да се запознаете със списъка на други материали по темата за сигурността в Kubernetes, който е посочен в „P.S.“, — може би сред тях ще намерите нужните подробности за актуалните за вас проблеми.
P.S.
Прочетете също в нашия блог:
- «»;
- «»;
- «»;
- «»;
- «».
Източник: habr.com
