Rootless kubernetes

Материал из ALT Linux Wiki


Общее описание

Запуск Kubernetes в режиме rootless обеспечивает запуск Podов без системных root-привелегий в рамках user namespace системного пользователя u7s-admin. Работа в этом режиме практически не требует никаких модификаций, но обеспечивает повышенные уровень защищенности kubernetes, так как клиентские приложения даже при использовании уязвимостей не могут получить права пользователя root и нарушить работу узла.

Запуск kubernetes версии 1.26.3 и старше в режиме rootless обеспечивает пакет podsec-k8s версии 1.0.5 или выше.

Быстрый старт

Установка master-узла

Инициализация master-узла

Для запуска kubernetes в режиме rootless установите пакет podsec-k8s версии 1.0.5 или выше.

apt-get install podsec-k8s

Измените переменную PATH:

export PATH=/usr/libexec/podsec/u7s/bin/:$PATH

В каталоге /usr/libexec/podsec/u7s/bin/ находятся программы, обеспечивающие работы kubernetes в rootless-режиме.

Для разворачивания master-узла запустите команду:

kubeadm init

По умолчанию уровень отладки устанавливается в 0. Если необходимо увеличить уровень отладки укажите перед подкомандой init флаг -v n. Где n принимает значения от 0 до 9-ти.

После:

  • генерации сертификатов в каталоге /etc/kuarnetes/pki,
  • загрузки образов,
  • генерации conf-файлов в каталоге /etc/kubernetes/manifests/, /etc/kubernetes/manifests/etcd/
  • запуска сервиса kubelet и Pod’ов системных kubernetes-образов

инициализируется kubernet-кластер из одного узла.

По окончании скрипт выводит строки подключения master(Control Plane) и worker-узлов:

You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

kubeadm join xxx.xxx.xxx.xxx:6443 --token ... --discovery-token-ca-cert-hash sha256:.. --control-plane

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join xxx.xxx.xxx.xxx:6443 --token ... --discovery-token-ca-cert-hash sha256:...

Запуск сетевого маршрутизатора для контейенеров kube-flannel

Для перевода узла в состояние Ready, запуска coredns Pod’ов запустите flannel.

На master-узле под пользоваталем root выполните команду:

# kubectl apply -f /etc/kubernetes/manifests/kube-flannel.yml
Connected to the local host. Press ^] three times within 1s to exit session.
[INFO] Entering RootlessKit namespaces: OK
namespace/kube-flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created
Connection to the local host terminated.

После завершения скрипта в течении минуты настраиваются сервисы мастер-узла кластера. По ее истечении проверьте работу usernetes (rootless kuber)


Проверка работы master-узла

На master-узле выполните команду:

# kubectl get daemonsets.apps -A
NAMESPACE      NAME              DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-flannel   kube-flannel-ds   1         1         1       1            1           <none>                   102s
kube-system    kube-proxy        1         1         1       1            1           kubernetes.io/os=linux   8h

Число READY каждого daemonset должно быть равно числу DESIRED и должно быть равно числу узлов кластера.

# kubectl get nodes -o wide
NAME       STATUS   ROLES           AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE           KERNEL-VERSION         CONTAINER-RUNTIME
<host>     Ready    control-plane   16m   v1.26.3   10.96.0.1     <none>        ALT SP Server 11100-01   5.15.105-un-def-alt1   cri-o://1.26.2

Проверьте работу usernetes (rootless kuber)

# kubectl get all -A
NAMESPACE     NAME                                   READY   STATUS    RESTARTS   AGE
kube-system   pod/coredns-c7df5cd6c-5pkkm            1/1     Running   0          19m
kube-system   pod/coredns-c7df5cd6c-cm6vf            1/1     Running   0          19m
kube-system   pod/etcd-host-212                      1/1     Running   0          19m
kube-system   pod/kube-apiserver-host-212            1/1     Running   0          19m
kube-system   pod/kube-controller-manager-host-212   1/1     Running   0          19m
kube-system   pod/kube-proxy-lqf9c                   1/1     Running   0          19m
kube-system   pod/kube-scheduler-host-212            1/1     Running   0          19m

NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  19m
kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   19m

NAMESPACE     NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
kube-system   daemonset.apps/kube-proxy   1         1         1       1            1           kubernetes.io/os=linux   19m

NAMESPACE     NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/coredns   2/2     2            2           19m

NAMESPACE     NAME                                DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/coredns-c7df5cd6c   2         2         2       19m

Состояние всех Pod’ов должны быть в 1/1.

Проверьте состояние дерева процессов:

# pstree
...
├─systemd─┬─(sd-pam)
│         ├─dbus-daemon
│         ├─nsenter.sh───nsenter───_kubelet.sh───kubelet───11*[{kubelet}]
│         └─rootlesskit.sh───rootlesskit─┬─exe─┬─conmon───kube-controller───7*[{kube-controller}]
│                                        │     ├─conmon───kube-apiserver───8*[{kube-apiserver}]
│                                        │     ├─conmon───kube-scheduler───7*[{kube-scheduler}]
│                                        │     ├─conmon───etcd───8*[{etcd}]
│                                        │     ├─conmon───kube-proxy───4*[{kube-proxy}]
│                                        │     ├─2*[conmon───coredns───8*[{coredns}]]
│                                        │     ├─rootlesskit.sh───crio───10*[{crio}]
│                                        │     └─7*[{exe}]
│                                        ├─slirp4netns
│                                        └─8*[{rootlesskit}]
...

Процесс kubelet запускается как сервис в user namespace процесса rootlesskit.

Все остальные процессы kube-controller, kube-apiserver, kube-scheduler, kube-proxy, etcd, coredns запускаются как контейнеры от соответствующих образов в user namespace процесса rootlesskit.

Обеспечение запуска обычных POD’ов на мастер-узле

По умолчанию на master-узле пользовательские Podы не запускаются. Чтобы снять это ограничение наберите команду:

# kubectl taint nodes <host> node-role.kubernetes.io/control-plane:NoSchedule-
node/<host> untainted

Инициализация и подключение worker-узла

Установите пакет podsec-k8s:

apt-get install podsec-k8s

Подключение worker-узлов

Скопируйте команду подключения worker-узла, полученную на этапе установки начального master-узла. Запустите ее:

kubeadm join xxx.xxx.xxx.xxx:6443 --token ... --discovery-token-ca-cert-hash sha256:...

По умолчанию уровень отладки устанавливается в 0. Если необходимо увеличить уровень отладки укажите перед подкомандой join флаг -v n. Где n принимает значения от 0 до 9-ти.

По окончании скрипт выводит текст:

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

Проверка состояния процессов

Проверьте состояние дерева процессов:

# pstree
...
├─systemd─┬─(sd-pam)
│         ├─dbus-daemon
│         ├─nsenter.sh───nsenter───_kubelet.sh───kubelet───10*[{kubelet}]
│         └─rootlesskit.sh───rootlesskit─┬─exe─┬─conmon───kube-proxy───4*[{kube-proxy}]
│                                        │     ├─rootlesskit.sh───crio───9*[{crio}]
│                                        │     └─6*[{exe}]
│                                        ├─slirp4netns
│                                        └─8*[{rootlesskit}]
...

Процесс kubelet запускается как сервис в user namespace процесса rootlesskit.

Все остальные процессы kube-proxy, kube-flannel запускаются как контейнеры от соответствующих образов в user namespace процесса rootlesskit.

Проверка готовности master и worker узлов kubernets

Зайдите на master-узел и проверьте подключение worker-узла:

# kubectl get nodes -o wide
NAME       STATUS   ROLES           AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                 KERNEL-VERSION         CONTAINER-RUNTIME
host-212   Ready    control-plane   7h54m   v1.26.3   10.96.0.1     <none>        ALT SP Server 11100-01   5.15.105-un-def-alt1   cri-o://1.26.2
host-226   Ready    <none>          8m30s   v1.26.3   10.96.0.1     <none>        ALT SP Server 11100-01   5.15.105-un-def-alt1   cri-o://1.26.2
...

Инициализация и подключение дополнительных master-узлов

Подключение master-узлов

Проверка состояния процессов

Проверка готовности master и worker узлов kubernets

Разворачивание rootless kubernetes кластера с балансировщиком REST-запросов haproxy

При подключении дополнительного control-plane(master)-узла необходимо

  • установить и настроить на один из улов в кластере или вне его haproxy для балансировки запросов;
  • переустановить начальный master-узел для работы с haproxy
  • подключать дополнительные control-plane(master)-узлы с указанием их в балансировщике запросов haproxy;
  • подключать дополнительные worker-узлы

Настройка балансировщика REST-запросов haproxy

Полная настройка отказоустойчивого кластера haproxy из 3-х узлов описана в документе ALT Container OS подветка K8S. Создание HA кластера.

Здесь же мы рассмотрим создание и настройка с одним сервером haproxy с балансировкой запросов на master-узлы.

Установите пакет haproxy:

# apt-get install haproxy

Отредактируйте конфигурационный файл /etc/haproxy/haproxy.cfg:

  • добавьте в него описание frontend’a main, принимающего запросы по порту 8443:
     frontend main
      bind *:8443
      mode tcp
      option tcplog
      default_backend apiserver
    
  • добавьте описание backend’а apiserver:
    backend apiserver
      option httpchk GET /healthz
      http-check expect status 200
      mode tcp
      option ssl-hello-chk
      balance     roundrobin
          server master01 <IP_или_DNS_начального_мастер_узла>:6443 check
    
  • запустите haproxy:
# systemctl enable haproxy
# systemctl start haproxy

Настройка отказоустойчивого кластера серверов haproxy, keepalived

Поддержка управление доступом на основе ролей (RBAC)

Мониторинг безопасности системы

Особенности разворачивания приложений kubernetes

При использовании сервисов типа NodePort поднятые в рамках кластера порты в диапазоне 30000-32767 остаются в namespace пользователя u7s-admin. Для их проброса наружу необходимо в пользователе u7s-admin запустить команду:

$ nsenter_u7s rootlessctl add-ports 0.0.0.0:<port>:<port>/tcp

Сервисы типа NodePort из за их небольшого диапазона и "нестабильности" портов при переносе решения в другой кластер довольно редко используются. Рекомендуется вместо них использовать сервисы типа ClusterIP c доступом к ним через Ingress-контроллеры.

Установка и настройка ingress-контролера

Выбор регистратора образов

Пакет обеспечивает загрузку kubernet-образов с регистраторов различного уровня. Уровень регистратора определяется переменной среды U7S_REGISTRY. Переменная может принимать нижеописанные основные значения.

Native kubernetes регистратор

export U7S_REGISTRY=

Если переменная U7S_REGISTRY установлена в пустое значение образы загружаются со стандартного регистратора образов kubernetes.

Регистратор altlinux

С регистратора altlinux устанавливаются образы для которых не требуются ограничения политики доступа для различных категория пользователей:

  • export U7S_REGISTRY=registry.altlinux.org/k8s-c10f1 - образы для сертфицированного дистрибутива c10;
  • export U7S_REGISTRY=registry.altlinux.org/k8s-p10 - образы для несертфицированного дистрибутива p10.

Локальный регистратор

C локального регистраторе, как правило, устанавливается подписанные образы с ограничением политики доступа для различных категория пользователей, устанавливаемые скриптами пакета podsec. Это образы загружаются с регистратора registry.local пользователем группы podsec_dev, подписываются и загружаются в локальный регистратор registry.local. Подробности по установке rootless kubernetes в этом режиме описаны в документе Установка и настройка U7S (rootless kuber).

  • export U7S_REGISTRY=registry.local/k8s-c10f1 - образы для сертфицированного дистрибутива c10;
  • export U7S_REGISTRY=registry.local/k8s-p10 - образы для несертфицированного дистрибутива p10.

Настройка политики доступа к образам различным категориям пользователей

Поддержка электронной подписи образов

Автоматический выбор регистратора образов

Если переменная U7S_REGISTRY не установлена, ее значения вычисляется автоматически по следующему алгоритму:

  • Если файл /etc/hosts содержит описание хоста registry.local префикс переменной U7S_REGISTRY принимает значение registry.local/, иначе registry.altlinux.org/.
  • Если переменная CPE_NAME файла /etc/os-release содержит значение spserver суффикс переменной U7S_REGISTRY принимает значение k8s-c10f1, иначе k8s-p10.