ABC за безбедност во Kubernetes: автентикација, овластување, ревизија

ABC за безбедност во Kubernetes: автентикација, овластување, ревизија

Порано или подоцна, во работењето на кој било систем, се поставува прашањето за безбедност: обезбедување автентикација, поделба на правата, ревизија и други задачи. Веќе создаден за Kubernetes многу решенија, кои ви овозможуваат да постигнете усогласеност со стандардите дури и во многу тешки средини... Истиот материјал е посветен на основните аспекти на безбедноста имплементирани во вградените механизми на K8s. Како прво, тоа ќе биде корисно за оние кои почнуваат да се запознаваат со Кубернетес - како почетна точка за проучување на прашања поврзани со безбедноста.

Автентикација

Постојат два типа на корисници во Kubernetes:

  • Сметки за услуги — сметки управувани од Kubernetes API;
  • Корисници — „нормални“ корисници управувани од надворешни, независни сервиси.

Главната разлика помеѓу овие типови е тоа што за сервисни сметки има специјални објекти во Kubernetes API (тие се нарекуваат така - ServiceAccounts), кои се врзани за именски простор и збир на податоци за авторизација складирани во кластерот во објекти од типот Secrets. Таквите корисници (Сметки на услуги) првенствено се наменети за управување со правата за пристап до Кубернетес API на процесите што се извршуваат во кластерот Кубернетес.

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

Секое барање за API е поврзано или со сметка за услуга, со корисник или се смета за анонимно.

Податоците за автентикација на корисникот вклучуваат:

  • Корисничко име — корисничко име (чувствително на големи букви!);
  • UID - низа за идентификација на корисникот читлива од машина, која е „поконзистентна и единствена од корисничкото име“;
  • групи — список на групи на кои припаѓа корисникот;
  • дополнителен — дополнителни полиња што може да ги користи механизмот за овластување.

Kubernetes може да користи голем број механизми за автентикација: сертификати X509, токени на носител, прокси за автентикација, основна автентичност на HTTP. Користејќи ги овие механизми, можете да имплементирате голем број шеми за авторизација: од статична датотека со лозинки до OpenID OAuth2.

Покрај тоа, можно е да се користат неколку шеми за авторизација истовремено. Стандардно, кластерот користи:

  • токени за сервисни сметки - за сметки за услуги;
  • X509 - за корисници.

Прашањето за управување со сервисни сметки е надвор од опсегот на овој напис, но за оние кои сакаат подетално да се запознаат со ова прашање, препорачувам да започнете со официјални страници со документација. Ќе го разгледаме подетално прашањето како функционираат сертификатите 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, добивање кориснички сертификат (за да добиете сертификат, мора да користите сметка што има пристап до клучот CA од кластерот Kubernetes, кој стандардно се наоѓа во /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
    • или како Немапрепорачана опција - не мора да го наведете root сертификатот (тогаш 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

Со ослободувањето Кубернес 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 (Контрола на пристап заснована на улоги). Тој е прогласен за стабилен уште од верзијата Кубернес 1.8. RBAC имплементира модел на права во кој се што не е експлицитно дозволено е забрането.
За да се овозможи RBAC, треба да го стартувате Kubernetes api-серверот со параметарот --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 - во кластерот, вклучително и објекти специфични за кластерот, како што се јазли, адреси кои не се ресурси (т.е. не се поврзани со ресурсите на Кубернетес - на пример, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - се користи за врзување Role и ClusterRole на корисник, корисничка група или сервисна сметка.

Ентитетите 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

Ревизија на настанот

Шематски, архитектурата Кубернетес може да се претстави на следниов начин:

ABC за безбедност во 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

Покрај овие три неопходни параметри, има многу дополнителни поставки поврзани со ревизија: од ротација на дневници до описи на веб-куки. Пример за параметри за ротација на дневникот:

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

Но, ние нема да се задржиме на нив подетално - можете да ги најдете сите детали во кубе-аписервер документација.

Како што веќе споменавме, сите параметри се поставени во манифестот со конфигурацијата на 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-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

Во политиката можете да наведете листа на корисници (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.

За брзо реагирање на ревизорските настани, можно е опишете веб-кука. Ова прашање е опфатено во официјална документација, ќе го оставам надвор од опсегот на оваа статија.

Резултатите од

Статијата дава преглед на основните безбедносни механизми во кластерите на Kubernetes, кои ви дозволуваат да креирате персонализирани кориснички сметки, да ги одделите нивните права и да ги снимите нивните дејства. Се надевам дека ќе биде корисно за оние кои се соочуваат со вакви прашања во теорија или во пракса. Исто така, препорачувам да го прочитате списокот со други материјали на тема безбедност во Кубернетес, кој е даден во „ПС“ - можеби меѓу нив ќе ги најдете потребните детали за проблемите што се релевантни за вас.

PS

Прочитајте и на нашиот блог:

Извор: www.habr.com

Додадете коментар