Абецеда безбедности у Кубернетесу: аутентификација, ауторизација, ревизија

Абецеда безбедности у Кубернетесу: аутентификација, ауторизација, ревизија

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

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

Постоје два типа корисника у Кубернетесу:

  • Сервисни налози — налози којима управља Кубернетес АПИ;
  • Корисници — „нормални“ корисници којима управљају спољни, независни сервиси.

Главна разлика између ових типова је у томе што за сервисне налоге постоје посебни објекти у Кубернетес АПИ-ју (они се тако зову - ServiceAccounts), који су везани за простор имена и скуп ауторизационих података ускладиштених у кластеру у објектима типа Сецретс. Такви корисници (сервисни налози) су првенствено намењени за управљање правима приступа Кубернетес АПИ-ју процеса који се покрећу у Кубернетес кластеру.

Обични корисници немају уносе у Кубернетес АПИ-ју: њима морају управљати спољни механизми. Намењени су људима или процесима који живе ван кластера.

Сваки АПИ захтев је повезан са налогом услуге, корисником или се сматра анонимним.

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

  • Корисничко име — корисничко име (разликује велика и мала слова!);
  • УИД - машински читљив идентификациони низ корисника који је „доследнији и јединственији од корисничког имена“;
  • grupe — списак група којима корисник припада;
  • Ектра — додатна поља која може да користи механизам ауторизације.

Кубернетес може да користи велики број механизама за аутентификацију: Кс509 сертификате, токене носиоца, прокси за аутентификацију, ХТТП Басиц Аутх. Користећи ове механизме, можете имплементирати велики број шема ауторизације: од статичне датотеке са лозинкама до ОпенИД ОАутх2.

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

  • токени сервисних налога - за налоге услуге;
  • Кс509 - за кориснике.

Питање о управљању сервисним налозима је ван оквира овог чланка, али за оне који желе да се детаљније упознају са овим питањем, препоручујем да почну са странице званичне документације. Детаљније ћемо размотрити питање како Кс509 сертификати функционишу.

Сертификати за кориснике (Кс.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"
  • обрада захтева за сертификат коришћењем ЦА кључева Кубернетес кластера, добијање корисничког сертификата (да бисте добили сертификат, морате да користите налог који има приступ ЦА кључу Кубернетес кластера, који се подразумевано налази у /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
  • креирање конфигурационе датотеке:
    • опис кластера (наведите адресу и локацију датотеке ЦА сертификата за одређену инсталацију кластера):
      kubectl config set-cluster kubernetes --certificate-authority=/etc/kubernetes/pki/ca.crt --server=https://192.168.100.200:6443
    • или како непрепоручена опција - не морате да наведете роот сертификат (онда кубецтл неће проверити исправност апи-сервера кластера):
      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

Да бисте то урадили, можете кодирати датотеке наведене у њима користећи басе64 и регистровати их у конфигурацији, додајући суфикс имену кључева -data, тј. примивши certificate-authority-data итд

Сертификати са кубеадм-ом

Са ослобађањем Кубернетес 1.15 рад са сертификатима је постао много лакши захваљујући алфа верзији његове подршке у кубеадм утилити. На пример, генерисање конфигурационе датотеке са корисничким кључевима сада може изгледати овако:

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

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

Резултирајућа конфигурација ће бити излазна у стдоут. Треба га сачувати у ~/.kube/config кориснички налог или у датотеку наведену у променљивој окружења KUBECONFIG.

Дубље

За оне који желе да разумеју детаљније описана питања:

Овлашћење

Подразумевано овлашћени налог нема права да ради на кластеру. Да би доделио дозволе, Кубернетес примењује механизам ауторизације.

Пре верзије 1.6, Кубернетес је користио тип ауторизације под називом АБАЦ (Контрола приступа заснована на атрибутима). Детаљи о томе могу се наћи у званична документација. Овај приступ се тренутно сматра застарелим, али га и даље можете користити заједно са другим типовима аутентификације.

Тренутни (и флексибилнији) начин поделе права приступа кластеру се зове РБАЦ (Контрола приступа заснована на улогама). Од верзије је проглашен стабилним Кубернетес 1.8. РБАЦ имплементира модел права у којем је забрањено све што није изричито дозвољено.
Да бисте омогућили РБАЦ, потребно је да покренете Кубернетес апи-сервер са параметром --authorization-mode=RBAC. Параметри се постављају у манифесту са конфигурацијом апи-сервера, који се подразумевано налази дуж путање /etc/kubernetes/manifests/kube-apiserver.yaml, у одељку command. Међутим, РБАЦ је већ подразумевано омогућен, тако да највероватније не би требало да бринете о томе: ово можете да проверите помоћу вредности authorization-mode (у већ поменутом kube-apiserver.yaml). Иначе, међу његовим значењима могу бити и друге врсте овлашћења (node, webhook, always allow), али ћемо њихово разматрање оставити ван оквира материјала.

Иначе, већ смо објавили статью са прилично детаљним описом принципа и карактеристика рада са РБАЦ-ом, па ћу се даље ограничити на кратко навођење основа и примера.

Следећи АПИ ентитети се користе за контролу приступа у Кубернетес преко РБАЦ-а:

  • Role и ClusterRole — улоге које служе за описивање права приступа:
  • Role омогућава вам да опишете права унутар именског простора;
  • ClusterRole - унутар кластера, укључујући објекте специфичне за кластер као што су чворови, УРЛ-ови који нису ресурси (тј. нису повезани са Кубернетес ресурсима - на пример, /version, /logs, /api*);
  • RoleBinding и ClusterRoleBinding - користи се за везивање Role и ClusterRole на корисника, корисничку групу или сервисни налог.

Ентитети Роле и РолеБиндинг су ограничени простором имена, тј. мора бити унутар истог именског простора. Међутим, РолеБиндинг може референцирати ЦлустерРоле, што вам омогућава да креирате скуп генеричких дозвола и контролишете приступ користећи их.

Улоге описују права користећи скупове правила која садрже:

  • АПИ групе - види званична документација помоћу апиГроупс и излаза kubectl api-resources;
  • ресурси (средства: pod, namespace, deployment итд.);
  • Глаголи (глаголи: set, update итд.)
  • имена ресурса (resourceNames) - за случај када треба да обезбедите приступ одређеном ресурсу, а не свим ресурсима овог типа.

Детаљнију анализу ауторизације у Кубернетесу можете пронаћи на страници званична документација. Уместо тога (или боље речено, поред овога) навешћу примере који илуструју њен рад.

Примери РБАЦ ентитета

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

Ревизија догађаја

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

Абецеда безбедности у Кубернетесу: аутентификација, ауторизација, ревизија

Кључна Кубернетес компонента одговорна за обраду захтева је апи-сервер. Све операције на кластеру пролазе кроз њега. Више о овим унутрашњим механизмима можете прочитати у чланку „Шта се дешава у Кубернетесу када покренете кубецтл рун?'.

Ревизија система је занимљива функција у Кубернетесу, која је подразумевано онемогућена. Омогућава вам да евидентирате све позиве на Кубернетес АПИ. Као што можете претпоставити, све радње везане за праћење и промену стања кластера се обављају преко овог АПИ-ја. Добар опис његових могућности може се (као и обично) наћи у званична документација К8с. Затим ћу покушати да представим тему једноставнијим језиком.

Дакле, да омогући ревизију, морамо да проследимо три потребна параметра у контејнер у апи-серверу, који су детаљније описани у наставку:

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

Али нећемо се детаљније задржавати на њима - све детаље можете пронаћи у кубе-аписервер документација.

Као што је већ поменуто, сви параметри су постављени у манифесту са конфигурацијом апи-сервера (подразумевано /etc/kubernetes/manifests/kube-apiserver.yaml), у одељку command. Вратимо се на 3 потребна параметра и анализирамо их:

  1. audit-policy-file — путања до ИАМЛ датотеке која описује политику ревизије. Касније ћемо се вратити на његов садржај, али за сада ћу напоменути да фајл мора бити читљив процесом апи-сервера. Због тога је неопходно да га монтирате унутар контејнера, за шта можете додати следећи код у одговарајуће делове конфигурације:
      volumeMounts:
        - mountPath: /etc/kubernetes/policies
          name: policies
          readOnly: true
      volumes:
      - hostPath:
          path: /etc/kubernetes/policies
          type: DirectoryOrCreate
        name: policies
  2. audit-log-path — путања до датотеке евиденције. Путања такође мора бити доступна процесу апи-сервера, тако да описујемо његово монтирање на исти начин:
      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) не евидентирају захтеве који нису приступили ресурсима (приступи такозваним УРЛ-овима који нису ресурси).

Такође сви захтеви пролазе неколико фаза:

  • RequestReceived — фаза када је захтев примљен од стране процесора и још увек није пренет даље дуж ланца процесора;
  • ResponseStarted — шаљу се заглавља одговора, али пре него што се пошаље тело одговора. Генерисано за дуготрајне упите (нпр. watch);
  • ResponseComplete — тело одговора је послато, више информација неће бити послато;
  • Panic — догађаји се генеришу када се открије ненормална ситуација.

Да бисте прескочили све кораке које можете да користите omitStages.

У датотеци политике можемо описати неколико секција са различитим нивоима евидентирања. Биће примењено прво подударно правило пронађено у опису смерница.

Кубелет даемон прати промене у манифесту са конфигурацијом апи-сервера и, ако их открије, поново покреће контејнер са апи-сервером. Али постоји важан детаљ: промене у датотеци смерница ће бити игнорисане. Након што унесете измене у датотеку смерница, мораћете ручно да поново покренете апи-сервер. Пошто је апи-сервер покренут као статички под, тим kubectl delete неће довести до поновног покретања. Мораћете то да урадите ручно docker stop на кубе-мастерс, где је политика ревизије промењена:

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

Када омогућавате ревизију, важно је то запамтити оптерећење на кубе-аписерверу се повећава. Посебно се повећава потрошња меморије за чување контекста захтева. Евидентирање почиње тек након што се пошаље заглавље одговора. Оптерећење такође зависи од конфигурације политике ревизије.

Примери политика

Погледајмо структуру датотека политика користећи примере.

Ево једноставне датотеке 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).

Обрати пажњу! Ресурси и групе ресурса (АПИ групе, тј. апиГроупс), као и њихове верзије инсталиране у кластеру, могу се добити помоћу команди:

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

Још један добар пример политике ревизије је профил који се користи у ГЦЕ.

Да бисте брзо одговорили на догађаје ревизије, могуће је опишите вебхоок. Ово питање је покривено у званична документација, оставићу то ван оквира овог чланка.

Резултати

У чланку је дат преглед основних безбедносних механизама у Кубернетес кластерима, који вам омогућавају да креирате персонализоване корисничке налоге, одвојите њихова права и забележите њихове радње. Надам се да ће бити од користи онима који се суочавају са оваквим питањима у теорији или пракси. Такође вам препоручујем да прочитате списак других материјала на тему безбедности у Кубернетесу, који је дат у „ПС“ – можда међу њима пронађете потребне детаље о проблемима који су вам релевантни.

ПС

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

Извор: ввв.хабр.цом

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