Привет всем! В данной статье мы осветим наш опыт внедрения реестра Docker-образов Harbor в CI/CD платформу Gitorion. Расскажем, как настроить внешнюю аутентификацию Harbor в Keycloak по протоколу OIDC. Разграничим права доступа пользователей к реестру на основе ролей RBAC. Настроим дисковые квоты и автоматизируем очистку Harbor от устаревших Docker-образов, используя API Harbor в пайплайне Jenkins.
Назначение реестра Docker-образов
Кратко напомним, какую функцию выполняет реестр Docker-образов в цикле CI/CD. Во время непрерывной интеграции разработчик вносит изменения в код и делает commit в Git-репозиторий Forgejo. Forgejo посылает Web-хук в Jenkins. Jenkins автоматически вытягивает код из Git-репозитория, компилирует и упаковывает в Docker-образ. Для хранения всех собираемых на платформе Docker-образов используется реестр Docker-образов. Во время непрерывной доставки pipeline Jenkins устанавливает Helm-чарт приложения в кластер Kubernertes. Helm-чарт создает Deployment или StatefulSet, которые извлекают Docker-образ с приложением из приватного реестра Docker-образов и используют его для запуска Docker-контейнера в кластере Kubernetes.
Обоснование внедрения Harbor
В статье CI/CD Kubernetes платформа Gitorion. Приватный реестр Docker-образов с аутентификацией в Keycloak и Web-интерфейсом мы рассмотрели простейший вариант приватного реестра Docker-образов на базе связки Docker-registry с Web-интерфейсом Joxit и аутентификацией в Keycloak. Однако, это решение подойдет команде разработчиков, которой просто нужно делать push/pull Docker-образов в реестр, иметь простой Web-интерфейс, закрытый логином и паролем, и одинаковые права доступа для всех членов команды. В качестве альтернативы мы интегрировали в платформу реестр Harbor, обладающий более широким набором функций.
Краткий обзор Harbor
Harbor - это бесплатный Open-source инструмент, предоставляющий пользователям следующие возможности:
закачивать push и скачивать pull Docker-образы;
хранить Docker-образы и Helm-чарты на внешнем накопителе;
создавать публичные или приватные репозитории сразу для нескольких проектов;
предоставлять пользователю удобный Web-интерфейс;
выполнять аутентификацию пользователей. Harbor может самостоятельно выполнять аутентификацию и хранить логины и пароли пользователей в собственной базе данных. Также к Harbor можно подключить внешний источник аутентификации по одному из протоколов LDAP, UAA, OIDC;
разграничивать права доступа к реестру на основе ролей RBAC;
задавать дисковые квоты;
удалять устаревшие Docker-образы;
сканировать Docker-образы на уязвимости;
подключать к Harbor другие реестры Docker-образов в качестве бэкенда.
Подключаем Harbor к Keycloak
Поскольку бесшовную аутентификацию во все сервисы платформы выполняет Keycloak, настроим аутентификацию пользователей в Harbor, используя Keycloak как внешний источник аутентификации.
На странице администратора Keycloak создайте клиента для Harbor. В верхнем правом углу выберите область Realm и нажмите "Create client" в меню "Clients".
В следующем окне задайте тип клиента "OpenID Connect" в поле "Clietn type". Задайте ClientID, имя клиента, описание клиента и нажмите кнопку "Next".
Включите "Client authentication" и галочки "Standart flow" и "Direct access grants". Нажмите кнопку "Next".
В следующем окне задайте URL вашего реестра Docker-образов в поле "Root URL" и нажмите кнопку "Next".
В результате будет создан клиент Harbor в Keycloak. Теперь войдите администратором в Web-интерфейс Harbor.
Перейдите в меню "Configuration -> Authentication".
Выберите тип аутентификации "OIDC" в выпадающем списке "Auth Mode" и задайте следующие параметры:
"OIDC Provider Name" - надпись на кнопке внешней аутентификации, которая появится на странице аутентификации Harbor;
"OIDC Endpoint" - адрес конечной точки внешней аутентификации, состоящий из URL к Keycloak и пути к области, в которой был создан клиент Harbor в предыдущем пункте;
"OIDC Client" - имя клиента Harbor в Keycloak, заданное в поле "Client ID" в Keycloak;
"OIDC Client Secret" - ключ доступа Harbor к Keycloak. Cкопируйте из поля "Client Secret" на вкладке "Credentials" настроек клиента Harbor в Keycloak;
"OIDC Group Filter" - при успешной аутентификации пользователя Keycloak выдаст Harbor токен, содержащий имя группы, в которой состоит пользователь. В данном поле можно отфильтровать возвращаемые группы с помощью регулярного выражения;
"Group Clime Name" - имя заявки из Harbor в Keycloak на получение группы пользователя;
"OIDC Admin Group" - группа с административными правами;
"OIDC Scope" - список scope с информацией о пользователе, который Keycloak должен передать Harbor в токене после успешной аутентификации пользователя;
"Veryfi Sertificate" - установить защищенное SSL-соединение между Harbor и Keycloak;
"Automatic Onboarding" - при первой аутентификации пользователя с помощью Keycloak Harbor выдает запрос на создание локального пользователя и предлагает связать с ним пользователя из Keycloak. Установите данную галочку, чтобы автоматизировать создание и привязку пользователя. Например, для пользователя developer из Keycloak Harbor автоматически создаст локального пользователя developer_developer и свяжет с пользователем из Keycloak.
Задайте "Redirect URI", расположенный в строке над кнопкой "SAVE" в поле "Valid Redirect URIs" в настройках клиента Harbor в Keycloak. Нажмите кнопку "SAVE", и в Harbor будет создан внешний источник аутентификации в Keycloak.
Аутентификация пользователей Harbor в Keycloak
После добавления внешнего источника аутентификации на странице аутентификации Harbor появится кнопка, по которой можно пройти аутентификацию в Keycloak.
Нажмите кнопку "LOGIN WITH keycloak", и вас перенаправит на окно аутентификации Keycloak.
Введите логин и пароль, и в случае удачной аутентификации Keycloak перекинет вас обратно на Web-интерфейс Harbor.
Разграничение прав доступа с помощью ролей RBAC
Harbor поддерживает разграничение прав пользователей в соответствии с их ролью в проекте. Всего Harbor поддерживает 5 ролей для пользователей: Limited Guest, Guest, Developer, Maintainer и ProjectAdmin. Список разрешенных действий для каждой роли можно посмотреть тут. В статье CI/CD Kubernetes платформа Gitorion. Единый вход Single Sign-On (SSO) во все сервисы платформы при помощи Keycloak мы создали две группы пользователей: "devs" - пользователям которой даны права только на чтение и "admins" - пользователем которой даны административные права во всех сервисах платформы. Ниже мы покажем, как связать группу "devs" из Keycloak c ролью "Developer" в Harbor, а группу "admins" c ролью "ProjectAdmin".
Настроим Keycloak передавать в Harbor группу пользователя в токене после успешной аутентификации пользователя. В настройках клиента Harbor в Keycloak перейдите на вкладку "Client Scopes".
Выберите "harbor-dedicated", перейдите на вкладку "Mappers", нажмите кнопку "Configure a new mapper" и выберите в списке "Group Membership".
Задайте имя mapper-а в поле "Name". В поле "Token Claim Name" укажите имя заявки, которое задали в поле "Group Clime Name" при настройке источника аутентификации OIDC в Harbor выше. Нажмите кнопку "Save".
Теперь залогиньтесь в Harbor через Keycloak любым пользователем из группы "admins", а затем любым пользователем из группы "devs", чтобы пользователи и группы из Keycloak появились в Harbor.
Осталось только связать группы пользователей из Keycloak с ролями Harbor. Для этого выберите ваш проект с репозиториями в Harbor.
Перейдите на вкладку "Members" и нажмите кнопку "+GROUPS".
Свяжите роль "Project Admin" из Harbor с группой "admins" из Keycloak и аналогично группу "devs" свяжите с ролью "Developers".
Теперь залогиньтесь в Harbor через Keycloak любым пользователем из группы "admins", и вы увидите напротив названия проекта роль пользователя "System Admin", а в меню слева появится оснастка администратора Harbor.
Залогиньтесь любым пользователем из группы "devs", и вы увидите роль пользователя "Developer", а оснастка администратора в меню отсутствует.
Дисковые квоты
По умолчанию место на жестком диске, занимаемое Docker-образами проектов, не ограничено. Harbor позволяет установить дисковые квоты как для всех проектов разом, так и для каждого проекта в отдельности. Войдите администратором в Web-интерфейс Harbor и перейдите в меню "Project Quotas" в оснастке администратора.
Для примера зададим квоту 10Gb для проекта "gitorion".
В верхнем правом углу можно увидеть размер дисковой квоты для проекта и текущий размер занятого на диске места.
При исчерпании квоты попытка выполнить push Docker-образа в реестр приведет к ошибке, показанной на картинке ниже.
API Harbor. Автоматизируем очистку реестра
Harbor имеет собственный API, позволяющий взаимодействовать с реестром из скриптов и пайплайнов. В нашем случае мы использовали API Harbor для автоматизации очистки реестра от устаревших Docker-образов. Удалять Docker-образы можно в Web-интерфейсе Harbor, пометив галочкой и нажав кнопку, но это неудобно, когда Docker-образов много. Ознакомиться с API Harbor можно по ссылке "Harbor API v2.0" в левом нижнем углу Web-интерфейса Harbor. В появившемся окне пройдите аутентификацию в Harbor по кнопке "Authorize" и получите возможность запускать и отлаживать команды API прямо на странице API Harbor.
Тут же можно получить команды API и далее использовать в скриптах или пайплайнах. Для автоматизации очистки реестра нам потребовались три команды API Harbor:
//получить список репозиториев
curl -u $HARBOR_LOGIN:$HARBOR_PASSWORD -X GET https://registry.gitorion.kvm/api/v2.0/repositories
//получить список Docker-образов в репозитории
curl -u $HARBOR_LOGIN:$HARBOR_PASSWORD -X GET https://registry.gitorion.kvm/api/v2.0/projects/${project_name}/repositories/${repository_name}/artifacts
//Удалить Docker-образ
curl -u $HARBOR_LOGIN:$HARBOR_PASSWORD -X DELETE https://registry.gitorion.kvm/api/v2.0/projects/${project_name}/repositories/${repository_name}/artifacts/${reference}
Далее мы создали параметризированный пайплайн в Jenkins, который подключается к API Harbor и извлекает список репозиториев.
Полученный список репозиториев Jenkins подгружает в параметр ChoiceParameter.
Пользователь выбирает репозиторий, задает дату и нажимает кнопку "Собрать". Jenkins запускает пайплайн "registry-cleaning", который удаляет все Docker-образы в выбранном репозитории, созданные раньше указанной даты.
Для примера мы удалили из репозитория "owneruser/backend/dev1" проекта "gitorion" все Docker-образы старше 2024-10-31.
Журнал работы пайплайна очистки реестра "registry-cleaning" приведем на картинке ниже.
После очистки, Harbor отобразит в Web-интерфейсе, что репозиторий стал занимать меньше места, но фактически не удалит файлы с жесткого диска. Чтобы удалить файлы с жесткого диска нужно запустить сборщик мусора "Garbage Collection" в меню "Clean Up" оснастки администратора кнопкой "GC NOW".
Тут же можно настроить запуск сборщика мусора по расписанию, нажав кнопку "EDIT" в пункте "Shedule to GC".
Заключение
В данной статье мы рассмотрели ключевые функции реестра Docker-образов Harbor, которые позволили сделать его частью CI/CD цикла платформы Gitorion. Спасибо за внимание!