ОС Альт СП Kubernetes
Используемые инструменты контейнеризации
В настоящее время для разворачивания решений контейнеризации используются два основных альтернативных инструментария:
- dockerd, containerd (serverfull) - серверный вариант запуска контейнеров. Клиенты через CLI-команду docker обращаются к dockerd-демону, который через сервис containerd запускает контейнеры.
- podman, cri-o (serverless) - CLI-команда podman и kubernetes-движок cri-o непосредственно запускают контейнеры бех обращения к серверу.
В рамках дистрибутива ALTLinux реализовано решение podman, cri-o по следующим причинам:
- podman, cri-o поддерживают политики контейнеризации, позволяющие организовать группы пользователей с разными правами доступа к docker-образам при запуске контейнеров. Это обеспечивает поддержку «Требования по безопасности информации к средствам контейнеризации» приказа № 118 ФСТЭК России.
- podman, cri-o по своей идеологии разработки (serverless) поддерживают rootless-режим запуска контейнеров.
rootfull и rootless режим запуска контейнеров
podman
CLI команда podman является аналогом CLI команды docker и поддерживает аналогичный набор параметров. Команда docker для запуска контейнеров обращается к dockerd-демону, работающему на том же или другом компьютере. Контейнер запускается на том же узле, где работает демон dockerd обычно с правами root. В этом случае все контейнеры запускаются в rootfull режиме независимо от какого пользователя запущена CLI команда docker.
CLI команда podman запускает контейнеры на том же узле, где была запущена не обращаясь к отдельному демону. Контейнеры запускаются с правами того пользователя, от имени которого была запущена команда podman. Это позволяет организовать как rootfull, так и rooless режим запуска контейнера.
rootfull режим запуска контейнеров
До появления группы команд podsec, cri-o все контейнеры запускались в rootfull режиме.
Основное отличие rootfull режима от rottless - запуск образов в которых в качестве пользователя указан пользователь root.
# podman inspect <образ> | jq .[0].User
root
В rootfull режиме процесс работающий в контейнере работает от имени пользователя root с идентификатором (UID) 0. Причем и в рамках HOST-системы в которой запущен контейнер это процесс также имеет идентификатор UID=0. Если в контейнер примонтирован каталог HOST-системы, то злоумышленник через команду
podman exec -i <id_conteiner> rm -rf <каталог_монтирования>
может удалить монтируемый каталог HOST-системы или изменить его.
rootless режим запуска контейнеров
rootless режим запуска контейнеров позволяет запускать образы в которых в качестве пользователя указан пользователь root таким образом, что процесс работающий в контейнере работает от имени пользователя root с идентификатором (UID), а в рамках HOST системы этом процесс имеет идентификатор пользователя который запустил данный контейнер.
Данный режим доступен для пользователей входящих в группу podman.
Он включается командой:
# control newgidmap podmanonly # control newuidmap podmanonly
Эти команды для команд /usr/bin/newuidmap, /usr/bin/newguidmap устанавливают флаг cap_setuid=ep при котором они запускаются с правами root для пользователей, входящих в группу podman:
# ls -l /usr/bin/newuidmap /usr/bin/newgidmap -rwx--x--- 1 root podman 41440 апр 26 2024 /usr/bin/newgidmap -rwx--x--- 1 root podman 41440 апр 26 2024 /usr/bin/newuidmap # getcap /usr/bin/newuidmap /usr/bin/newgidmap /usr/bin/newuidmap cap_setuid=ep /usr/bin/newgidmap cap_setgid=ep
kubernetes
Системные требования
Минимальные системные требования:
- 2GB ОЗУ или больше;
- 2 ядра процессора или больше;
- Все машины должны быть доступны по сети друг для друга;
- Все машины должны успешно разрешать имена hostname друг друга (через DNS или hosts);
- Своп должен быть выключен.
Для разворачивания нижеописанных кластеров достаточно несколько (две и более) машин (nodes), одна из которых будет мастер (controlplane)-узлом. Остальные узлы будут рабочими (worker).
controlplane-узлы обеспечивают управление кластером и поддерживают по порту 6443 kubernetes API.
Работа с кластером (создание deployment's, replicasetreplicaset's, podreplicaset's, configmap's, ...) производится через этот API либо внешними приложениями либо через CLI команду kubeclt.
Если разворачивается более одного controlplane-узла, то необходимо либо вручную перераспределять запросы к ним, либо разворачивать в рамках кластера балансировщик для равномерного распределения API-запросов между controlplane-узлами кластера.
Все пользовательские POD'ы (контейнеры) разворачиваются на worker узлах.
В связи с этим при необходимости для них можно выделить большее количество оперативной, дисковой памяти и большее число ядер процессора.
Если на controlplane-узлах не предполагается большой нагрузки, то их можно перестроить на поддержку в том числе и пользовательских POD'ов. В этом случае "kubernetes-кластер" можно развернуть и на одном узле.
Варианты разворачивания ОС Альт СП kubernetes
Режим работы пользователя root кластера:
- rootfull режим - пользователь root кластера и контейнеров в нем имеет равные права с пользователем root HOST-системы.
- rootless режим - пользователь root кластера и контейнеров в нем имеет права обычного пользователя в HOST-системе (fake-root).
Использование политик доступа:
- В незащищенном режиме.
- В защищенном режиме с использованием политик доступа.
Использование регистраторов:
- внешний регистратор ;
- внутренний регистратор registry.local или комбинированный вариант;
rootfull kubernetes
При разворачивании kubernetes кластера в rootfull режиме на каждом узле systemd-сервис kubelet разворачивается с привелегиями пользователя root. Остальные сервисы кластера, разворачиваемые сервисом kubelet из docker-образов kubernetes также разворачиваются с привелегиями пользователя root.
Все PODы, запускаемые в рамках кластера от docker-образов с пользователем root (например стандартный образ nginx) также имеют привелегии пользователя root HOST-системы.
Работа в режиме rootfull несет определенные риски, так как злоумышленник может в POD'е с привелегиями root примонтировать каталог файловой системы HOST-узла (включая корневой) и получить доступ с правами root к файлам этого каталога вплоть до их удаления.
В kubernetes версии 1.33 и старше появилась возможность запуска POD'ов в rootless-режиме. Но это касается только POD'ов пользователя. Системные kubernetes POD'ы работают c приведениями пользователя root и при наличии в них уязвимостей злоумышленник может их использовать для атаки на kubernetes-кластер.
Для исключения этих уязвимостей есть возможность разворачивать кластер в rootless-режиме. Этот вариант разворачивания описал в главе [1]. Этот вариант разворачивания также позволяет:
- Создавать пользователей классов:
- Администратор кластера - управление кластером, создание пользователей, мониторинг работы кластера.
- Создатель образов - создание образов, их подпись и помещение в docker-регистратор.
- Пользователь образов - запуск POD'ов подписанных образов только с ограниченного перечня docker-регистраторов.
- Мониторить состояние кластере на предмет:
- наличия уязвимостей в образах и контейнерах;
- подозрительных изменений в каталогах работающего POD'аж
- изменения политик безопасности;
- подозрительных запросов к API-кластера;
- и другие
Перечисленные возможности также можно развернуть и в режиме rootfull. Далее рассматриваются все варианты разворачивания с их применением.
rootless Kubernetes (podsec-k8s)
При разворачивании kubernetes кластера в rootless режиме на каждом узле systemd-сервис kubelet разворачивается командой nsenter с окружении обычного пользователя u7s-admin. Остальные сервисы кластера, разворачиваемые сервисом kubelet из docker-образов kubernetes также разворачиваются командой rootlessctl в окружени пользователя u7s-admin.
Все PODы, запускаемые в рамках кластера от docker-образов с пользователем root (например стандартный образ nginx) в рамках POD'а имеют владельца root с идентификтором UID=0, позволяющего работать с ядром системы с привелегиями суперпользователя.
В рамках же HOST-системы POD работает с привелегиями обычного пользователя u7s-admin с идентификтором UID=486.
Это значительно снижает поверхность атаки на кластер, так как злоумышленник, войдя в контейнер может нарушить его работу, но в рамках HOST-системы имея права обычного пользователя он не сможет существенно нарушить работу системы.
Для разворачивание rootless кластера необходимо установить необходимые RPM-пакеты командой:
apt-get install podsec podsec-k8s podsec-inotify
Разворачивание rootless kubernetes возможно в следующих режимах:
- На платформах c10f в защищенном режиме с ISO-диска в локальной сети без доступа в Интернет;
- На платформах ALTLinux p10, p11, ... с использованием внешнего docker-регистратора kubernetes образов.
В свою очередь на платформах ALTLinux p10, p11, ... возможно разворачивание как в защищенном, так и незащищенном режиме.
Защищенный режим предполагает наличие политик доступа, обеспечивающих наличие классов пользователей с различными правами доступа:
Администратор- создание пользователей других классов, мониториг работы кластера.Создатель образов- создание образов, их подписывание и размещение на локальном или внешнем регистраторе.Пользователь образов- запуск POD'ов, Deployments, RepliceSets, ... на основе подписанных образов на локальном или внешнем регистраторе.
Пользователь образов и Администратор могут использовать в своей работе только подписанные образы и только с сконфигурированного регистратора. При ручной правке конфигураций есть возможность использовать нескольких регистраторов с образами подписанными несколькими пользователями класса Создатель образов.
При разворачивании rootless kubernetes с доступом в Интернет можно использовать различные регистраторы docker-образов:
- ALTLinux - docker-регистратор registry.altlinux.org (по умолчанию);
- Нативный kubernetes - docker-регистратор registry.k8s.io;
- Другие docker-регистраторы образов kubernetes.
Балансироващик REST-запросов к кластеру
Установка балансировщика REST-запросов haproxy
Если в вышеописанных вариантах разворачивания rootfull Или rootless-кластера устанавливается более одного controlplane узла, то по умолчанию распределять API-запросы к этим узлам кластера необходимо вручную.
Ручная балансировка запросов к API-интерфейсам master-узлов путем указания у клиентов адресов различных
master-узлов довольно неудобна, так как не обеспечивает равномерного распределения запросов по узлам кластера и не обеспечивает автоматической отказоустойчивости при выходе из строя master-узлов.
Решает данную проблему установка балансировщика нагрузки haproxy.
Перевод кластера в режим балансировки запросов через haproxy возможен, но данная процедура не гарантирует корректный перевод на всех версиях kubernetes и ее не рекомендуют применять на production кластерах.
Так что наиболее надежным способом создания кластера с балансировкой запросов является создание нового кластера.
Настройка балансировщика REST-запросов haproxy
Балансировщик REST-запросов haproxy можно устанавливать как на отдельный сервер, так на один из серверов кластера.
Если балансировщик устанавливается на
rootlessсервер кластера, то для балансировщика необходимо выделить отдельный IP-адрес. Если на этом же сервере функционируют локальный регистратор (registry.local) и сервер подписей (sigstore.local), то IP-адрес балансировщика может совпадать c IP-адресами этих сервисов.
Если планируется создание отказоустойчивого решения на основе нескольких серверов
haproxy, то для них кроме собственногоIP-адресанеобходимо будет для всех серверовhaproxyвыделить один общийIP-адрес, который будет иметьmaster-балансировщик.
Полная настройка отказоустойчивого кластера haproxy из 3-х узлов описана в документе ALT Container OS подветка K8S. Создание HA кластера.
Здесь же мы рассмотрим создание и настройка с одним сервером haproxy с балансировкой запросов на master-узлы.
Установите пакет haproxy:
# apt-get install haproxy
Отредактируйте конфигурационный файл /etc/haproxy/haproxy.cfg:
- добавьте в него описание
frontend’amain, принимающего запросы по порту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 server master02 <IP_или_DNS_второго_мастер_узла>:6443 check ...
- запустите
haproxy:
# systemctl enable haproxy # systemctl start haproxy
Настройка отказоустойчивого кластера серверов haproxy, keepalived
Масштабирование haproxy, установка пакетов
Если необходимо создать отказоустойчивое решение допускающее выход haproxy-севрера из строя
установите haproxy на несколько серверов. Файлы конфигурации haproxy<.code> на всех сервервх должны быть идентичны.
Для контроля доступности haproxy и переназначений виртуального адреса дополнительно установите на каждом сервис keepalived:
# apt-get install haproxy keepalived
Конфигурирование keepalived
Создайте файл конфигурации 'keepalived' /etc/keepalived/keepalived.conf:
! /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
router_id LVS_K8S
}
vrrp_script check_apiserver {
script "/etc/keepalived/check_apiserver.sh"
interval 3
weight -2
fall 10
rise 2
}
vrrp_instance VI_1 {
state MASTER
interface br0
virtual_router_id 51
priority 101
authentication {
auth_type PASS
auth_pass 42
}
virtual_ipaddress {
10.150.0.160
}
track_script {
check_apiserver
}
}
На одном из узлов установите параметр state в значение MASTER и параметр priority в значение 101.
На остальных параметр state в значение BACKUP и параметр priority в значение 100.
Скрипт /etc/keepalived/check_apiserver.sh проверяет доступность балансировщика haproxy:
#!/bin/sh
errorExit() {
echo "*** $*" 1>&2
exit 1
}
APISERVER_DEST_PORT=8443
APISERVER_VIP=10.150.0.160
curl --silent --max-time 2 --insecure https://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://localhost:${APISERVER_DEST_PORT}/"
if ip addr | grep -q ${APISERVER_VIP}; then
curl --silent --max-time 2 --insecure https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET https://${APISERVER_VIP}:${APISERVER_DEST_PORT}/"
fi
Параметр APISERVER_DEST_PORT задает порт балансировщиков haproxy, параметр APISERVER_VIP виртуальный адрес,
через который будут взаимодействовать master (control plane) узлы кластера k8s.
Скрипт проверяет работоспособность haproxy на локальной машине.
Подробности см. на [[1]]
А если в настоящее время виртуальный адрес принадлежит текущему узлу, то и работоспособность haproxy через виртуальный адрес.
Добавьте флаг на выполнение скрипта:
chmod a+x /etc/keepalived/check_apiserver.sh
При работающем балансировщике и хотя бы одному доступному порту 6443 на master-узлах скрипт
должен завершаться с кодом 0.
Подробности см. на Keepalived
Разворачивание rootless кластера
Выбор варианта разворачивания
При разворачивании в режиме rootless в зависимости от использования локального регистратора docker-образов и применения политик доступа к ним можно обеспечить следующие варианты разворачивания rootless-кластера:
Варианты разворачивания rootless кластера
Локальный регистратор
Политики доступа
Примечание
Да
Да
Стандартный вариант при использовании команд пакета podsec-k8s: Возможность разворачивания в локальной сети без доступа в Интернет с поддержкой классов пользователей с ограничением доступа к docker-регистраторам
Да
Нет
Возможность разворачивания в локальной сети без доступа в Интернет. Политики доступа расширены или отсутствуют.
Нет
Да
Поддержка классов пользователей с ограничением доступа к docker-регистраторам. Политики доступа стандартные или расширены.
Нет
Нет
Стандартный вариант разворачивания rootfull-решений, но в поддержкой работы узлов кластера в rootless-режиме
Разворачивание с локальным регистратора и с политиками доступа в rootless режиме
Основной особенностью при разворачивании rootless кластера с ISO-диска в защищённом режиме без доступа в Интернет является то, что docker-образы загружаются командой podsec-load-sign-oci в локальный регистратор registry.local из каталога /media/ALTLinux/containers/ примонтированного диска.
Каталог содержит два файла-архива слоев образов в формате OCI:
base_amd64.tar.xz - базовые образы для создания новых образов;
k8s_amd64.tar.xz - kubernetes-образы для разворачивания кластера.
Разворачивании rootless кластера как и rootfull кластера производится через команду kubeadm. Формат вызова команды на Master ControlPlane, остальных ControlPlane's и Worker's аналогичен.
Основные отличия:
- Для
Master ControlPlane необходимо не один, а два IP-адреса.
- На
Master ControlPlane устанавливаются дополнительные сервисы.
- Запускается не нативная команда
kubeadm из каталога /usr/bin, а оболочка над ним, обеспечивающая создания rootless-окружения пользователя u7s-admin.
Дополнительные сервисы включают в себя:
- регистратор docker-образов с доменом
registry.local;
- WEB-сервер открытых ключей и
Container Network Policy с доменом sigstore.local;
- сервер анализа уязвимостей
trivy.
Установка пакетов
Установите пакеты podsec:
apt-get install podsec-k8s podsec podsec-k8s-rbac podsec-inotify trivy
Выделение IP адресов для Master ControlPlane
Из за особенностей rootless-режима для Master ControlPlane необходимо выделит два IP-адреса. Один адрес будет использоваться в rootless-окружения, второй для обращения к основным ControlPlane сервисам Master узла.
В качестве примера выделим два адреса (в общем случае метод выделения может быть другим):
- 192.168.122.70 - IP-адрес для rootless окружения;
- 192.168.122.80 - IP- адрес для обращения к основным ControlPlane сервисам Master узла.
Допустим мы имеем на узлу интерфейс enp1s0. В этом случае
структура файлов каталога /etc/net/ifaces/enp1s0 описания интерфейса ensp1s0
будет выглядеть следующим образом:
Файл options:
BOOTPROTO=static
TYPE=eth
CONFIG_WIRELESS=no
SYSTEMD_BOOTPROTO=static
CONFIG_IPV4=yes
DISABLED=no
NM_CONTROLLED=no
SYSTEMD_CONTROLLED=no
Файл ipv4address:
192.168.122.70/24
192.168.122.80/24
Файл ipv4route:
default via 192.168.122.1
Файл resolv.conf:
nameserver 192.168.122.1
После конфигурации данных файлов необходимо перезагрузить узел.
Интерфейс для данных параметров после перезагрузки выглядит следующим образом:
# ip a show dev enp1s0
2: enp1s0: mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 52:54:00:db:e1:57 brd ff:ff:ff:ff:ff:ff
inet 192.168.122.70/24 brd 192.168.122.255 scope global enp1s0
valid_lft forever preferred_lft forever
inet 192.168.122.80/24 brd 192.168.122.255 scope global secondary enp1s0
valid_lft forever preferred_lft forever
...
Создание файлов конфигурации Container Network Policy на Master ControlPlane в rootless режиме
Для создания Container Network Policy на Master узле вызовите команду:
# podsec-create-policy 192.168.122.70 # ip-aдрес_регистратора и WEB-сервера подписей
Добавление привязки доменов registry.local sigstore.local trivy.local к IP-адресу 192.168.122.70
Создание группы podman
Инициализация каталога /var/sigstore/ и подкаталогов хранения открытых ключей и подписей образов
Создание каталога и подкаталогов /var/sigstore/
Создание группы podman_dev
Создание с сохранением предыдущих файла политик /etc/containers/policy.json
Создание с сохранением предыдущих файл /etc/containers/registries.d/default.yaml описания доступа к открытым ключам подписантов
Добавление insecure-доступа к регистратору registry.local в файле /etc/containers/registries.conf
Настройка использования образа registry.local/k8s-c10f1/pause:3.9 при запуска pod'ов в podman (podman pod init)
После выполнения команды:
- файл /etc/host должен содержать строку:
...
192.168.122.70 registry.local sigstore.local trivy.local
- файл /etc/containers/policy.json, являющийся symlink'ом к файлу /etc/containers/policy_YYYY-MM-DD_HH:mm:SS должен иметь содержимое (запрет доступа по всем ресурсам):
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {}
}
}
- файл /etc/containers/registries.d/default.yaml, являющийся symlink'ом к файлу /etc/containers/registries.d/default_YYYY-MM-DD_HH:mm:SS должен иметь содержимое (ю URLs доступа к серверу подписей):
default-docker:
lookaside: http://sigstore.local:81/sigstore/
sigstore: http://sigstore.local:81/sigstore/
Данные файлы конфигурируют сервис cri-o, который контролирует доступ к docker-образам согласно указанным политикам.
На данный момент файл /etc/containers/policy.json запрещает доступ к образам по всем видам транспортов, кроме доступа к docker-регистраторам. На данный момент список регистраторов пуст.
Разворачивание дополнительных сервисов на Master ControlPlane в rootless режиме
Для разворачивание дополнительных сервисов на Master ControlPlane поднимите сервисы регистратора и WEB-сервера подписей командой:
# podsec-create-services
Synchronizing state of nginx.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable nginx
Created symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /lib/systemd/system/nginx.service.
registry
Created symlink /etc/systemd/system/multi-user.target.wants/docker-registry.service → /lib/systemd/system/docker-registry.service.
Проверьте функционирование сервисов:
# netstat -nlpt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
...
tcp 0 0 0.0.0.0:81 0.0.0.0:* LISTEN 14996/nginx -g daem
...
tcp 0 0 :::80 :::* LISTEN 15044/docker-regist
...
tcp 0 0 :::4954 :::* LISTEN 30864/trivy
...
Порт 81 должен слушать сервис nginx. Порт 80 ервис docker-registry. Порт 4954 сервис trivy.
Создание на Master ControlPlane пользователей различных классов
При разворачивании kubernetes в rootless режиме в системе могут существовать пользователи нескольких классов:
- Администратор системы - пользователь root.
- Создатель образов контейнеров.
- Пользователь информационной системы.
- Обычный пользователь.
Администратор системы
Роль администратора системы выполняет пользователь root:
- имеющий права создавать других пользователей
- имеющий права просматривать системные логи в том числе логи по безопасности;
- не имеющий права создавать новые образы и
- может (как и пользователь информационной системы) использовать только подписанные образы образы с регистратора registy.local.
Создание пользователя разработчика образов контейнеров
Разработчика образов контейнеров в отличие от других пользователей имеет доступ ко всем образам по всем протоколам.
Это необходимо для возможности создания новых образов для локального регистратора registry.local.
Кроме этого пользователь этого класса при создании формирует электронную подпись, которую может использовать
при размещении образов на регистраторе registry.local.
Открытые ключи всех разработчиков образов для проверки подписи при их загрузке с регистратора registry.local хранятся
в каталоге /var/sigstore/keys.
Для создания пользователя разработчик образов контейнеров выполните команду указав имя пользователя (обычно imagemaker):
# podsec-create-imagemakeruser <имя_пользователя_создателя образов>
Во время выполнения команды необходимо:
- дважды ввести пароль для пользователя;
- выбрать тип и длину GPG-ключа;
- указать срок действия ключа;
- ввести E-mail для ключа;
- ввести пароль для подписывания образа.
Файл /etc/containers/policy.json, должен изменить symlink на другой файл /etc/containers/policy_YYYY-MM-DD_HH:mm:SS с содержимым (разрешение доступа к регистратору registry.local с открытым ключом пользователя imagemaker):
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
"registry.local": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/var/sigstore/keys/imagemaker.pgp"
}
]
}
}
}
Должен появится каталог /var/sigstore/ со следующей структурой:
├── index.html
├── keys
│ ├── imagemaker.pgp
│ └── policy.json
└── sigstore
Проверьте доступ к этому каталогу через http:
# curl -s http://sigstore.local:81/keys/ | jq
[
{
"name": "imagemaker.pgp",
"type": "file",
"mtime": "Tue, 23 May 2023 05:43:59 GMT",
"size": 2436
},
{
"name": "policy.json",
"type": "file",
"mtime": "Tue, 23 May 2023 05:43:25 GMT",
"size": 276
}
]
Команду podsec-create-imagemakeruser можно запускать без параметров или задать несколько пользователей этого класса.
При запуска без параметров создается пользователь с именем imagemaker.
При необходимости задания нескольких пользователей к имени каждого пользователя должен быть добавлен суффикс @registry.local для указания, что все подписанные ими образы помещаются в регистратор registry.local.
Вызов в этом случае выглядит так:
# podsec-create-imagemakeruser <имя_пользователя1>@registry.local <имя_пользователя2>@registry.local ...
Создание пользователя информационной системы
Пользователь информационной системы имеет право запускать только подписанные образы с локального регистраторв registry.local.
Для создания пользователя информационной системы вызовите команду:
# podsec-create-podmanusers <имя_пользователя_информационной_системы1> [<имя_пользователя_информационной_системы2> ...]
Во время выполнения команды необходимо дважды ввести пароль для пользователя
Обычный пользователь
Обычный пользователь также
имеет право запускать только подписанные образы с локального регистраторв registry.local, но для него
корректный запуск контейнеров командами podman, crictl, ... не гарантируется.
Создается он обычными командами создания пользователей системы.
Доступ к OCI-архиву базовых и kubernetes образов
Методы получения OCI-архивов
OCI-архивы базовых и kubernetes образов располагаются на ISO-диске в каталоге containers под именами base_amd64.tar.xz и
k8s_amd64.tar.xz соответственно.
Их следует скопировать в домашний каталог пользователя разработчика образов контейнеров.
Вы можете самостоятельно сформировать эти архивы для разворачивания последней доступной версии kubernetes.
Формирование OCI-архива kubernetes-образов с регистратора registry.altlinux.org
Для подъема регистратора docker-образов необходимо проверить наличие и при необходимости установить установить пакет podsec-dev и пакеты podsec-k8s podsec:
apt-get install podsec-dev podsec-k8s podsec
OCI-архив kubernetes-образов представляет собой сжатый командой xz tar-архив
каталога kubernetes образов в формате OCI.
Хранение в формате OCI позволяет минимизировать размер архива с нескольких гигабайт до 2-х сотен мегабайт. Это достигается за счет того, что OCI-каталоге образов каждый слой образов встречается однократно. А так как kubernetes-образы имеют много общих слоев, размер OIC-каталога в несколько раз меньше, чем суммарный объем архивов образов, сохраненных командой podman save. Кроме того образы, записываются в OCI-архив с несжатыми слоями. Это позволяет эффективно их сжимать компрессором xz.
Для формирования OCI-архива kubernetes-образов из под пользователя root:
- перейдите в каталог /root
- если в каталоге уже существует подкаталог k8s_amd64 переименуйте его или удалите;
- вызовите команду:
podsec-k8s-save-oci k8s_amd64 amd64
- Первым параметром указывается имя каталога в который помещается архив amd64.tar.xz или arm64.tar.xz в зависимости от архитектуры.
- Вторым - имя архитектуры (amd64 или arm64).
Команда:
- устанавливает последние версии пакетов kubeadm, crio;
- определяет список kubernetes-образов последней версии, включая образы etcd и flannel;
- скачивает их с регистратора registry.altlinux.org и помещает в каталог /root/.local/share/usernetes/images/c10f/amd64/ в формате
containers-storage;
- копирует образы из каталога /root/.local/share/usernetes/images/c10f/amd64/ в каталог k8s_amd64/amd64 в формате
oci;
- по окончании копирования всех образов архивирует каталог k8s_amd64/amd64 командой tar, сжимает архив и помещает в файл amd64.tar.xz указанного каталога k8s_amd64.
Для архивации других образов (например базовых c10f/distroless-base, c10f docker-регистратора registry.altlinux.org) необходимо в переменной U7S_ALTREGISTRY указать имя docker-регистратора и вызвать команду podsec-save-oci.
export U7S_ALTREGISTRY=registry.altlinux.org
podsec-save-oci base_amd64 amd64 '' c10f/distroless-base c10f/alt
- Первым параметром указывается имя каталога в который помещается архив amd64.tar.xz.
- Вторым - имя архитектуры (amd64 или arm64).
- Третьим - тип транспорта (по умолчанию docker://).
- В последующих параметрах указываются список архивируемых образов.
Команда:
- устанавливает последние версии пакетов kubeadm, crio;
- принимает список архивируемых образов;
- скачивает их с указанного переменной среды U7S_ALTREGISTRY регистратора и помещает в каталог /root/.local/share/usernetes/images/c10f/amd64/ в формате
containers-storage;
- копирует образы из каталога /root/.local/share/usernetes/images/c10f/amd64/ в каталог k8s_amd64/amd64 в формате
oci;
- по окончании копирования всех образов архивирует каталог k8s_amd64/amd64 командой tar, сжимает архив и помещает в файл amd64.tar.xz указанного каталога base_amd64.
Если Вам необходимо архивировать образы архитектуры arm64 укажите вторым параметром команд arm64.
Полученные OCI-архивы следует скопировать в домашний каталог пользователя разработчика образов контейнеров.
Подписывание образов и размещения на локальном регистраторе
Загрузите kubernetes-образы от пользователя imagemaker.
$ podsec-load-sign-oci <имя_файла_OCI-архива> amd64 <E-mail_подписанта>
Во время выполнения скрипта будет запрошен пароль для подписи.
Внимание: Данную команду нельзя запускать путем получения прав пользователя через команду su - imagemaker, так как устанавливаются не все переменные среды. Сделайте полный заход под пользователем, например по протоколу ssh:
# ssh imagemaker@localhost
или через machinectl:
# machinectl shell imagemaker@
После выполнения скрипта проверьте наличие образов в регистраторе:
# curl -s registry.local/v2/_catalog | jq
{
"repositories": [
"c10f/coredns",
"c10f/etcd",
"c10f/flannel",
"c10f/flannel-cni-plugin",
"c10f/kube-apiserver",
"c10f/kube-controller-manager",
"c10f/kube-proxy",
"c10f/kube-scheduler",
"c10f/pause",
"k8s-c10f2/coredns",
"k8s-c10f2/etcd",
"k8s-c10f2/flannel",
"k8s-c10f2/flannel-cni-plugin",
"k8s-c10f2/kube-apiserver",
"k8s-c10f2/kube-controller-manager",
"k8s-c10f2/kube-proxy",
"k8s-c10f2/kube-scheduler",
"k8s-c10f2/pause"
]
}
Внимание: Кроме образов с префиксом c10f/ в результате запроса могкт быть отображены образы с префиксами k8s-c10f1, k8s-c10f2. Это связано с обеспечением совместимости предыдущего способа именования префикса образов k8s-c10f1<N> и текущего c10f.
Проверьте наличие подписей в каталоге /var/sigstore/sigstore/k8s-c10f2:
# tree /var/sigstore/sigstore/c10f/
/var/sigstore/sigstore/c10f/
├── coredns@sha256=...
│ └── signature-1
├── etcd@sha256=...
│ └── signature-1
├── flannel-cni-plugin@sha256=...
│ └── signature-1
├── flannel@sha256=...
│ └── signature-1
├── kube-apiserver@sha256=...
│ └── signature-1
├── kube-controller-manager@sha256=...
│ └── signature-1
├── kube-proxy@sha256=...
│ └── signature-1
├── kube-scheduler@sha256=...
│ └── signature-1
└── pause@sha256=...
└── signature-1
Число подкаталогов должно совпадать с числом образов в регистраторе и каждый подкаталог должен иметь файл signature-1.
Создание дополнительных образов и размещение их в локальном регистраторе
Копирование образов с других регистраторов
Для копирования образа (например nginx) с внешнего регистратора загрузите его в пользователе разработчика образов контейнеров:
[imagemaker@master1 ~]$ podman pull registry.altlinux.org/c10f/nginx:1.26.3
Trying to pull registry.altlinux.org/c10f/nginx:1.26.3...
Getting image source signatures
Copying blob 1bc1a80e4a16 done |
Copying blob 82e02127e2b4 skipped: already exists
Copying blob 98ed66316f15 done |
Copying blob a2bb93664add skipped: already exists
Copying blob b43be2116c2b done |
Copying blob 4df9de94b01c done |
Copying blob 5c2c8c67033f done |
Copying config d8a1de134d done |
Writing manifest to image destination
d8a1de134d2ea60956f987b6c47acdac0e8dcc863c6a98e16210f9a82e860932
Навешайте на него тег с именем локального регистратора registry.local:
[imagemaker@master1 ~]$ podman tag registry.altlinux.org/c10f/nginx:1.26.3 registry.local/c10f/nginx:1.26.3
Поместите образ в локальный регистратор, указав в флаге --sign-by E-mail пользователя введенные при создании ключей пользователя:
[imagemaker@master1 ~]$ podman push --tls-verify=false --sign-by="..." registry.local/c10f/nginx:1.26.3
Во время выполнения скрипта будет запрошен пароль, указанный при создании ключей подписи.
Getting image source signatures
Copying blob f0e31397ae37 done |
Copying blob 60204c5adf60 done |
Copying blob 9a0fa9f6d6ea done |
Copying blob 5957b6b3c861 done |
Copying blob f06afe809992 done |
Copying blob e268fece4a97 done |
Copying blob 6cb900dcc924 done |
Copying config d8a1de134d done |
Writing manifest to image destination
Creating signature: Signing image using simple signing
Storing signatures
Создание собственных образов
Создайте каталог (например net-tools) для хранения артефактов образа и перейдите в него:
[imagemaker@master1]$ mkdir net-tools
[imagemaker@master1]$ cd net-tools
Сформируйте Dockerfile:
FROM registry.altlinux.org/c10f/alt
RUN apt-get update && \
apt-get install -y tcpdump nmap bind-utils
Создайте от образа registry.altlinux.org/c10f/alt дочерний образ registry.local/net/net-tools:
[imagemaker@master1 net-tools]$ podman build -t registry.local/net/net-tools .
STEP 1/2: FROM registry.altlinux.org/c10f/alt
STEP 2/2: RUN apt-get update && apt-get install -y tcpdump nmap bind-utils
Get:1 http://update.altsp.su c10f2/branch/x86_64 release [3576B]
...
Fetched 46.1MB in 11s (3845kB/s)
Reading Package Lists...
Building Dependency Tree...
Reading Package Lists...
Building Dependency Tree...
The following extra packages will be installed:
...
Done.
COMMIT registry.local/net/net-tools
--> 06c7112c2901
Successfully tagged registry.local/net/net-tools:latest
Поместите образ в локальный регистратор, указав в флаге --sign-by E-mail пользователя введенные при создании ключей пользователя:
podman push --tls-verify=false --sign-by="kaf@basealt.ru" registry.local/net/net-tools:latest
Во время выполнения скрипта будет запрошен пароль, указанный при создании ключей подписи.
Getting image source signatures
Copying blob 9a0fa9f6d6ea done |
Copying blob 08347d1dc3ae done |
Copying blob 5957b6b3c861 done |
Copying config 06c7112c29 done |
Writing manifest to image destination
Creating signature: Signing image using simple signing
Storing signatures
Разворачивание Master ControlPlane узла
Инициализация
Измените переменную PATH:
export PATH=/usr/libexec/podsec/u7s/bin/:$PATH
Запустите команду:
# kubeadm -v 9 init --apiserver-advertise-address 192.168.122.80
При запуске в параметре --apiserver-advertise-address укажите IP-адрес API-интерфейса kube-apiserver. Этот адрес должен отличаться от IP-адреса регистратора и WEB-сервера подписей.
Внимание: По умолчанию уровень отладки устанавливается в 0. Если необходимо увеличить уровень отладки укажите перед подкомандой init флаг -v n. Где n принимает значения от 0 до 9-ти.
Внимание: При запуске с балансировщиком запросов haproxy необходимо дополнительно указать параметр --control-plane-endpoint:
# kubeadm init --apiserver-advertise-address 192.168.122.80 --control-plane-endpoint <IP_адрес_haproxy>:<PORT_haproxy>
После:
- генерации сертификатов в каталоге /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:...
Запомните команды kubeadm join ... подключения controplane и worker узлов.
Для проверки состояния kubernetes из одного 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
NAME STATUS ROLES AGE VERSION
host-... Ready control-plane ... v1.xx.x
Проверьте работу всех ресурсов:
# 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.
Проверьте состояние дерева rootless-процессов:
# 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’ов на мастер-узле
Установка режима запуска на Controlplane пользовательских POD'ов
По умолчанию на master-узле пользовательские Podы не запускаются. Если необходимо снять это ограничение наберите команду:
# kubectl taint nodes <host> node-role.kubernetes.io/control-plane:NoSchedule-
node/<host> untainted
Где <host> - имя master-узла, отображаемое в выводе команды:
# kubectl get nodes
Подключение ControlPlane и Worker узлов
Установка пакетов
Установите пакеты podsec необходимые для функционировния узла.
# apt-get install podsec-k8s podsec podsec-inotify
Создание файлов конфигурации Container Network Policy на ControlPlane или Worker в rootless режиме
Для создание файлов конфигурации подключаемого узла вызовите команду:
# podsec-create-policy <IP_адрес_MASTER_Controlplane_узла>
Добавление привязки доменов registry.local sigstore.local trivy.local к IP адресу 192.168.122.70
Создание группы podman
Инициализация /var/sigstore/ каталога /var/sigstore/ и подкаталогов хранения открытых ключей и подписей образов
Создание каталога и подкаталогов /var/sigstore/
Создание с сохранением предыдущего файла политик /etc/containers/policy.json
Создание с сохранением предыдущего файла /etc/containers/registries.d/default.yaml описания доступа к открытым ключам подписантов
Добавление insecure-доступа к регистратору registry.local в /etc/containers/registries.conf file
Команда произведен действия аналогичные действиям команды на Master ControlPlane узле, но файл конфигурации
/etc/containers/policy.json скопирует с Master узла.
Подключение узла к кластеру
Измените переменную PATH:
export PATH=/usr/libexec/podsec/u7s/bin/:$PATH
Для подключения Controlplane или Worker узла к кластеру скопируйте строку подключения kubeadm join ... из логов команды
инициализации Master Controlplane узла.
# kubeadm join ...
После завершения выполнения команды проверьте по отображаемым на мониторе логам ее успешность и запустите на Master ControlPlane узле команду:
# kubectl get nodes
NAME STATUS ROLES AGE VERSION
host-xxx Ready control-plane --- v1....
host-yyy Ready <none> --- v1....
Подключенный узел должен отображаться в списке с состоянием Ready.
Другие способы разворачивания rootless кластера
Разворачивание с локальным регистратора с расширенными политиками доступа или без них
Политики доступа описываются в файле /etc/containers/policy.json. ФОрмат этого файла описан в документе
containers-policy.json - syntax for the signature verification policy file.
Ниже описаны методы корректировки данного файла с помощью команды jq, обеспечивающей корректность структуры json-файла.
При необходимости Вы можете править этот файл текстовым редактором соблюдая корректность JSON-структуры.
Если Вы корректируете данный файл на Master Conrolplane узле ДО разворачивания остальный узлов скопируей его в каталог /var/sigstore/keys/. В этом случае это файл автоматически скопируется в каталог /etc/containers/ разворачиваемого узла.
Если узлы развернуты скопируйте этот файл в каталог /etc/containers/ развернтых узлов.
По умолчанию файл /etc/containers/policy.json политик доступа к docker-образам настраивается на максимальные ограничения:
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
"registry.local": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/var/sigstore/keys/imagemaker.pgp"
}
]
}
}
}
Пользователям разрешается доступ только к образам на локальном регистраторе registry.local, подписанными ключом пользователя imagemaker.
При необходимости Вы можете расширить политику:
- указав дополнительные допустимые ключи подписи;
- расширив список доступных docker-регистраторов;
- расширив список доступных транспортов.
Добавление нового пользователя разработчика образов контейнеров
В описанной выше схеме создается только один пользователь разработчика образов контейнеров.
Вы можете, используя скрипт podsec-create-imagemakeruser создавать неограниченое число пользователей данного класса.
К сожалению в версиях podsec <= 1.1.20 при добавлении нового пользователя список предыдущих пользователей в файле /etc/containers/policy.json обнуляется.
Ниже приведена последовательность действия для поддержания корректного списка пользователей.
Файл /etc/containers/policy.json является символической ссылкой на файл политик с именем по дате создания политики.
Например:
# ls -l /etc/containers/policy*
-rw-r--r-- 1 root root 256 авг 28 2024 /etc/containers/policy_2025-10-29_12:53:52
-rw-r--r-- 1 root root 98 окт 30 12:53 /etc/containers/policy_2025-10-30_12:53:52
-rw-r--r-- 1 root root 276 окт 30 13:23 /etc/containers/policy_2025-10-30_13:23:00
lrwxrwxrwx 1 root root 26 ноя 10 14:20 /etc/containers/policy.json -> policy_2025-10-30_13:23:00
Данный подход позволяет хранить историю политик для данного узла и при необходимости переключать текущие политики перелинковкой файла policy.json:
# cd /etc/containers; ln -sf policy_<время_создания_политики> policy.json
Запомните в переменной oldPolicyFile имя файла текущей политики.
# policyFile='policy.json'
# oldPolicyFile=$(readlink $policyFile)
В данном примере oldPolicyFile будет хранить имя файла policy_2025-10-30_13:23:00 в каталоге /etc/containers/.
Файл содержит JSON-объект описания политики:
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
"registry.local": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/var/sigstore/keys/imagemaker.pgp"
}
]
}
}
}
Создайте нового пользователя:
# podsec-create-imagemakeruser imagemaker2
В процессе создания пользователя создастся новый файл политик с именем /etc/containers/policy_2025-11-10_14:19:00
и файл политик /etc/containers/policy.json залинкуется на него.
# ls -l /etc/containers/policy*
-rw-r--r-- 1 root root 256 авг 28 2024 /etc/containers/policy_2025-10-29_12:53:52
-rw-r--r-- 1 root root 98 окт 30 12:53 /etc/containers/policy_2025-10-30_12:53:52
-rw-r--r-- 1 root root 98 окт 30 13:22 /etc/containers/policy_2025-10-30_13:22:40
-rw-r--r-- 1 root root 276 окт 30 13:23 /etc/containers/policy_2025-10-30_13:23:00
-rw-r--r-- 1 root root 277 ноя 10 14:19 /etc/containers/policy_2025-11-10_14:19:00
lrwxrwxrwx 1 root root 26 ноя 10 14:20 /etc/containers/policy.json -> policy_2025-11-10_14:19:00
Новый файл /etc/containers/policy_2025-11-10_14:19:00 в элементе .transports.docker."registry.local" содержит
массив с описанием тропы до открытого ключа нового пользователя :
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
"registry.local": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/var/sigstore/keys/imagemaker2.pgp"
}
]
}
}
}
Приведенные ниже команды объединять массивы:
# cd /etc/containers;
# registryArray=$(jq -sc '.[0].transports.docker."registry.local" + .[1].transports.docker."registry.local"' $policyFile $oldPolicyFile)
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# jq '.transports.docker."registry.local"|='$registryArray $policyFile > $newPolicyFile
# ln -sf $newPolicyFile policy.json
Файл /etc/containers/policy.json будет содержать массив со всеми открытым ключами пользователей:
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
"registry.local": [
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/var/sigstore/keys/imagemaker2.pgp"
},
{
"type": "signedBy",
"keyType": "GPGKeys",
"keyPath": "/var/sigstore/keys/imagemaker.pgp"
}
]
}
}
}
Вы можете не использовать данные команды, а поправить файл /etc/containers/policy.json в текстовом редакторе.
Добавление нового регистратора
Вы можете добавить в файле /etc/containers/policy.json новый регистратор в объект .transports.docker.
Например registry.altlinux.org:
№ cd /etc/containers;
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# jq '.transports.docker."registry.altlinux.org"|=[{type:"insecureAcceptAnything"}]' policy.json > $newPolicyFile
# ln -sf $newPolicyFile policy.json
В данном примере политика доступа insecureAcceptAnything для регистратора registry.altlinux.org разрешает досступ к нему без ограничений. Вы можете поменять политику доступа на другую.
Файл /etc/containers/policy.json будет иметь вид:
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
"registry.local": [
...
],
"registry.altlinux.org": [
{
"type": "insecureAcceptAnything"
}
]
}
}
}
В этом случае загрузка образов с регистратора registry.altlinux.org будет производится без проверки подписи:
# podman pull registry.altlinux.org/alt/alt
Trying to pull registry.altlinux.org/alt/alt:latest...
Getting image source signatures
Copying blob c549b474d68c done |
Copying blob 8d382247a69f done |
Copying config 97c70e35e5 done |
Writing manifest to image destination
97c70e35e5754c99e2739a341746ab94e4f118e9c63ceaba806e369af80075e9
Расширение списка доступных транспортов
Политики доступа к образам поддерживают несколько типов транспорта:
atomic - Образ располагается в регистраторе типа atomic.
containers-storage - образы хранятся в каталоге файловой системы в формате драйвера (например для podman/cri-o: [overlay@/var/lib/containers/storage]).
dir - Образ располагается в локальном каталоге;
docker - Образ располагается в docker-регистраторе поддерживающий протокол "Docker Registry HTTP API V2".
docker-archive - Образ в виде tar-архива созданный командами docker save, podman save, ...
oci -Образ располагается в локальном каталоге в формате "Open Container Image Layout Specification". В таком формате в виде сжатого tar-архива хранятся kubernetes-образы на ISO диске дистрибутива;
tarball - Заархивированная (tar) файловая система образа.
- ...
Рассмотрим пример добавления транспорта docker-archive. Текущая политика запрещает получать образы их архивного файла, полученными командами docker save, podman save.
# podman load -i /tmp/nginx.tar
* docker-archive: Source image rejected: Running image docker-archive:/tmp/nginx.tar:registry.altlinux.org/c10f/nginx:latest is rejected by policy.
Для обеспечения возможности получать образы из архивов этого формата добавим транспорт docker-archive с типом insecureAcceptAnything:
№ cd /etc/containers;
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# jq '.transports."docker-archive"."".[0].type="insecureAcceptAnything"' policy.json > $newPolicyFile
# ln -sf $newPolicyFile policy.json
Файл /etc/containers/policy.json получит вид:
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
...
},
"docker-archive": {
"": {
"policy": [
{
"type": "insecureAcceptAnything"
}
]
}
}
}
}
После этого из архива /tmp/nginx.tar экспортируется образ registry.altlinux.org/c10f/nginx:latest:
# podman load -i /tmp/nginx.tar
Getting image source signatures
Copying blob f0e31397ae37 skipped: already exists
Copying blob 9a0fa9f6d6ea skipped: already exists
Copying blob f06afe809992 skipped: already exists
Copying blob 5957b6b3c861 skipped: already exists
Copying blob e268fece4a97 skipped: already exists
Copying blob 60204c5adf60 skipped: already exists
Copying blob 6cb900dcc924 skipped: already exists
Copying config d8a1de134d done |
Writing manifest to image destination
Loaded image: registry.altlinux.org/c10f/nginx:latest
Отключение политик доступа
Сформируйте новый файл политик:
# cd /etc/containers
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# echo '{"default":[{"type":"insecureAcceptAnything"}],"transports":{"docker-daemon":{"":[{"type":"insecureAcceptAnything"}]}}}' | jq > $newPolicyFile
# ln -sf $newPolicyFile policy.json
Текущий файл политик будет иметь следующую структуру:
{
"default": [
{
"type": "insecureAcceptAnything"
}
],
"transports": {
"docker-daemon": {
"": [
{
"type": "insecureAcceptAnything"
}
]
}
}
}
При этой конфигурации поддерживаются все виде транспортов и загрузка образов со всех регистраторов.
Расширение политик доступа к docker-образам для конкретных пользователей
Описание пользовательских файлов политик доступа к docker-образам
Кроме общесистемного файла описания политик доступа /etc/containers/policy.json к docker-образам в домашнем каталоге пользователя в подкаталоге .config/containers/ может располагаться пользовательский файл policy.json.
Политики доступа этого файла перекрывают политики доступа общесистемного файла /etc/containers/policy.json.
Для пользователей класса "Создатель образов" файл .config/containers/policy.json обеспечивает выключение политик для данного пользователя:
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
...
},
"docker-archive": {
"": {
"policy": [
{
"type": "insecureAcceptAnything"
}
]
}
}
}
}
Пользователи класса "Пользователь образов" содержит каталог .config/containers с запретом записи в него файлов.
# lsattr .config
----i---------e------- .config/containers
Таким образом пользователи данного класса используют общесистемный файл описания политик доступа /etc/containers/policy.json
и не могут создать свой альтернативный файл .config/containers/policy.json.
Образы и контейнеры запускаемые из суперпользователя root располагаются в каталоге /var/lib/containers.
Образы и контейнеры запускаемые из обычных пользователей располагаются в каталоге ~/.local/share/containers.
Kubernetes-образы и kubernetes-контейнеры запускаемые из под пользователя u7s-admin располагаются в каталоге
~u7s-admin/.local/share/usernetes/containers/. Причем каталог ~u7s-admin/.local/share/containers/ придинкован к этому каталогу. Это обеcпечивает единый каталог хранения образов и контейнеров запускаемых командой podsec и запускаемых движком cri-o rootless kubernetes.
Конфигурирование пользовательских файлов политик доступа к docker-образам
Конфигурирование пользовательских файлов ~/.config/containers/poliсy.json политик доступа к docker-образам
ничем не отличается от конфигурирования общесистемного файла /etc/containers/policy.json, описанного в разделе
Разворачивание с локальным регистратора с расширенными политиками доступа или без них.
Разворачивание без локального регистратора с политиками доступа
При разворачивании без локального регистратора kubernetes-образы берутся с регистратора registry.altlinux.org.
В связи с этим необходимо в файле политик обеспечить доступ к этому регистратору командами:
# cd /etc/containers
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# jq '.transports.docker|={"registry.altlinux.org":[{"type":"insecureAcceptAnything"}]}' policy.json
# ln -sf $newPolicyFile policy.json
Файл политик /etc/containers/poliсy.json будет иметь вид:
{
"default": [
{
"type": "reject"
}
],
"transports": {
"docker": {
"registry.altlinux.org": [
{
"type": "insecureAcceptAnything"
}
]
}
}
}
Для разворачивания kubernetes-кластера с регистратора registry.altlinux.org перед запуском команды инициализации Master Controlplane узла kubeadm init ... или команды присоединения узла kubeadm join ... необходимо установить переменные определяющие регистратор с которого загружаются образы и версию kubernetes.
Регистратор с которого загружаются образы задается переменной U7S_REGISTRY.
# export U7S_REGISTRY=registry.altlinux.org
Список доступных версий kubernetes можно получить командой:
# curl -ks https://$U7S_REGISTRY/v2/c10f/kube-apiserver/tags/list |
jq -r '.tags|map(select(.|startswith("v")))[]'
v1.26.3
v1.26.6
v1.26.10
v1.26.11
v1.26.14
v1.26.15
v1.27.12
v1.27.14
v1.27.16
v1.28.8
v1.28.10
v1.28.12
v1.28.13
v1.28.14
v1.28.15
v1.29.8
v1.29.9
v1.29.14
v1.29.15
v1.30.4
v1.30.5
v1.30.10
v1.30.12
v1.30.14
v1.31.1
v1.31.6
v1.31.8
v1.31.10
v1.31.12
v1.32.4
v1.32.6
v1.32.8
v1.33.2
v1.33.4
Версия разворачивания kubernetes определяется командой U7S_KUBEVERSION:
# export U7S_KUBEVERSION=v1.33.4
После установки переменных U7S_REGISTRY, U7S_KUBEVERSION на Master Controlplane узле вызывается команда инициализации узла кластера:
# export PATH=/usr/libexec/podsec/u7s/bin/:$PATH
# kubeadm init ...
На остальных подключаемых узлов кластера:
# export PATH=/usr/libexec/podsec/u7s/bin/:$PATH
# kubeadm join ...
Разворачивание без локального регистратора и без политик доступа
Если при функционировании кластера нет необходимости в поддержке политик доступа её можно выключить как описано выше командой:
# cd /etc/containers
# newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
# echo '{"default":[{"type":"insecureAcceptAnything"}],"transports":{"docker-daemon":{"":[{"type":"insecureAcceptAnything"}]}}}' | jq > $newPolicyFile
# ln -sf $newPolicyFile policy.json
Далее, как описано в предыдущем разделе определяются переменные U7S_REGISTRY, U7S_KUBEVERSION и разворачиваются Controlplane и Worker узлы кластера.
Разворачивание rootfull кластера
Выбор варианта разворачивания
При разворачивании в режиме rootfull в зависимости от использования локального регистратора docker-образов и применения политик доступа к ним можно обеспечить следующие варианты разворачивания rootfull-кластера:
Варианты разворачивания rootfull кластера
Локальный регистратор
Политики доступа
Примечание
Нет
Нет
Стандартный вариант
Да
Да
Возможность разворачивания в локальной сети без доступа в Интернет с поддержкой классов пользователей с ограничением доступа к docker-регистраторам
Да
Нет
Возможность разворачивания в локальной сети без доступа в Интернет
Нет
Да
Поддержка классов пользователей с ограничением доступа к docker-регистраторам
Разворачивание без локального регистратора и политик доступа
Данный вариант является наиболее общеприменимым, но он не позволяет:
- разворачивать kubernetes-кластер в локальной сети без доступа в Интернет;
- ограничивать доступ к внешним docker-регистраторам с потенциальными уязвимостями в поддерживаемых образах пользователям различных классов.
Развертывание Master ControlPlane узла
Установка RPM-пакетов
Необходимо установить следующие пакеты:
# apt-get update
# apt-get -y install \
kubernetes<minorKubeVerison>-kubeadm \
kubernetes<minorKubeVerison>-kubelet \
kubernetes<minorKubeVerison>-crio \
cri-tools<kminorKubeVerison> \
jq yq
Где <minorKubeVerison> - любая доступная в репозитории минорная версия >=1.26 без начального символа v. Список доступных минорных версий можно посмотреть запросом:
# curl -ks https://registry.altlinux.org/v2/c10f/kube-apiserver/tags/list |
jq -r '.tags|map(select(.|startswith("v")))|map(.[1:5])|map(select(.>"1.25"))[]' |
sort -uV
Где <платформа> - ALTLinux-платформа на которой разворачивается кластер (sisyphus, p10, c10f, p11, ...). См. файл /etc/os-release.
На текущий момент (26.10.2025) список доступных минорных версий для платформы c10f:
# curl -ks https://registry.altlinux.org/v2/c10f/kube-apiserver/tags/list |
jq -r '.tags|map(select(.|startswith("v")))|map(.[1:5])|map(select(.>"1.25"))[]' |
sort -uV
1.26
1.27
1.28
1.29
1.30
1.31
1.32
1.33
Желательно устанавливать минорную версию с максимальным номером.
Команда установки пакетов kubernetes версии 1.33 будет выглядеть следующим образом:
# apt-get update
# apt-get -y install \
kubernetes1.33-kubeadm \
kubernetes1.33-kubelet \
kubernetes1.33-crio \
cri-tools1.33 \
jq yq
Запуск сервисов
После установки пакетов выбранной версии нужно
активировать сервисы crio, kubelet и запустить сервис crio:
# systemctl enable --now crio
# systemctl enable kubelet
Инициализация Master ControlPlane узла
Для инициализация Master ControlPlane узла после установки пакетов и запуска сервисов выполните на узле под пользователем root команду:
# kubeadm init \
-v <DebugLevel> \
--control-plane-endpoint <IP> \
--upload-certs \
--pod-network-cidr=<POD_NET> \
--image-repository=registry.altlinux.org/<платформа> \
--kubernetes-version=<kubeversion>
Где:
- <DebugLevel> - Уровень отладки в интервале 0-9;
- <IP> - IP адрес узра приема API-запросов. Если в кластере один Controlplane узел, то это адрес этого узла. Если в кластере несколько Controlplane узлов - адрес haproxy балансировщика запросов.
- <POD_NET> - Диапазон IP-адресов, используемый для организации внутренеей kuberbetes сети для взаимодействия POD'ов. Этот диапазон зависит от типа CNI (см. ниже):
flannel - 10.244.0.0/16;
calico - 192.168.0.0/16.
- <платформа> - ALTLinux-платформа на которой разворачивается кластер (sisyphus, p10, c10f, p11, ...). См. файл /etc/os-release;
<kubeVerison> - любая доступная в репозитории в рамках выбранной минорной версии полная (patch) версия без начального символа v. Список доступных полных (patch) версий можно посмотреть запросом:
curl -ks https://registry.altlinux.org/v2/<платформа>/kube-apiserver/tags/list |
jq -r '.tags | map(select(.[1:5]=="<minorKubeVerison>")) | map(.[1:])[]' |
sort -uV
Например на текущий момент (26.10.2025) список доступных полных (patch) версий для минорной версии 1.33 платформы p11:
# curl -ks https://registry.altlinux.org/v2/p11/kube-apiserver/tags/list |
jq -r '.tags | map(select(.[1:5]=="1.33")) | map(.[1:])[]' |
sort -uV
1.33.1
1.33.2
1.33.3
1.33.4
Желательно устанавливать версию с максимальным номером.
Например команда инициализации Master Controlplane узла на платформе p11 версии kubernetes 1.33.4 c CNI flannel будет выглядеть следующим образом:
# kubeadm init \
-v 9 \
--control-plane-endpoint <EndpointIP> \
--upload-certs \
--pod-network-cidr=10.244.0.0/16 \
--image-repository=registry.altlinux.org/p11 \
--kubernetes-version=1.33.4 2>&1 |
tee /tmp/kubeadm.log
В данном примере вывод команды kubeadm в stdout, stderr объединяются и записываются в файл /tmp/kubeadm.log для возможного последующего анализа.
В случае успешного разворачивания вывод команды закачивается текстом:
Your Kubernetes control-plane has initialized successfully!
...
You can now join any number of control-plane nodes running the following command on each as root:
kubeadm join <EndpointIP>:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane --certificate-key <key>
...
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join <EndpointIP>:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash>
Первая команда используется для подключения controlplane-узлов.
Вторая команда - для подключения worker-узлов.
Обратите внимание, что первая команда отличается от второй только наличием флагов --control-plane --certificate-key <key>.
Для тех пользователей, которые будут работать с kubernetes-кластером (включая пользователя root) необходимо в домашнем каталоге пользователя создать подкаталог .kube, скопировать в него файл /etc/kubernetes/admin.conf под именем config и установить владельца каталога и файла.
# user=<имя_пользователя_с_доступом_в_кластер>
# userhome=$(getent passwd "$user" | cut -d: -f6)
# mkdir -p $userhome/.kube
# cp -i /etc/kubernetes/admin.conf $userhome/.kube/config
# chown -R $user:$user $userhome/.kube
Для пользователя root можно не копируя файл конфигурации указать его в переменной KUBECONFIG:
# export KUBECONFIG=/etc/kubernetes/admin.conf
Разворачивание kubernetees на master controlplane узле производится в течении нескольких минут. По окончании разворачивании вывод команды
# kubectl get all -A
должен выглядить следующим образом:
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system pod/coredns-84c9f8566b-mg2wf 0/1 Pending 0 ...
kube-system pod/coredns-84c9f8566b-zhrqr 0/1 Pending 0 ...
kube-system pod/etcd-host-98 1/1 Running 0 ...
kube-system pod/kube-apiserver-host-98 1/1 Running 0 ...
kube-system pod/kube-controller-manager-host-98 1/1 Running 0 ...
kube-system pod/kube-proxy-d55w6 1/1 Running 0 ...
kube-system pod/kube-scheduler-host-98 1/1 Running 0 ...
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 67m
kube-system service/kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 67m
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 67m
NAMESPACE NAME READY UP-TO-DATE AVAILABLE AGE
kube-system deployment.apps/coredns 0/2 2 0 67m
NAMESPACE NAME DESIRED CURRENT READY AGE
kube-system replicaset.apps/coredns-84c9f8566b 2 2 0 67m
Вывод для всех POD'ов имеет в поле READY значение 1/1
за исключением двух POD'ов
pod/coredns-..., имеющих значение 0/1.
Значение 1/1 для этих двух POD'ов установится после настройка внутренней сети кластера (CNI).
Команда
# kubectl get nodes -o wide
выводит список из одного узла:
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
host-98 NotReady control-plane 8h v1.33.4 192.168.122.98 <none> ALT Server 11.0 (Mendelevium) 6.12.27-6.12-alt1 cri-o://1.33.4
Состояние NotReady сменится на Ready после настройка внутренней сети кластера (CNI).
Подключение Worker узлов
Для добавления Worker узла установите пакеты
# apt-get update
# apt-get -y install \
kubernetes<kubeVerison>-kubeadm \
kubernetes<kubeVerison>-kubelet \
kubernetes<kubeVerison>-crio \
cri-tools<kubeVerison>
и активируйте сервисы
# systemctl enable --now crio
# systemctl enable kubelet
Скопируйте строку подключения Worker узла и выполните ее на подключаемом узле:
kubeadm join <EndpointIP>:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash> 2>&1 |
tee /tmp/kubeadm.log
В случае возникновении ощибок разворачивания логи можно будет посмотреть в файле /tmp/kubeadm.log.
Подключение ControlPlane узлов
Добавлять ControlPlane узел имеет смысл только в том случае когда у Вас установлен балансировщик API-запросов к кластеру.
Для добавления ControlPlane узла установите пакеты
# apt-get update
# apt-get -y install \
kubernetes<kubeVerison>-kubeadm \
kubernetes<kubeVerison>-kubelet \
kubernetes<kubeVerison>-crio \
cri-tools<kubeVerison>
и активируйте сервисы
# systemctl enable --now crio
# systemctl enable kubelet
Скопируйте строку подключения ControlPlane узла и выполните ее на подключаемом узле:
kubeadm join <EndpointIP>:6443 --token <token> \
--discovery-token-ca-cert-hash sha256:<hash> \
--control-plane --certificate-key <key>
Настройка внутренней сети кластера в различных CNI
Сетевые плагины CNI (Container Network Interface) обеспечивают создание оверлейной сети kubernetes-кластера
в рамках которой производится обмен данными между PO'ами и через POS'ы coredns поддерживается свой DNS-сервис.
Существует множество сетевых плагинов CNI, основные из которых:
- flannel - Простой. легко разворачиваемый плагин обеспечивающий создание оверлейной сети в диапазоне IP-алресов 10.244.0.0/16.
- calico - Сетевой плагин обеспечивающий создание оверлейной сети в диапазоне IP-алресов 192.168.0.0/16 и использующий eBPF ((Extended Berkeley Packet Filter), поддерживающий обработку IP-пакетов кластера на уровне ядра операционный системы.
- cilium - Сетевой плагин обеспечивающий создание оверлейной сети в диапазоне IP-алресов 10.244.0.0/16, использующий eBPF и множество дополнительных сервисов по обработке IP-пакетов и защите сетевого трафика.
CNI flannel
Для Flannel с использованием образов на базе ALT:
Манифесты находятся по адресу https://altlinux.space/cloud/manifests/src/branch/master/flannel/<платформа>.
Где <платформа> на текущий момент (25.10.2024): sisyphus, p10, c10f.
Каждый каталог платформы содержит каталоги
├── <major>
│ ├── <minor>
│ │ └── <patch>
│ │ └── kube-flannel.yml
...
└── latest
└── kube-flannel.yml
Выберите для Вашей платформы (например c10f) установленной версии kubernetes необходимую версию flannel (например 0.27.3) и наберите команду разворачивания:
$ kubectl apply -f https://altlinux.space/cloud/manifests/raw/branch/master/flannel/c10f/0/27/3/kube-flannel.yml
Для последних версий kubernetes можно использовать последнюю версию flannel (тег latest):
$ kubectl apply -f https://altlinux.space/cloud/manifests/raw/branch/master/flannel/c10f/latest/kube-flannel.yml
CNI calico
- Перед запуском
calico-манифестов перейдите в каталог /etc/cni/net.d/:
# cd /etc/cni/net.d/
- и создайте файл
100-crio-bridge.conflist
# cp 100-crio-bridge.conflist.sample 100-crio-bridge.conflist
- Запустите POD'ы из
calico-манифестов:
$ kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/tigera-operator.yaml
$ kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/master/manifests/custom-resources.yaml
CNI cilium
В настоящее время (18.11.2025) идет создание docker-образов для регистратора registry.altlinux.org.
Разворачивание нативного CNI cilium описано на странице
Cilium Quick Installation: Cilium 1.18.4 documentation
Другие способы разворачивания rootfull кластера
Остальные варианты разворачивания rootfull-кластера с поддержкой локального регистратора и политик доступа требует установки группы пакетов podsec:
apt-get install podsec-k8s podsec podsec-inotify
После установки пакетов необходимо, как и в случае rootless кластера на Master ControlPlane:
- создать файлы конфигурации Container Network Policy;
- развернуть дополнительные сервисы.
В дальнейшем в зависимости от варианта разворачивания возможно:
- создание на Master ControlPlane пользователей различных классов;
- установка и настройка мониторинга безопасности системы.
Создание файлов конфигурации Container Network Policy на Master ControlPlane в rootfull режиме
Для создания Container Network Policy на Master узле вызовите команду:
# podsec-create-policy <IP> # ip-aдрес_регистратора и WEB-сервера подписей
Где:
- <IP> - IP-адрес основного интерфеса узла
Проверка файлов конфигурации Container Network Policy подробно описана в разделе разворачивания rootless-kubernetes Создание файлов конфигурации Container Network Policy на Master ControlPlane в rootless режиме
Разворачивание дополнительных сервисов на Master ControlPlane в rootfull режиме
Для разворачивание дополнительных сервисов на Master ControlPlane поднимите сервисы регистратора и WEB-сервера подписей командой:
# podsec-create-services
Вывод команды и проверка функционирование сервисов подробно описана в разделе разворачивания rootless-kubernetes Разворачивание дополнительных сервисов на Master ControlPlane в rootless режиме
Разворачивание без локального регистратора с политиками доступа
Данный вариант разворачивания позволит ограничить список docker-регистриторов к которым имеют доступ пользователи.
Разворачивание с локальным регистратора без политик доступа
Этот вариант позволяет ускорить разворачивание кластера, так как все образы будут располанаться в локальной сети, что ускорит их загрузку на узлы кластера.
Первоначально необходимо сформировать oci-архивы kubernetes-образов.
Если у Вас есть ISO-oбраз дистрибутива C10F, то архив можно взять с этого диска.
Он располагается в каталоге /containers/ под именем k8s_amd64.tar.xz.
Если у Вас ISO-образа нет или Вы планируете установить последнюю версию образов,
то Вы можете сформировать архив с регистратора registry.altlinux.org.
Описание формирования архива OIC-образов Вы можете найти в разделе
Формирование OCI-архива kubernetes-образов с регистратора registry.altlinux.org .
Необходимые команды команды описаны в разделах разворачивания rootless-kubernetes:
Подписывание образов и размещения на локальном регистраторе
После создание пользователя разработчика образов контейнеров выполните команды:
cd /etc/containers
newPolicyFile=policy_$(date '+%Y-%m-%d_%H:%M:%S')
jq '.default[0].type|="insecureAcceptAnything"' /etc/containers/policy.json > $newPolicyFile
ln -sf $newPolicyFile policy.json
или в текстовом редакторе подправить значения поля default[0].type c reject на insecureAcceptAnything.
Это отключит контроль политик использования docker-образов.
Подписывание архивированных образов и помещение их в регистратор
В качестве oci-архива kubetnetes образов можно взять либо файл /containers/k8s_amd64.tar.xz расположенный на ISO-образе C10F, либо сформировать собственный архив.
Процесс создания сжатого OCI-архива образов описан в разделе
Формирование OCI-архива kubernetes-образов с регистратора registry.altlinux.org
Необходимые команды команды описаны в разделах разворачивания rootless-kubernetes:
Подписывание образов и размещения на локальном регистраторе
Разворачивание с локальным регистратора и с политиками доступа
Поддержка управление доступом на основе ролей (RBAC)
Поддержку управления доступом на основе ролей (RBAC) обеспечивает пакет
podsec-k8s-rbac.
В пакет podsec-k8s-rbac входит набор скриптов для работы с RBAC - Role Based Access Control:
podsec-k8s-rbac-create-user - создание RBAC-пользователя;
podsec-k8s-rbac-create-kubeconfig - создание ключей, сертификатов и файла конфигурации RBAC-пользователя;
podsec-k8s-rbac-create-remoteplace - создание удаленного рабочего места;
podsec-k8s-rbac-bindrole - привязывание пользователя к кластерной или обычной роли;
podsec-k8s-rbac-get-userroles - получить список кластерные и обычных ролей пользователя;
podsec-k8s-rbac-unbindrole - отвязывание пользователя от кластерной или обычной роли.
podsec-k8s-rbac-create-user - создание RBAC-пользователя
Формат:
podsec-k8s-rbac-create-user имя_пользователя
Описание:
Скрипт:
- создает RBAC пользователя
- создает в домашнем директории каталог .kube
- устанавливаются соответствующие права доступа к каталогам.
podsec-k8s-rbac-create-kubeconfig - создание ключей, сертификатов и файла конфигурации RBAC-пользователя
Формат:
podsec-k8s-rbac-create-kubeconfig имя_пользователя[@<имя_удаленного_пользователя>] [группа ...]
Описание:
Скрипт должен вызываться администратором безопасности средства контейнеризации.
Для rootless решения имя удаленного пользователя принимается u7s-admin.
Для rootfull решения необходимо после символа @ указать имя удаленного пользователя.
Скрипт в каталоге ~имя_пользователя/.kube производит:
- Создании личного (private) ключа пользователя (файл
имя_пользователя.key).
- Создание запроса на подпись сертификата (CSR) (файл
имя_пользователя.key).
- Запись
запроса на подпись сертификата CSR в кластер.
- Подтверждение
запроса на подпись сертификата (CSR).
- Создание
сертификата (файл имя_пользователя.crt).
- Проверку корректности сертификата
- Формирование файла конфигурации пользователя (файл
config)
- Добавление контекста созданного пользователя
podsec-k8s-rbac-create-remoteplace - создание удаленного рабочего места
Формат:
podsec-k8s-rbac-create-remoteplace ip-адрес
Описание:
Скрипт производит настройку удаленного рабочего места пользователя путем копирования его конфигурационного файла.
podsec-k8s-rbac-bindrole - привязывание пользователя к кластерной или обычной роли
Формат:
podsec-k8s-rbac-bindrole имя_пользователя role|role=clusterrole|clusterrole роль имя_связки_роли [namespace]
Описание:
Скрипт производит привязку пользователя к обычной или кластерной роли используя имя_связки_роли.
Параметры:
- имя_пользователя должно быть создано командой podsec-k8s-rbac-create-user и сконфигурировано на доступ к кластеру командой podsec-k8s-rbac-create-kubeconfig;
- тип роли может принимать следующие значения:
* role - пользователь привязывется к обычной роли с именем <роль> (параметр namespace в этом случае обязателен);
* role=clusterrole - пользователь привязывется к обычной роли используя кластерную роль с именем <роль> (параметр namespace в этом случае обязателен);
* clusterrole - пользователь привязывется к кластерной роли используя кластерную роль с именем <роль> (параметр namespace в этом случае должен отсутствовать).
- роль - имя обычной или кластерной роли в зависимости от предыдущего параметра;
- имя_связки_роли - имя объекта класса rolebindings или clusterrolebindings в зависимости от параметра тип роли. В рамках этого объекта к кластерной или обычной роли могут быть привязаны несколько пользователей.
- namespace - имя namespace для обычной роли.
podsec-k8s-rbac-get-userroles - получить список кластерные и обычных ролей пользователя
Формат:
podsec-k8s-rbac-get-userroles имя_пользователя [showRules]
Описание:
Скрипт формирует список кластерные и обычных ролей которые связаны с пользователем. При указании флага showRules, для каждой роли указывается список правил ("rules:[...]"), которые принадлежат каждой роли пользователя.
Результат возвращается в виде json-строки формата:
{
"": {
"clusterRoles": [...],
"roles": {
"allNamespaces": [...],
"namespaces": [
{
"": [...],
...
}
}
}
}
Где [...] - массив объектов типа:
{
"bindRoleName": "",
"bindedRoleType": "ClusterRole|Role",
"bindedRoleName": "",
"unbindCmd": "podsec-k8s-rbac-unbindrole ..."
}
podsec-k8s-rbac-unbindrole - отвязывание пользователя от кластерной или обычной роли
Формат:
podsec-k8s-rbac-unbindrole имя_пользователя role|clusterrole роль имя_связки_роли [namespace]
Описание:
Скрипт производит отвязку роли от кластерной или обычной роли, созданной командой podsec-k8s-rbac-bindrole. Полный текст команды можно получить в выводе команды podsec-k8s-rbac-get-userroles в поле unbindCmd. Если в указанном имя_связки_роли объекте класса rolebindings или clusterrolebindings еще остаются пользователи - объект модифицируется. Если список становится пуст - объект удаляется.
Параметры:
имя_пользователя должно быть создано командой podsec-k8s-rbac-create-user и сконфигурировано на доступ к кластеру командой podsec-k8s-rbac-create-kubeconfig;
- тип роли может принимать следующие значения:
* role - пользователь привязывается к обычной роли с именем <роль> (параметр namespace в этом случае обязателен);
* clusterrole - пользователь привязывается к кластерной роли используя кластерную роль с именем <роль> (параметр namespace в этом случае должен отсутствовать).
роль - имя обычной или кластерной роли в зависимости от предыдущего параметра;
имя_связки_роли - имя объекта класса rolebindings или clusterrolebindings в зависимости от параметра тип роли. В рамках этого объекта к кластерной или обычной роли могут быть привязаны несколько пользователей.
namespace - имя namespace для обычной роли.
Мониторинг безопасности системы
Мониторинг безопасности системы обеспечивает пакет podsec-inotify.
В пакет podsec-inotify входит набор скриптов для мониторинга безопасности системы:
- podsec-inotify-check-policy - проверка настроек политики контейнеризации на узле;
- podsec-inotify-check-containers - проверка наличия изменений файлов в директориях rootless контейнерах;
- podsec-inotify-check-images - проверка образов на предмет их соответствия настройки политикам контейнеризации на узле;
- podsec-inotify-check-kubeapi - мониторинг аудита API-интерфейса kube-apiserver control-plane узла;
- podsec-inotify-check-vuln - мониторинг docker-образов узла сканером безопасности trivy.
Настройка сервиса trivy
Часть скриптов мониторинга для обнаружения уязвимостей использует сканер trivy.
Сканер безопасности trivy работает как клиент сервера trivy принимающего соединения по порту 4954 на узле с доменом trivy.local.
Если Ваш узел работает в составе кластера, то необходимо:
- на одном из узлов кластера поднять сервер trivy командой:
systemctl enable --now trivy
- на всех узлах кластера прописать в файле
/etc/hosts строку
<IP-адрес_узла_сервера_trivy> trivy.local
Если Ваш узел вне кластера необходимо:
- на узле поднять сервер trivy командой:
systemctl enable --now trivy
- прописать в файле
/etc/hosts строку
127.0.0.1 trivy.local
На платформе c10f сервер trivy запускается автоматически скриптом podsec-create-services на мастер-сервере кластера, привязка домена trivy.local к IP-адресу сервера производится автоматически скриптом podsec-create-policy.
Мониторинг сообщений об уязвимостей через nagwad
Все сообщения об обнаруженных уязвимостях скрипты записывают в системный лог в следующем формате:
<месяц> <день> <время> <host> <имя_скрипта>[<id>]: <уровень_уязвимости>: <текст_сообщения>
Посмотреть эти сообщения можно командой:
journalctl -t <имя_скрипта>
Например:
journalctl -t podsec-inotify-check-vuln
июл 16 06:22:36 host-136 podsec-inotify-check-vuln[383501]: Critical: В образе registry.altlinux.org/k8s-sisyphus/kube-apiserver:v1.30.1 пользователя u7s-admin обнаружены критические и высокие уязвимости.
...
Для передачи сообщений серверу мониторинга общей инфраструктуры icigna необходимо поднять сервис nagwad:
# apt-get install nagwad-service
# systemctl enable --now nagwad
В файловой системе создастся каталог
/var/log/nagwad/<boot_uid>/podsec/.
Все сообщения об уязвимостях сервис nagwad будет записывать из системного лога в данный каталог в файлы под именем
podsec.<message_id>.<level>.
Например /var/log/nagwad/3c22e4b3-d4d7-4975-a49c-f630a15c041d/podsec/:
CRITICAL: podsec-inotify-check-vuln(Critical) В образе registry.altlinux.org/k8s-sisyphus/kube-apiserver:v1.30.1 пользователя u7s-admin обнаружены критические и высокие уязвимости.
Эти файлы в дальнейшем передаются серверу мониторинга общей инфраструктуры icigna.
podsec-inotify-check-policy - проверка настроек политики контейнеризации на узле
Формат:
podsec-inotify-check-policy [-v[vv]] [-a интервал] [-f интервал] -c интервал -h интервал [-m интервал] х-w интервалъ [-l интервал] [-d интервал]
Описание:
Плугин проверяет настройки политики контейнеризации на узле.
Проверка идет по следующим параметрам:
- файл
policy.json установки транспортов и политик доступа к регистраторам:
Параметр контроля пользователей
Вес метрики
имеющих defaultPolicy != reject, но не входящих в группу podman_dev
102
не имеющих не имеющих registry.local в списке регистраторов для которых проверяется наличие электронной подписи образов
103
имеющих в политике регистраторы для которых не проверяется наличие электронной подписи образов
104
имеющих в списке поддерживаемых транспорты отличные от docker (транспорт получения образов с регистратора)
105
- файлы привязки регистраторов к серверам хранящим электронные подписи (файл привязки о умолчанию
default.yaml и файлы привязки регистраторов *.yaml каталога registries.d). Наличие (число) пользователей:
Параметр контроля пользователей
Вес метрики
не использующих хранилище подписей http://sigstore.local:81/sigstore/ как хранилище подписей по умолчанию
106
- контроль групп пользователей
- наличие пользователей имеющих образы, но не входящих в группу
podman:
Параметр контроля пользователей
Вес метрики
наличие пользователей имеющих образы, но не входящих в группу podman
101
- наличие пользователей группы
podman (за исключением входящих в группу podman_dev):
Параметр контроля пользователей
Вес метрики
входящих в группу wheel
101
имеющих каталог .config/containers/ открытым на запись и изменения
90 * доля_нарушителей
не имеющих файла конфигурации .config/containers/storage.conf
90 * доля_нарушителей
доля_нарушителей считается как: число_нарушителей / число_пользователей_группы_podman
Все веса метрик суммируются и формируется итоговая метрика.
podsec-inotify-check-containers - проверка наличия изменений файлов в директориях rootless контейнерах
Формат:
podsec-inotify-check-containers
Описание:
Скрипт:
- создаёт список директорий
rootless контейнеров, существующих в системе,
- запускает проверку на добавление,удаление, и изменение файлов в директориях контейнеров,
- отсылает уведомление об изменении в системный лог.
podsec-inotify-check-images - проверка образов на предмет их соответствия настройки политикам контейнеризации на узле
Формат:
podsec-inotify-check-images [-v[vv]] [-a интервал] [-f интервал] -c интервал -h интервал [-m интервал] х-w интервалъ [-l интервал] [-d интервал]
Описание:
Плугин проверяет образы на предмет их соответствия настройки политикам контейнеризации на узле. Проверка идет по следующим параметрам:
Параметр контроля пользователей
Вес метрики
наличие в политике пользователя регистраторов не поддерживающие электронную подпись
101
наличие в кэше образов неподписанных образов
101
наличие в кэше образов вне поддерживаемых политик
101
Все веса метрик суммируются и формируется итоговая метрика.
podsec-inotify-check-kubeapi - мониторинг аудита API-интерфейса kube-apiserver control-plane узла
Формат:
podsec-inotify-check-kubeapi [-d]
Описание:
Скрипт производит мониторинг файла /etc/kubernetes/audit/audit.log аудита API-интерфейса kube-apiserver.
Политика аудита располагается в файле /etc/kubernetes/audit/policy.yaml:
apiVersion: audit.k8s.io/v1
kind: Policy
omitManagedFields: true
rules:
# do not log requests to the following
- level: None
nonResourceURLs:
- "/healthz*"
- "/logs"
- "/metrics"
- "/swagger*"
- "/version"
- "/readyz"
- "/livez"
- level: None
users:
- system:kube-scheduler
- system:kube-proxy
- system:apiserver
- system:kube-controller-manager
- system:serviceaccount:gatekeeper-system:gatekeeper-admin
- level: None
userGroups:
- system:nodes
- system:serviceaccounts
- system:masters
# limit level to Metadata so token is not included in the spec/status
- level: Metadata
omitStages:
- RequestReceived
resources:
- group: authentication.k8s.io
resources:
- tokenreviews
# extended audit of auth delegation
- level: RequestResponse
omitStages:
- RequestReceived
resources:
- group: authorization.k8s.io
resources:
- subjectaccessreviews
# log changes to pods at RequestResponse level
- level: RequestResponse
omitStages:
- RequestReceived
resources:
- group: "" # core API group; add third-party API services and your API services if needed
resources: ["pods"]
verbs: ["create", "patch", "update", "delete"]
# log everything else at Metadata level
- level: Metadata
omitStages:
- RequestReceived
Текущие настройки производят логирование всех обращений "несистемных" пользователей (в том числе анонимных) к ресурсам kubernetes.
Скрипт производит выборку всех обращений, в ответ на которые был сформирован код более 400 - запрет доступа.
Все эти факты записываются в системный журнал и накапливаются в файле логов /var/lib/podsec/u7s/log/kubeapi/forbidden.log, который периодически передается через посту системному адмиристратору.
Параметры:
-d - скирпт запускается в режиме демона, производящего онлайн мониторинг файла /etc/kubernetes/audit/audit.log и записывающего факты запросов с запретом доступа в системный журнал и файл логов /var/lib/podsec/u7s/log/kubeapi/forbidden.log.
- при запуске без параметров скрипт посылает файл логов
/var/lib/podsec/u7s/log/kubeapi/forbidden.log почтой системному администратору (пользователь root) и обнуляет файл логов.
В состав пакета кроме этого скрипта входят:
файл описания сервиса/lib/systemd/system/podsec-inotify-check-kubeapi.service. Для его запуска екобходимо выполнить команды:
# systemctl enable podsec-inotify-check-kubeapi.service # systemctl start podsec-inotify-check-kubeapi.service
- файл для cron /etc/podsec/crontabs/podsec-inotify-check-kubeapi. Файл содержит единственную строку с описанием режима запуска скрипта podsec-inotify-check-kubeapi для передачи почты системному администратору.
Скрипт запускается один раз в 10 минут. Во время установки пакета строка файла (в случае ее отсутствия) дописыватся в crontab-файл /var/spool/cron/root пользователя root. Если необходимо изменить режим запуска скрипта или выключить его это можно сделать командой редактирования crontab-файла:
# crontab -e
podsec-inotify-check-vuln - мониторинг docker-образов узла сканером безопасности trivy
Формат:
podsec-inotify-check-vuln
Описание:
Скрипт производит мониторинг docker-образов узла сканером безопасности trivy:
- Если скрипт запускается от имени пользователя
rootскрипт:
- проверяет сканером
trivyrootfullобразы; - для всех пользователей каталога
/home/проверяется наличиеrootless-образов. При их наличии проверяет сканеромtrivyэти образы.
- Если скрипт запускается от имени обычного пользователя проверяется наличие
rootless-образов. При их наличии проверяет сканеромtrivyэти образы.
Результат анализа посылается в системный лог.
Если при анализе образа число обнаруженных угроз уровня HIGH больше 0, результат посылается почтой системному администратору (root).
Параметры:
Отсутствуют.
Периодический запуск скрипта
В состав пакета кроме этого входит systemd/timers файл
/usr/lib/systemd/system/podsec-inotify-check-vuln.timer.
При его активации командой:
systemctl enable podsec-inotify-check-vuln.timer
каждый час запускается скрипт мониторинга.
Период запуска можно указать в описателе OnCalendar вышеуказанного systemd/timers файла.
Установка и настройка ingress-контролера
Ingress-контроллер обеспечивает переадресацию http(s) запросов по указанным шаблонам на внутренние сервисы kubernetes-кластера.
Для bare-metal решений и решений на основе виртуальных машин наиболее приемлимым является
ingress-nginx контроллер.
При применении Ingress-контроллера нет необходимости создавать Nodeport-порты и пробрасывать их из namespace пользователя u7s-admin. Ingress-контроллер переадресует http{s) запрос через сервис непосредственно на порты Pod'ов входящих в реплики deployment.
Установка и настройка ingress-nginx-контролера в кластере
Для установки Ingress-контроллера скопируйте его YAML-манифест:
curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.0/deploy/static/provider/baremetal/deploy.yaml -o ingress-nginx-deploy.yaml
Выберите свободный порт в диапазона 30000 - 32767 (например 31000) и добавьте его в элемент
spec.ports.appProtocol==http
Yaml-описании kind==Service:
...
---
kind: Service
spec:
ports:
- appProtocol: http
...
nodePort: 31000
...
Если в Вашем решении используется ТОЛЬКО локальный регистратор registry.local
- создайте алиасы образам nginx:
podman tag registry.k8s.io/ingress-nginx/controller:v1.8.0@sha256:744ae2afd433a395eeb13dc03d3313facba92e96ad71d9feaafc85925493fee3 registry.local/ingress-nginx/controller:v1.8.0 podman tag registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20230407@sha256:543c40fd093964bc9ab509d3e791f9989963021f1e9e4c9c7b6700b02bfb227b registry.local/ingress-nginx/kube-webhook-certgen:v20230407
и поместите их в локальный регистратор:
podman push --tls-verify=false --sign-by='<EMAIL>' registry.local/ingress-nginx/controller podman push --tls-verify=false --sign-by='<EMAIL>' registry.local/ingress-nginx/kube-webhook-certgen
- исправьте имена образов в скачанном нанифесте на имена образов в локальном регистраторе.
Запустите Ingress-nginx-контролер:
kubectl apply -f ingress-nginx-deploy.yaml
На одном или нескольких kubernet-узлах (эти узла в дальнейшем нужно прописать в файле конфигурации балансировщика haproxy) пробросьте порт nginx-контроллера (31000) из namespace пользователя u7s-admin в сеть kubernetes:
nsenter_u7s rootlessctl add-ports 0.0.0.0:31000:31000/tcp
Настройка Ingress-правил
Kubernetes поддерживает манифесты типа Ingress (kind: Ingress) описывающие правила переадресации запросов URL http-запррса на внутренние порты сервисов (kind: Service) kubernetes. Сервисы в свою очередь перенаправляют запросы на реплики Pod'ов, входящих в данный сервис.
Общий вид Ingress-манифеста:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: <ingress_имя>
spec:
ingressClassName: nginx
rules:
- host: <домен_1>
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: <имя_сервиса_1>
port:
number: 80
- path: /<тропа_1>
pathType: Prefix
backend:
service:
name: <имя_сервиса_2>
port:
number: 80
- host: <домен_2>
...
Где:
host: <домен_1>,<домен_2>, ... - домены WEB-серверов на которых приходит запрос;path:/>,path:/<тропа_1>- тропы (префиксы запросов после домена)pathType: Prefix- тип троп:PrefixилиExact;service:- имя сервиса на который перенаправляется запрос, если полученный запрос соответсвует правилу;port- номер порта на который перенаправляется запрос.
Если запросу соответствует несколько правил, выбирается правило с наиболее длинным префиксом.
Подробности смотри в Kubernetes: Ingress
Настройка haproxy и DNS
Добавьте в файлы конфигурации haproxy /etc/haproxy/haproxy.conf переадресацию запросов на порт 80 (http) по IP-адресу балансировщика haproxy на IP-адреса kubernet-узлов на которых выбранный порт nginx-контроллера (31000) проброшен из namespace пользователя u7s-admin в сеть kubernetes:
frontend http
bind *:80
mode tcp
option tcplog
default_backend http
backend http
mode tcp
balance roundrobin
server <server1> <ip1>:31000 check
server <server2> <ip2>:31000 check
Заведите DNS-запись связывающую DNS-имя http-сервиса с IP-адресам haproxy-сервера.
- ↑ ...




