Азбука бяспекі ў Kubernetes: аўтэнтыфікацыя, аўтарызацыя, аўдыт

Азбука бяспекі ў Kubernetes: аўтэнтыфікацыя, аўтарызацыя, аўдыт

Рана ці позна ў эксплуатацыі любой сістэмы ўстае пытанне бяспекі: забеспячэнні аўтэнтыфікацыі, падзелы мае рацыю, аўдыту і іншых задач. Для Kubernetes ужо створана мноства рашэнняў, якія дазваляюць дамагчыся адпаведнасці стандартам нават у вельмі патрабавальных асяродках… Гэты ж матэрыял прысвечаны базавым аспектам бяспекі, рэалізаваным у рамках убудаваных механізмаў K8s. У першую чаргу ён будзе карысны тым, хто пачынае знаёміцца ​​з Kubernetes, - як адпраўная кропка для вывучэння пытанняў, звязаных з бяспекай.

аўтэнтыфікацыя

У Kubernetes ёсць два тыпы карыстальнікаў:

  • Сэрвісныя акаўнты - Акаўнты, якія кіруюцца Kubernetes API;
  • карыстальнікаў – «нармальныя» карыстачы, кіраваныя вонкавымі, незалежнымі сэрвісамі.

Асноўнае адрозненне гэтых тыпаў у тым, што для Service Accounts існуюць спецыяльныя аб'екты ў Kubernetes API (яны так і называюцца - ServiceAccounts), якія прывязаны да прасторы імёнаў і набору аўтарызацыйных дадзеных, якія захоўваюцца ў кластары ў аб'ектах тыпу Secrets. Такія карыстальнікі (Service Accounts) прызначаны ў асноўным для кіравання правамі доступу да Kubernetes API працэсаў, якія працуюць у кластары Kubernetes.

Звычайныя ж Users не маюць запісаў у Kubernetes API: кіраванне імі павінна ажыццяўляцца вонкавымі механізмамі. Яны прызначаны для людзей або працэсаў, якія жывуць па-за кластарам.

Кожны запыт да API прывязаны альбо да Service Account, альбо да User, альбо лічыцца ананімным.

Аўтэнтыфікацыйныя дадзеныя карыстальніка ўключаюць у сябе:

  • Імя карыстальніка - імя карыстальніка (залежыць ад рэгістра!);
  • UID — машынна-чытаемы радок ідэнтыфікацыі карыстальніка, які «больш кансістэнтны і ўнікальны, чым імя карыстальніка»;
  • груп - спіс груп, да якіх належыць карыстальнік;
  • экстра - Дадатковыя палі, якія могуць быць выкарыстаны механізмам аўтарызацыі.

Kubernetes можа выкарыстоўваць вялікую колькасць механізмаў аўтэнтыфікацыі: сертыфікаты X509, Bearer-токены, які аўтэнтыфікуе проксі, HTTP Basic Auth. Пры дапамозе гэтых механізмаў можна рэалізаваць вялікую колькасць схем аўтарызацыі: ад статычнага файла з паролямі да OpenID OAuth2.

Больш за тое, дапускаецца выкарыстанне некалькіх схем аўтарызацыі адначасова. Па змаўчанні ў кластары выкарыстоўваюцца:

  • service account tokens - для Service Accounts;
  • X509 - для Users.

Пытанне пра кіраванне 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, які па змаўчанні знаходзіцца ў /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-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

Пасля паказаных вышэй маніпуляцый, у файле .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: Патрабаваны advertise address можна паглядзець у канфігу api-server, які па змаўчанні размешчаны ў /etc/kubernetes/manifests/kube-apiserver.yaml.

Выніковы канфіг будзе выведзены ў stdout. Яго трэба захаваць у ~/.kube/config ўліковага запісу карыстальніка ці ж у файл, пазначаны ў зменнай асяроддзі KUBECONFIG.

Капнуць глыбей

Для жадаючых больш старанна разабрацца ў апісаных пытаннях:

Аўтарызацыя

Аўтарызаваны ўліковы запіс па змаўчанні не мае правоў на дзеянні ў кластары. Для прадастаўлення дазволаў у Kubernetes рэалізаваны механізм аўтарызацыі.

Да версіі 1.6 у Kubernetes ужываўся тып аўтарызацыі, званы ABAC (Attribute-based access control). Падрабязнасці аб ім можна знайсці ў афіцыйнай дакументацыі. У наш час гэты падыход лічыцца састарэлым (legacy), аднак вы ўсё яшчэ можаце выкарыстоўваць яго адначасова з іншымі тыпамі аўтарызацыі.

Актуальны ж (і больш гнуткі) спосаб падзелу правоў доступу да кластара завецца РБАК (Кантроль доступу на аснове роляў). Ён быў аб'яўлены стабільным з версіі Кубернетэс 1.8. 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;
  • рэсурсы (рэсурсы: pod, namespace, deployment і да т.п.);
  • дзеясловы (Дзеясловы: set, update і да т.п.).
  • імёны рэсурсаў (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, что находится в том же namespace,
                   # или имя ClusterRole, использование которой
                   # хотим разрешить пользователю
  apiGroup: rbac.authorization.k8s.io

Аўдыт падзей

Схематычна архітэктуру Kubernetes можна ўявіць наступным чынам:

Азбука бяспекі ў Kubernetes: аўтэнтыфікацыя, аўтарызацыя, аўдыт

Ключавы кампанент Kubernetes, які адказвае за апрацоўку запытаў, - api-server. Усе аперацыі над кластарам праходзяць праз яго. Падрабязней пра гэтыя ўнутраныя механізмы можна пачытаць у артыкуле «Што адбываецца ў Kubernetes пры запуску kubectl run?.

Аўдыт сістэмы - цікавая фіча ў 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

Але спыняцца падрабязней на іх не будзем - знайсці ўсе дэталі можна ў дакументацыі па kube-apiserver.

Як ужо згадвалася, усе параметры выстаўляюцца ў маніфесце са канфігурацыяй api-server (па змаўчанні /etc/kubernetes/manifests/kube-apiserver.yaml), у секцыі command. Вернемся да 3 абавязковых параметраў і разбяром іх:

  1. 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
  2. audit-log-path - шлях да файла лога. Шлях таксама павінен быць даступны працэсу api-server'a, таму аналагічна апісваем яго мантаванне:
      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).

Палітыка аўдыту

Зараз аб згаданым файле з апісаннем палітыкі лагіравання. Першае паняцце audit policy - гэта level, узровень лагіравання. Яны бываюць наступнымі:

  • None - не лагіраваць;
  • Metadata - лагіраваць метададзеныя запыту: карыстальніка, час запыту, мэтавы рэсурс (pod, namespace і да т.п.), тып дзеяння (verb) і да т.п.;
  • Request - лагіраваць метададзеныя і цела запыту;
  • RequestResponse - Лагаваць метададзеныя, цела запыту і цела адказу.

Апошнія два ўзроўні (Request и RequestResponse) не лагіруюць запыты, якія не звярталіся да рэсурсаў (звароты да так званых non-resources urls).

Таксама ўсе запыты праходзяць праз некалькі стадый:

  • RequestReceived - этап, калі запыт атрыманы апрацоўшчыкам і яшчэ не перададзены далей па ланцужку апрацоўшчыкаў;
  • ResponseStarted - загалоўкі адказу адпраўленыя, але перад адпраўкай цела адказу. Генеруецца для працяглых запытаў (напрыклад, watch);
  • ResponseComplete - цела адказу адпраўлена, больш інфармацыі адпраўляцца не будзе;
  • Panic - падзеі генеруюцца, калі выяўлена няштатная сітуацыя.

Для пропуску якіх-небудзь стадый можна выкарыстоўваць omitStages.

У файле палітыкі мы можам апісаць некалькі секцый з рознымі ўзроўнямі лагіравання. Прымяняцца будзе першае прыдатнае правіла, знойдзенае ў апісанні policy.

Дэман kubelet адсочвае змену маніфесту з канфігурацыяй api-server і пры выяўленні такіх перазапускае кантэйнер з api-server. Але ёсць важная дэталь: змены ў файле policy будуць ім ігнаравацца. Пасля занясення змен у файл policy запатрабуецца перазапусціць api-server уручную. Паколькі api-server запушчаны як static pod, каманда kubectl delete не прывядзе да яго перазапуску. Прыйдзецца ўручную зрабіць docker stop на kube-master'ах, дзе зменена палітыка аўдыту:

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

Пры ўключэнні аўдыту важна памятаць, што на kube-apiserver павялічваецца нагрузка. У прыватнасці, павялічваецца спажыванне памяці для захоўвання кантэксту запытаў. Запіс у лог пачынаецца толькі пасля адпраўкі загалоўка адказу. Таксама нагрузка залежыць ад канфігурацыі палітыкі аўдыту.

Прыклады палітык

Разбяром структуру файлаў policy на прыкладах.

Вось просты файл policy, каб лагіраваць усё на ўзроўні Metadata:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata

У policy можна ўказваць пералік карыстальнікаў (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

Наступны audit policy прыведзены ў якасці дэманстрацыі лепшых практык у дакументацыі 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

Іншы добры прыклад audit policy профіль, які выкарыстоўваецца ў GCE.

Для аператыўнага рэагавання на падзеі аўдыту ёсць магчымасць апісаць webhook. Гэтае пытанне расчынена ў афіцыйнай дакументацыі, пакіну яго за рамкамі дадзенага артыкула.

Вынікі

У артыкуле дадзены агляд механізмаў базавага забеспячэння бяспекі ў кластарах Kubernetes, якія дазваляюць ствараць персаніфікаваныя ўліковыя запісы карыстальнікам, падзяляць іх правы, а таксама рэгістраваць іх дзеянні. Спадзяюся, ён спатрэбіцца тым, хто сутыкнуўся з такімі пытаннямі ў тэорыі ці ўжо на практыцы. Рэкамендую таксама азнаёміцца ​​са спісам іншых матэрыялаў па тэме бяспекі ў Kubernetes, што прыведзены ў «PS», - магчыма, сярод іх вы знойдзеце патрэбныя падрабязнасці па актуальных для вас праблемах.

PS

Чытайце таксама ў нашым блогу:

Крыніца: habr.com

Дадаць каментар