Азбуката на сигурността в Kubernetes: удостоверяване, оторизация, одит

Азбуката на сигурността в Kubernetes: удостоверяване, оторизация, одит

Рано или късно при работата на всяка система възниква въпросът за сигурността: осигуряване на удостоверяване, разделяне на правата, одит и други задачи. Вече е създаден за Kubernetes много решения, които ви позволяват да постигнете съответствие със стандартите дори в много взискателни среди ... Същият материал е посветен на основните аспекти на сигурността, реализирани в рамките на вградените механизми на K8s. На първо място, ще бъде полезно за тези, които започват да се запознават с Kubernetes - като отправна точка за изучаване на въпроси, свързани със сигурността.

заверка

В Kubernetes има два типа потребители:

  • Сервизни акаунти - акаунти, управлявани от Kubernetes API;
  • Потребители - "нормални" потребители, управлявани от външни, независими услуги.

Основната разлика между тези типове е, че има специални обекти за акаунти за услуги в API на Kubernetes (те се наричат ​​така - ServiceAccounts), които са обвързани с пространство от имена и набор от данни за оторизация, съхранени в клъстера в обекти от тип Secrets. Такива потребители (сервизни акаунти) са предназначени главно за управление на правата за достъп до Kubernetes API на процеси, изпълнявани в Kubernetes клъстер.

Обикновените потребители, от друга страна, нямат записи в Kubernetes API: те трябва да се управляват от външни механизми. Те са предназначени за хора или процеси, живеещи извън клъстера.

Всяка заявка за API е свързана или с акаунт за услуга, или с потребител, или се счита за анонимна.

Данните за удостоверяване на потребителя включват:

  • Потребител — потребителско име (малки и малки букви!);
  • UID - машинночетим потребителски идентификационен низ, който е "по-последователен и уникален от потребителско име";
  • Групи — списък на групите, към които принадлежи потребителят;
  • екстра - допълнителни полета, които могат да се използват от механизма за оторизация.

Kubernetes може да използва голям брой механизми за удостоверяване: X509 сертификати, токени на носителя, прокси за удостоверяване, HTTP Basic Auth. Използвайки тези механизми, можете да приложите голям брой схеми за оторизация: от файл със статична парола до OpenID OAuth2.

Освен това могат да се използват едновременно множество схеми за оторизация. По подразбиране клъстерът използва:

  • токени за сервизен акаунт - за Сервизни акаунти;
  • X509 - за потребители.

Въпросът за управлението на ServiceAccounts е извън обхвата на тази статия и за тези, които желаят да научат повече за този проблем, препоръчвам да започнете с страници с официална документация. Ще разгледаме по-отблизо издаването на сертификати X509.

Сертификати за потребители (X.509)

Класическият начин за работа със сертификати включва:

  • генериране на ключове:
    mkdir -p ~/mynewuser/.certs/
    openssl genrsa -out ~/.certs/mynewuser.key 2048
  • генериране на заявка за сертификат:
    openssl req -new -key ~/.certs/mynewuser.key -out ~/.certs/mynewuser.csr -subj "/CN=mynewuser/O=company"
  • обработка на заявката за сертификат с помощта на CA ключовете на Kubernetes клъстера, получаване на потребителски сертификат (за да получите сертификат, трябва да използвате акаунт, който има достъп до ключа на Kubernetes клъстер CA, който по подразбиране се намира в /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
  • създаване на конфигурационен файл:
    • описание на клъстера (посочете адреса и местоположението на CA сертификатния файл на конкретната инсталация на клъстера):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • или как непрепоръчителна опция - не можете да посочите основния сертификат (тогава kubectl няма да провери коректността на api-сървъра на клъстера):
      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

След горните манипулации, във файла .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

С освобождаване Kubernetes 1.15 работата със сертификати стана много по-лесна благодарение на алфа версията на поддръжката му в помощна програма kubeadm. Например, ето как може да изглежда сега генерирането на конфигурационен файл с потребителски ключове:

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

NB: Задължително адрес за реклама може да се види в конфигурацията на api-сървъра, която се намира по подразбиране в /etc/kubernetes/manifests/kube-apiserver.yaml.

Получената конфигурация ще бъде отпечатана на stdout. Трябва да се съхранява ~/.kube/config потребителски акаунт или към файл, посочен в променлива на средата KUBECONFIG.

Копайте по-дълбоко

За тези, които искат да разгледат по-отблизо описаните проблеми:

Упълномощаване

Упълномощеният акаунт по подразбиране няма права да действа върху клъстера. За да предостави разрешения, Kubernetes прилага механизъм за оторизация.

Преди версия 1.6 Kubernetes използва тип оторизация, наречен ABAC (Контрол на достъпа, базиран на атрибути). Подробности за него можете да намерите в официална документация. Понастоящем този подход се счита за наследен, но все пак можете да го използвате едновременно с други типове оторизация.

Действителният (и по-гъвкав) начин за разделяне на правата за достъп до клъстер се нарича RBAC (Ролев контрол на достъпа). Той е обявен за стабилен от версията Kubernetes 1.8. RBAC прилага модел на права, който забранява всичко, което не е изрично разрешено.
За да активирате RBAC, трябва да стартирате api-сървър на Kubernetes с параметъра --authorization-mode=RBAC. Параметрите са зададени в манифеста с конфигурацията на api-сървъра, която по подразбиране се намира по пътя /etc/kubernetes/manifests/kube-apiserver.yaml, в раздел command. По подразбиране обаче RBAC вече е активиран, така че най-вероятно не трябва да се притеснявате за това: можете да проверите това чрез стойността authorization-mode (във вече споменатото kube-apiserver.yaml). Между другото, сред неговите стойности може да има и други видове разрешение (node, webhook, always allow), но ще оставим тяхното разглеждане извън обхвата на материала.

Между другото, вече сме публикували Статия с доста подробна история за принципите и характеристиките на работа с RBAC, така че по-нататък ще се огранича до кратко изброяване на основите и примерите.

Следните API обекти се използват за контролиране на достъпа до Kubernetes чрез RBAC:

  • Role и ClusterRole - роли, които служат за описание на правата за достъп:
  • Role ви позволява да опишете правата в рамките на пространството от имена;
  • ClusterRole - в рамките на клъстера, включително към специфични за клъстера обекти като възли, URL адреси без ресурси (т.е. несвързани с ресурси на Kubernetes - например, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - използва се за подвързване Role и ClusterRole към потребител, потребителска група или ServiceAccount.

Обектите Role и RoleBinding са обвързани с пространство от имена, т.е. трябва да бъде в същото пространство от имена. Въпреки това, RoleBinding може да се отнася до ClusterRole, което ви позволява да създадете набор от общи разрешения и да контролирате достъпа с тях.

Ролите описват права с помощта на набори от правила, съдържащи:

  • API групи - вж официална документация от apiGroups и изход kubectl api-resources;
  • ресурси (ресурси: pod, namespace, deployment и др.);
  • глаголи (глаголи: set, update и други подобни).
  • имена на ресурси (resourceNames) - за случая, когато трябва да предоставите достъп до конкретен ресурс, а не до всички ресурси от този тип.

По-подробна разбивка на оторизацията в Kubernetes може да бъде намерена на страницата официална документация. Вместо това (или по-скоро в допълнение към това) ще дам примери, които илюстрират работата му.

Примери за RBAC обект

прост Role, което ви позволява да получите списък и състояние на подове и да ги следите в пространството на имената 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, което ви позволява да получите списък и състояние на подове и да ги наблюдавате в целия клъстер:

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

Пример RoleBinding, което позволява на потребителя mynewuser "чете" подове в пространството на имената 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

Одит на събития

Схематично архитектурата на Kubernetes може да бъде представена по следния начин:

Азбуката на сигурността в Kubernetes: удостоверяване, оторизация, одит

Ключовият компонент на Kubernetes, отговорен за обработката на заявките, е − api-сървър. През него минават всички операции на клъстера. Можете да прочетете повече за тези вътрешни механизми в статията "Какво се случва в Kubernetes, когато стартирате kubectl run?".

Системният одит е интересна функция в Kubernetes, която е деактивирана по подразбиране. Тя ви позволява да регистрирате всички обаждания към Kubernetes API. Както можете да предположите, всички действия, свързани с контрола и промяната на състоянието на клъстера, се извършват чрез този API. Добро описание на неговите възможности (както обикновено) можете да намерите в официална документация K8s. По-нататък ще се опитам да обясня темата по по-прост начин.

По този начин, за да се даде възможност за одит, трябва да предадем три необходими параметъра към контейнера в api-сървъра, които са описани по-подробно по-долу:

  • --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

Но ние няма да се спираме на тях по-подробно - можете да намерите всички подробности в документация на kube-apiserver.

Както вече споменахме, всички параметри са зададени в манифеста с конфигурацията на api-сървъра (по подразбиране /etc/kubernetes/manifests/kube-apiserver.yaml), в раздела command. Нека се върнем към 3-те необходими параметъра и да ги анализираме:

  1. audit-policy-file - пътят до YAML файла с описание на политиката (политиката) на одита. Ще се върнем към съдържанието му, но засега ще отбележа, че файлът трябва да може да се чете от процеса на api-сървъра. Следователно трябва да го монтирате вътре в контейнера, за което можете да добавите следния код към съответните раздели на конфигурацията:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path - път до лог файла. Пътят трябва да е достъпен и за процеса на api-сървъра, така че описваме монтирането му по същия начин:
      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 — формат на одитния журнал. По подразбиране е json, но наследеният текстов формат също е наличен (legacy).

Политика за одит

Сега за споменатия файл с описание на политиката за регистриране. Първата концепция за одитна политика е level, ниво на регистриране. Те са както следва:

  • None - не влизайте в лог;
  • Metadata — метаданни за заявка за регистриране: потребител, време на заявка, целеви ресурс (под, пространство от имена и т.н.), тип действие (глагол) и т.н.;
  • Request - метаданни на регистрационния файл и тяло на заявката;
  • RequestResponse - метаданни на регистрационния файл, тяло на заявката и тяло на отговора.

Последните две ниваRequest и RequestResponse) не регистрирайте заявки, които не са имали достъп до ресурси (препратки към така наречените url адреси без ресурси).

Освен това всички заявки преминават няколко етапа:

  • RequestReceived - етапът, когато заявката е получена от манипулатора и все още не е прехвърлена по-нататък по веригата от манипулатори;
  • ResponseStarted - Заглавките на отговора се изпращат, но преди да бъде изпратено тялото на отговора. Генерирани за продължителни заявки (напр. watch);
  • ResponseComplete - тялото за отговор е изпратено, повече информация няма да бъде изпращана;
  • Panic — Събития се генерират, когато се открие необичайна ситуация.

За да пропуснете всеки етап, можете да използвате omitStages.

Във файла на правилата можем да опишем няколко секции с различни нива на регистриране. Ще бъде приложено първото съответстващо правило, намерено в описанието на правилата.

Демонът kubelet следи за промяна в манифеста с конфигурацията на api-сървъра и, ако има такава, рестартира контейнера на api-сървъра. Но има важна подробност: промените във файла на правилата ще бъдат игнорирани. След като направите промени във файла с политики, ще трябва да рестартирате api-сървъра ръчно. Тъй като api-сървърът се стартира като статичен под, екип kubectl delete няма да го рестартира. Ще трябва да го направите ръчно docker stop на kube-masters, където политиката за одит е променена:

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

В правилата можете да посочите списък с потребители (Users и 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);
  • глаголи (глаголи: get, update, delete и други);
  • ресурси (ресурси, Както следва: pod, configmaps и т.н.) и групи ресурси (apiGroups).

Забележка! Ресурси и групи ресурси (API групи, т.е. apiGroups), както и техните версии, инсталирани в клъстера, могат да бъдат получени с помощта на командите:

kubectl api-resources
kubectl api-versions

Следната политика за одит е предоставена като демонстрация на най-добрите практики в Документация на 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

Друг добър пример за одитна политика е профил, използван в GCE.

За бърз отговор на одитни събития е възможно да се опишете webhook. Този въпрос е обхванат в официална документацияЩе го оставя извън обхвата на тази статия.

Резултати от

Статията предоставя преглед на основните механизми за сигурност в клъстерите на Kubernetes, които позволяват създаване на персонализирани потребителски акаунти, разделяне на техните права и регистриране на техните действия. Надявам се, че ще бъде полезно за тези, които се сблъскват с подобни проблеми на теория или вече на практика. Също така препоръчвам да се запознаете със списъка с други материали по темата за сигурността в Kubernetes, който е даден в „PS“, може би сред тях ще намерите необходимите подробности за проблемите, които са от значение за вас.

PS

Прочетете също в нашия блог:

Източник: www.habr.com

Добавяне на нов коментар