Руководство администратора
Данное руководство администратора содержит описание настройки и разворачивания продукта "Дистрибутивы и лицензии", а также особенности администрирования и эксплуатации ИС.
Сервисы ИС
Для корректной эксплуатации ИС "Дистрибутивы и лицензии" требуется установка следующих сервисов, входящих в продукт:
| Сервис | Описание | Образ (версии есть в релизах) | Требуется файловая система и точки монтирования |
|---|---|---|---|
engr-auth | Сервис ролей | docker-nexus.sfera.org/engr-auth | Нет |
lvcheck-aggregator-service | Сервис определения лицензий | docker-nexus.sfera.org/lvcheck-aggregator-service | Нет |
lvcheck-front-api | Сервис политик безопасности | docker-nexus.sfera.org/lvcheck-front-api | Нет |
lvcheck-storage-service | Сервис хранения лицензий | docker-nexus.sfera.org/lvcheck-storage-service | Нет |
ppbd-gateway | Маршрутизация трафика | docker-nexus.sfera.org/ppbd-gateway | Нет |
ppdl-back | Серверная часть репозиториев | docker-nexus.sfera.org/ppdl-back | /nexus-data |
ppdl-fe | Интерфейсная часть репозиториев | docker-nexus.sfera.org/ppdl-fe | Нет |
scancode-service | Сервис извлечения лицензий из текстов | docker-nexus.sfera.org/scancode-service | Нет |
Базы данных
Если названия баз данных будут отличаться от описанных в текущем разделе, то учитывайте это при настройке сервисов, использующих данные БД.
| Тип БД | Название | Где используется |
|---|---|---|
| PostgreSQL | license | lvcheck-storage-service lvcheck-aggregator-service |
| PostgreSQL | license_front | lvcheck-front-api |
| PostgreSQL | engr_auth | engr-auth |
Настройка ИС
Настройка ИС "Дистрибутивы и лицензии" включается в себя настройку каждого сервиса продукта через переменные окружения Docker-контейнеров, подробнее о настройке параметров установки сервисов ИС см. разделы:
- Настройка сервиса ppbd-gateway;
- Настройка сервиса engr-auth;
- Настройка сервиса ppdl-back;
- Настройка сервиса ppdl-fe;
- Настройка сервиса lvcheck-front-api;
- Настройка сервиса lvcheck-storage-service;
- Настройка сервиса lvcheck-aggregator-service;
- Настройка сервиса scancode-service;
- Настройка прокси для Docker-репозиториев;
- Настройка интеграции ИС с Канальным приложением.
Настройка сервиса ppbd-gateway
Заполните следующие переменные окружения сервиса ppbd-gateway:
| Переменная | Описание | Значение по умолчанию |
|---|---|---|
| APPLICATION_AUTHENTICATION_SERVICE_URL | URL-адрес сервиса аутентификации | http://common-gateway.ppch.svc.cluster.local:8000 |
| APPLICATION_ROUTES_LICENSE_FRONT_URL | URL-адрес сервиса проверки лицензий | http://lvcheck-front-api:80 |
| APPLICATION_ROUTES_NEXUS_INNER_PREFIX | Путь до сервиса репозиториев, должен соответствовать префиксу URL-адреса, заданному данной подсистеме в коллекции шлюзов канального приложения | /app/ppbd/api/ |
| APPLICATION_ROUTES_NEXUS_OUTER_HOST | Доменное имя канального приложения | - |
| APPLICATION_ROUTES_NEXUS_OUTER_PORT | Порт канального приложения | 443 |
| APPLICATION_ROUTES_NEXUS_OUTER_PROTO | Протокол канального приложения (http/https) | https |
| APPLICATION_ROUTES_NEXUS_URL | URL-адрес сервиса репозиториев | http://ppdl-back:80 |
| SERVER_PORT | Порт сервиса репозиториев | 80 |
Рекомендуемые лимиты ресурсов:
| Ресурс | Значение |
|---|---|
| CPU | 500m |
| RAM | 500Mi |
Настройка сервиса engr-auth
Заполните следующие переменные окружения сервиса engr-auth:
| Переменная | Описание | Значение по умолчанию |
|---|---|---|
| PORT | Порт сервиса | 8000 |
| DB_HOST | Хост и порт сервера ИС | pgsql-proxy:5432 |
| DB_NAME | Имя БД | engr_auth |
| DB_SCHEMA | Схема БД | public |
| DB_USERNAME | Имя пользователя БД | - |
| DB_PASSWORD | Пароль пользователя БД | - |
| LDAP_SYNC_ENABLED | Признак включения синхронизации с LDAP-сервером | true |
Рекомендуемые лимиты ресурсов:
| Ресурс | Значение |
|---|---|
| CPU | 1000m |
| RAM | 1500Mi |
Настройте БД после развёртывания сервиса, выполнив скрипт roles.sql:
-- действия
INSERT INTO public.actions (action_id, title, space_type_id) VALUES ('license:check', 'Проверка библиотек', '*');
INSERT INTO public.actions (action_id, title, space_type_id) VALUES ('license:audit', 'Формирование отчетов', '*');
INSERT INTO public.actions (action_id, title, space_type_id) VALUES ('license:view_policy', 'Просмотр политик', '*');
INSERT INTO public.actions (action_id, title, space_type_id) VALUES ('license:manage_policy', 'Управление политиками', '*');
-- роли
INSERT INTO public.roles (role_id, title, space_id) VALUES ('license:viewer', 'Пользователь', '*');
INSERT INTO public.roles (role_id, title, space_id) VALUES ('license:auditor', 'Аудитор', '*');
INSERT INTO public.roles (role_id, title, space_id) VALUES ('license:policy_viewer', 'Наблюдатель за политиками', '*');
INSERT INTO public.roles (role_id, title, space_id) VALUES ('license:policy_manager', 'Управляющий политиками', '*');
INSERT INTO public.roles (role_id, title, space_id) VALUES ('license:admin', 'Администратор', '*');
-- связи ролей и действий
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('9ff19710-f942-11ed-bad1-32ac81b7b97f', 'license:viewer', 'license:check');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('f2ce7200-f942-11ed-bad1-32ac81b7b97f', 'license:auditor', 'license:check');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('f2ce7bec-f942-11ed-bad1-32ac81b7b97f', 'license:auditor', 'license:audit');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('27ba8ad0-f943-11ed-bad1-32ac81b7b97f', 'license:policy_viewer', 'license:view_policy');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('27ba9ac0-f943-11ed-bad1-32ac81b7b97f', 'license:policy_viewer', 'license:check');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('8d80a34a-f943-11ed-bad1-32ac81b7b97f', 'license:policy_manager', 'license:view_policy');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('8d80ad4a-f943-11ed-bad1-32ac81b7b97f', 'license:policy_manager', 'license:manage_policy');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('8d80b010-f943-11ed-bad1-32ac81b7b97f', 'license:policy_manager', 'license:check');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('b6048e1c-f943-11ed-bad1-32ac81b7b97f', 'license:admin', 'license:manage_policy');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('b6049ee8-f943-11ed-bad1-32ac81b7b97f', 'license:admin', 'license:view_policy');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('b604a550-f943-11ed-bad1-32ac81b7b97f', 'license:admin', 'license:audit');
INSERT INTO public.permissions (id, role_id, action_id) VALUES ('b604a8de-f943-11ed-bad1-32ac81b7b97f', 'license:admin', 'license:check');
Примеры вызова API для работы с сервисом
| Запрос | Назначение | Параметры запроса |
|---|---|---|
| curl 'http://host:port/api/v1/users/:user/actions' | Получение списка привилегий пользователя | user – идентификатор пользователя |
| curl -X PUT 'http://host:port/api/v1/user-space-roles/user/:user/space/*/role/:role' | Добавление роли пользователю |
|
| curl -X DELETE 'http://host:port/api/v1/user-space-roles/user/:user/space/*/role/:role' | Удаление роли у пользователя |
|
| curl -X PUT 'http://host:port/api/v1/space-group-roles/space/*/group/:group/role/:role' | Добавление роли группе пользователей |
|
| curl -X DELETE 'http://host:port/api/v1/space-group-roles/space/*/group/:group/role/:role' | Удаление роли у группы пользователей |
|
| curl -X POST 'http://host:port/api/v1/sync/ldap' | Синхронизация пользователей с LDAP | - |
Настройка сервиса ppdl-back
Убедитесь, что значение порта сервиса ppdl-back равно 8081 (нередактируемое значение).
Рекомендуемые лимиты ресурсов:
| Ресурс | Значение |
|---|---|
| CPU | 500m |
| RAM | 4096Mi |
После развёртывания сервиса выполните первоначальную настройку, запустив следующий скрипт инициализации:
Скрипт инициализации script.sh
#!/bin/bash
nexus_url=${nexus_url:-http://host.docker.internal:8081}
max_tries=${max_tries:-200}
admin_username=${admin_username:-admin}
default_admin_password=${default_admin_password:-admin123}
admin_password=${admin_password:-123}
#possible values:
# true - enable anonymous access
# false - disable anonymous access
# keep - keep, do not change default value
anonymous_enabled=${anonymous_enabled:-false}
anonymous_user=${anonymous_user:-anonymous}
anonymous_realm=${anonymous_realm:-NexusAuthorizingRealm}
auth_header=${auth_header:-X_AUTH_USER}
auth_capability_comment=${auth_capability_comment:-Sfera proxy header}
#ldap_username - username to login to ldap (ci_dos_ppdl@corp.dev.vtb)
#ldap_password - password to login to ldap
#ldap_host - host of LDAP (corp.dev.vtb)
ldap_port=${ldap_port:-389}
ldap_protocol=${ldap_protocol:-LDAP}
#ldap_searchbase - search base (DC=corp,DC=dev,DC=vtb)
#tech_username - ldap user which should be granted nx-admin role
tech_user_role=${tech_user_role:-nx-admin}
#license_firewall_url - http://host/api/firewall/{repository}
license_firewall_repo_placeholder=${license_firewall_repo_placeholder:-\{repository\}}
license_firewall_comment=${license_firewall_comment:-Sfera licensing firewall}
default_realms='["NexusAuthenticatingRealm","NexusAuthorizingRealm"]'
new_realms1='["NexusAuthenticatingRealm","NexusAuthorizingRealm","LdapRealm"]'
new_realms2='["NexusAuthenticatingRealm","NexusAuthorizingRealm","LdapRealm","rutauth-realm"]'
new_realms3='["NexusAuthenticatingRealm","NexusAuthorizingRealm","rutauth-realm"]'
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
current_url=$nexus_url/service/rest/v1/repositories
echo "Checking nexus container started: curl $current_url"
status_code=invalid
tries=$max_tries
while :
do
status_code=$(curl --write-out '%{http_code}' --silent --output /dev/null -X GET $current_url)
if [[ "$status_code" == "200" ]] ; then
break
fi
tries=$((tries - 1))
if [[ $tries == 0 ]] ; then
break;
fi
echo -e "${YELLOW}Timeout or invalid response code $status_code remaining attempts $tries${NC}"
sleep 5
done
if [[ $tries == 0 ]] ; then
echo -e "${RED}Failed to detect started nexus container${NC}"
exit -1
fi
echo -e "${GREEN}Nexus is started at $current_url${NC}"
current_url=$nexus_url/service/rest/v1/security/anonymous
echo "Checking if $admin_username default password in effect: curl <default password> $current_url"
status_code=$(curl -u "$admin_username:$default_admin_password" --write-out '%{http_code}' --silent --output /dev/null -X GET $current_url)
if [[ "$status_code" == "200" ]] ; then
current_url=$nexus_url/service/rest/v1/security/users/admin/change-password
echo -e "${GREEN}Returned 200: $admin_username default password is in effect${NC}"
echo "Changing to new password: curl $current_url"
status_code=$(curl -u "$admin_username:$default_admin_password" --write-out '%{http_code}' --silent --output /dev/null -X PUT -H "Content-Type: text/plain" -d "$admin_password" $current_url)
if [[ "$status_code" == "204" ]] ; then
echo -e "${GREEN}Password changed for $admin_username${NC}"
else
echo -e "${RED}Unexpected status code $status_code${NC}"
exit -2
fi
elif [[ "$status_code" == "401" ]] ; then
echo -e "${GREEN}Returned 401: default password is not in effect${NC}"
else
echo -e "${RED}Unexpected status code $status_code${NC}"
exit -3
fi
current_url=$nexus_url/service/rest/v1/security/anonymous
echo "Checking if $admin_username password in effect: curl <password> $current_url"
status_code=$(curl -u "$admin_username:$admin_password" --write-out '%{http_code}' --silent --output /dev/null -X GET $current_url)
if [[ "$status_code" == "200" ]] ; then
echo -e "${GREEN}Returned 200: $admin_username password is in effect${NC}"
else
echo -e "${RED}Unexpected status code $status_code${NC}"
exit -4
fi
if [[ "$anonymous_enabled" == "keep" ]] ; then
echo "Keeping existing value for anonymous access"
else
current_url=$nexus_url/service/rest/v1/security/anonymous
echo "Changing anonymous access: curl $current_url to $anonymous_enabled"
request_body="{\"enabled\":$anonymous_enabled,\"userId\":\"$anonymous_user\",\"realmName\":\"$anonymous_realm\"}"
status_code=$(curl -u "$admin_username:$admin_password" --write-out '%{http_code}' --silent --output /dev/null -X PUT -H "Content-Type: application/json" -H "accept: application/json" -d "$request_body" $current_url)
if [[ "$status_code" == "200" ]] ; then
echo -e "${GREEN}Returned 200: anonymous access is set${NC}"
else
echo -e "${RED}Unexpected status code $status_code${NC}"
exit -5
fi
fi
current_url=$nexus_url/service/rest/v1/security/realms/active
echo "Checking existing realms: curl $current_url"
current_response=$(curl -u "$admin_username:$admin_password" --silent -X GET $current_url)
current_response="$(echo -e "${current_response}" | tr -d '[:space:]')"
if [[ "$current_response" == "$default_realms" ]] ; then
echo -e "${GREEN}Default realms in effect $default_realms${NC}"
echo "Updating realms to $new_realms1"
current_url=$nexus_url/service/rest/v1/security/realms/active
status_code=$(curl -u "$admin_username:$admin_password" --write-out '%{http_code}' --silent --output /dev/null -X PUT -H "Content-Type: application/json" -H "accept: application/json" -d "$new_realms1" $current_url)
if [[ "$status_code" == "204" ]] ; then
echo -e "${GREEN}Returned 200: new realms set${NC}"
else
echo -e "${RED}Unexpected status code $status_code${NC}"
exit -6
fi
auth_header_set=false
elif [[ "$current_response" == "$new_realms1" ]] ; then
echo -e "${GREEN}New realms in effect $new_realms1${NC}"
auth_header_set=false
elif [[ "$current_response" == "$new_realms2" ]] ; then
echo -e "${GREEN}New realms in effect $new_realms2${NC}"
auth_header_set=true
elif [[ "$current_response" == "$new_realms3" ]] ; then
echo -e "${GREEN}New realms in effect $new_realms3${NC}"
echo "Adding LDAP realm"
current_url=$nexus_url/service/rest/v1/security/realms/active
status_code=$(curl -u "$admin_username:$admin_password" --write-out '%{http_code}' --silent --output /dev/null -X PUT -H "Content-Type: application/json" -H "accept: application/json" -d "$new_realms2" $current_url)
if [[ "$status_code" == "204" ]] ; then
echo -e "${GREEN}Returned 200: new realms set${NC}"
else
echo -e "${RED}Unexpected status code $status_code${NC}"
exit -6
fi
auth_header_set=true
else
echo -e "${YELLOW}Unexpected realms list [$current_response]. Assuming nexus already initialized and modified, finishing initialization."
exit 1
fi
if [[ "$auth_header_set" == "false" ]] ; then
current_url=$nexus_url/service/extdirect
echo "Setting auth header capability"
request_body="{\"action\":\"capability_Capability\",\"method\":\"create\",\"data\":[{\"id\":\"NX.coreui.model.Capability-1\",\"typeId\":\"rutauth\",\"notes\":\"$auth_capability_comment\",\"enabled\":true,\"properties\":{\"httpHeader\":\"$auth_header\"}}],\"type\":\"rpc\",\"tid\":11}"
current_response=$(curl -u "$admin_username:$admin_password" --silent -X POST -H "Content-Type: application/json" -d "$request_body" $current_url)
current_response="$(echo -e "${current_response}" | tr -d '[:space:]')"
if [[ "$current_response" == *'"success":true'* ]] ; then
echo -e "${GREEN}Auth header capability successfully set${NC}"
elif [[ "$current_response" == *'"success":false'* ]] ; then
echo -e "${RED}Auth header capability was already set but realm is missing${NC}"
exit -7
else
echo -e "${RED}Unexpected response $current_response${NC}"
exit -8
fi
else
echo "Auth capability already set"
fi
current_url=$nexus_url/service/extdirect
echo "Checking outreach capability present: curl $current_url"
request_body="{\"action\":\"capability_Capability\",\"method\":\"read\",\"data\":null,\"type\":\"rpc\",\"tid\":1}"
current_response=$(curl -u "$admin_username:$admin_password" --silent -X POST -H "Content-Type: application/json" -d "$request_body" $current_url)
current_response="$(echo -e "${current_response}" | tr -d '[:space:]')"
type_id=$(echo "$current_response" | grep -oP '(?<=\"id\":\")\w+(?=\",\"typeId\"\:\"OutreachManagementCapability\")')
if [[ "$type_id" == "" ]] ; then
echo -e "${GREEN}No outreach capability found${NC}"
else
echo -e "${GREEN}Found outreach capability $type_id${NC}"
current_url=$nexus_url/service/extdirect
echo "Removing outreach capability: curl $current_url"
request_body="{\"action\":\"capability_Capability\",\"method\":\"remove\",\"data\":[\"$type_id\"],\"type\":\"rpc\",\"tid\":1}"
current_response=$(curl -u "$admin_username:$admin_password" --silent -X POST -H "Content-Type: application/json" -d "$request_body" $current_url)
current_response="$(echo -e "${current_response}" | tr -d '[:space:]')"
if [[ "$current_response" == *'"success":true'* ]] ; then
echo -e "${GREEN}Outreach capability successfully removed${NC}"
elif [[ "$current_response" == *'"success":false'* ]] ; then
echo -e "${RED}Outreach capability was not removed${NC}"
exit -9
else
echo -e "${RED}Unexpected response $current_response${NC}"
exit -10
fi
fi
echo "Checking LDAP connection: curl $current_url"
current_url=$nexus_url/service/rest/v1/security/ldap
current_response=$(curl -u "$admin_username:$admin_password" --silent -X GET $current_url)
current_response="$(echo -e "${current_response}" | tr -d '[:space:]')"
if [[ "$current_response" == "[]" ]] ; then
echo -e "${GREEN}No active LDAP connections${NC}"
current_url=$nexus_url/service/rest/v1/security/ldap
echo "Adding LDAP connection: curl $current_url to $ldap_host"
request_body="{\"name\":\"main\",\"protocol\":\"$ldap_protocol\",\"useTrustStore\":false,\"host\":\"$ldap_host\",\"port\":$ldap_port,\"searchBase\":\"$ldap_searchbase\",\"authScheme\":\"SIMPLE\",\"authRealm\":\"\",\"authUsername\":\"$ldap_username\",\"authPassword\":\"$ldap_password\",\"connectionTimeoutSeconds\":30,\"connectionRetryDelaySeconds\":300,\"maxIncidentsCount\":3,\"userBaseDn\":\"\",\"userSubtree\":true,\"userObjectClass\":\"user\",\"userLdapFilter\":\"\",\"userIdAttribute\":\"userPrincipalName\",\"userRealNameAttribute\":\"displayName\",\"userEmailAddressAttribute\":\"userPrincipalName\",\"userPasswordAttribute\":\"\",\"ldapGroupsAsRoles\":true,\"groupType\":\"DYNAMIC\",\"groupBaseDn\":null,\"groupSubtree\": false,\"groupObjectClass\": null,\"groupIdAttribute\": null,\"groupMemberAttribute\":null,\"groupMemberFormat\":null,\"userMemberOfAttribute\":\"memberOf\"}"
status_code=$(curl -u "$admin_username:$admin_password" --write-out '%{http_code}' --silent --output /dev/null -X POST -H "Content-Type: application/json" -H "accept: application/json" -d "$request_body" $current_url)
if [[ "$status_code" == "201" ]] ; then
echo -e "${GREEN}LDAP configuration created${NC}"
else
echo -e "${RED}Unexpected status code $status_code${NC}"
exit -11
fi
else
echo "LDAP connection already set"
fi
current_url=$nexus_url/service/rest/v1/security/users
echo "Checking presence of LDAP user $ldap_username: curl $current_url"
current_response=$(curl -u "$admin_username:$admin_password" --silent -X GET -G $current_url --data-urlencode "userId=$ldap_username" --data-urlencode 'source=LDAP')
current_response="$(echo -e "${current_response}" | tr -d '[:space:]')"
if [[ "$current_response" == "[]" ]] ; then
echo -e "${RED}Unable to find user $ldap_username. Need to manually remove all LDAP connections and run script again.${NC}"
exit -12
else
echo -e "${GREEN}Successfully found LDAP user $ldap_username${NC}"
fi
if [[ "$tech_username" == "" ]] ; then
echo "Skipping granting role to user because tech_username environment variable is not set"
else
current_url=$nexus_url/service/rest/v1/security/users
echo "Getting full user name for LDAP user $tech_username: curl $current_url"
current_response=$(curl -u "$admin_username:$admin_password" --silent -X GET -G $current_url --data-urlencode "userId=$tech_username" --data-urlencode 'source=LDAP')
current_response="$(echo -e "${current_response}" | tr -d '[:space:]')"
if [[ "$current_response" == "[]" ]] ; then
echo -e "${RED}Unable to find user $tech_username${NC}"
exit -13
else
full_tech_username=$(echo "$current_response" | grep -oP '(?<=\"userId\":\")[^\"]+(?=\")')
if [[ "$full_tech_username" == "" ]] ; then
echo -e "${RED}Unable to parse userId in response: $current_response${NC}"
exit -14
else
echo -e "${GREEN}Successfully found LDAP user $tech_username: $full_tech_username${NC}"
current_url=$nexus_url/service/rest/v1/security/users/$full_tech_username
request_body="{\"userId\":\"$full_tech_username\",\"firstName\":\"s\",\"lastName\":\"s\",\"emailAddress\":\"addr@host.com\",\"source\":\"LDAP\",\"status\":\"active\",\"roles\":[\"$tech_user_role\"]}"
status_code=$(curl -u "$admin_username:$admin_password" --write-out '%{http_code}' --silent -X PUT -H "Content-Type: application/json" -d "$request_body" "$current_url")
if [[ "$status_code" == "204" ]] ; then
echo -e "${GREEN}LDAP user $tech_username roles updated to [$tech_user_role]${NC}"
else
echo -e "${RED}Unexpected status code $status_code${NC}"
exit -15
fi
fi
fi
fi
if [[ "$license_firewall_url" == "" ]] ; then
echo "Skipping firewall capability because license_firewall_url variable is not set"
else
current_url=$nexus_url/service/extdirect
echo "Setting firewall capability"
props="{}"
request_body="{\"action\":\"capability_Capability\",\"method\":\"create\",\"data\":[{\"id\":\"NX.coreui.model.Capability-2\",\"typeId\":\"sfera.licensing\",\"notes\":\"$license_firewall_comment\",\"enabled\":true,\"properties\":{\"url\":\"$license_firewall_url\",\"repoPlaceholder\":\"$license_firewall_repo_placeholder\"}}],\"type\":\"rpc\",\"tid\":11}"
current_response=$(curl -u "$admin_username:$admin_password" --silent -X POST -H "Content-Type: application/json" -d "$request_body" $current_url)
current_response="$(echo -e "${current_response}" | tr -d '[:space:]')"
if [[ "$current_response" == *'"success":true'* ]] ; then
echo -e "${GREEN}Firewall capability successfully set${NC}"
elif [[ "$current_response" == *'"success":false'* ]] ; then
echo -e "${GREEN}Firewall capability was already set${NC}"
else
echo -e "${RED}Unexpected response $current_response${NC}"
exit -17
fi
fi
echo -e "${GREEN}Finished Nexus initialization${NC}"
| Параметр | Описание | Значение по умолчанию |
|---|---|---|
| nexus_url | URL-адрес установленного сервиса (используется скриптом для доступа к сервису) | http://host.docker.internal:8081 |
| max_tries | Максимальное количество попыток подключения | 200 |
| admin_username | Имя учётной записи Nexus с правами администратора, с помощью которой скрипт выполняет настройку | admin |
| default_admin_password | Пароль администратора для запуска скрипта | admin123 |
| admin_password | Пароль администратора, устанавливаемый скриптом в процессе выполнения | 123 |
| anonymous_enabled | Признак предоставления пользователям доступа к сервису ppdl-back без авторизации | false |
| anonymous_user | Имя неавторизованного пользователя, права которого действуют при доступе к сервису ppdl-back без авторизации | anonymous |
| anonymous_realm | Realm неавторизованного пользователя | NexusAuthorizingRealm |
| auth_header | Заголовок авторизации, в котором сервис api-gateway передает имя пользователя (должно быть идентичным значению, заданным в конфигурации api-gateway) | X_AUTH_USER |
| auth_capability_comment | Комментарий к Nexus capability, создаваемой через заголовок auth_header | Sfera proxy header |
| ldap_username | Имя пользователя LDAP, используемый сервисом ppdl-back для аутентификации пользователей | - |
| ldap_password | Пароль пользователя LDAP | - |
| ldap_host | Хост LDAP | - |
| ldap_port | Порт LDAP | 389 |
| ldap_protocol | Протокол LDAP (LDAP/LDAPS) | LDAP |
| ldap_searchbase | LDAP query DN для поиска пользователей (например, dc=example, dc=com) | - |
| tech_username | Имя технической учётной записи Выполняется поиск пользователя в LDAP и задается роль этому пользователю в Nexus | - |
| tech_user_role | Роль Nexus, которая выдается технической учётной записи в процессе выполнения скрипта | nx-admin |
| license_firewall_url | Шаблон URL-адреса сервиса lvcheck-front-api | - |
| license_firewall_repo_placeholder | В параметре license_firewall_url выполняется поиск подстроки, заданной этим параметром, и она заменяется на название репозитория | {repository} |
| license_firewall_comment | Комментарий к Nexus capability для подключения к сервису lvcheck-front-api | Sfera licensing firewall |
Настройка сервиса ppdl-fe
Заполните следующие переменные окружения сервиса ppdl-fe:
| Переменная | Описание | Значение по умолчанию |
|---|---|---|
| REACT_APP_API_PATH | Дополнительный путь к сервисам API, относительно текущего URL-адреса расположения сервиса ppdl-fe | app/ppbd/api |
Убедитесь, что значение порта сервиса ppdl-fe в контейнере равно 8000 (нередактируемое значение).
Рекомендуемые лимиты ресурсов:
| Ресурс | Значение |
|---|---|
| CPU | 500m |
| RAM | 500Mi |
Настройка сервиса lvcheck-front-api
Заполните следующие переменные окружения сервиса lvcheck-front-api:
| Переменная | Описание | Значение по умолчанию |
|---|---|---|
| PATH_TO_STORAGE_SERVICE | URL-адрес сервиса | http://lvcheck-storage-service:80 |
| POSTGRES_HOST | Хост ИС | - |
| POSTGRES_PORT | Порт ИС | - |
| POSTGRES_DBNAME | Имя БД | license_front |
| POSTGRES_USER | Имя пользователя БД | - |
| POSTGRES_PASSWORD | Пароль пользователя БД | - |
| SERVER_PORT | Порт сервиса | 80 |
Рекомендуемые лимиты ресурсов:
| Ресурс | Значение |
|---|---|
| CPU | 500m |
| RAM | 500Mi |
Настройка сервиса lvcheck-storage-service
Заполните следующие переменные окружения сервиса lvcheck-storage-service:
| Переменная | Описание | Значение по умолчанию |
|---|---|---|
| PATH_TO_AGGREGATOR_SERVICE | URL-адрес сервиса | http://lvcheck-aggregator-service:80 |
| POSTGRES_HOST | Хост ИС | - |
| POSTGRES_PORT | Порт ИС | - |
| POSTGRES_DBNAME | Имя БД | license |
| POSTGRES_USER | Имя пользователя БД | - |
| POSTGRES_PASSWORD | Пароль пользователя БД | - |
| SERVER_PORT | Порт сервиса | 80 |
Рекомендуемые лимиты ресурсов:
| Ресурс | Значение |
|---|---|
| CPU | 500m |
| RAM | 500Mi |
Настройка сервиса lvcheck-aggregator-service
Заполните следующие переменные окружения сервиса lvcheck-aggregator-service:
| Переменная | Описание | Значение по умолчанию |
|---|---|---|
| PATH_TO_LICENSE_MATCHER_SERVICE | URL-адрес сервиса scancode-service | http://scancode-service:80 |
| POSTGRES_HOST | Хост ИС | - |
| POSTGRES_PORT | Порт ИС | - |
| POSTGRES_DBNAME | Имя БД | license |
| POSTGRES_USER | Имя пользователя БД | - |
| POSTGRES_PASSWORD | Пароль пользователя БД | - |
| VTB_NEXUS_URL | URL-адрес репозитория Maven | - |
Рекомендуемые лимиты ресурсов:
| Ресурс | Значение |
|---|---|
| CPU | 500m |
| RAM | 500Mi |
Настройка сервиса scancode-service
Заполните следующие переменные окружения сервиса scancode-service:
| Переменная | Описание | Значение по умолчанию |
|---|---|---|
| SERVER_PORT | Порт сервиса | 80 |
Рекомендуемые лимиты ресурсов:
| Ресурс | Значение |
|---|---|
| CPU | 600m |
| RAM | 1500Mi |
Настройка прокси для Docker-репозиториев
Для работы Docker-репозиториев выполните настройку проксирующих сервисов, так как Docker-протокол не поддерживает сложные составные URl-адреса.
Пример структуры yaml-файла для входящего трафика (ingress) платформы "Сфера"
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ppbd-docker
namespace: ppch
annotations:
cert-manager.io/cluster-issuer: sfera
nginx.ingress.kubernetes.io/proxy-body-size: 10g
nginx.ingress.kubernetes.io/rewrite-target: /app/ppbd/api/v2/$1
spec:
ingressClassName: nginx
rules:
- host: docker-ppbd.sfera.org
http:
paths:
- path: /v2/(.*)
pathType: Prefix
backend:
service:
name: sfera-gateway-service
port:
number: 8000
Настройка интеграции ИС с Канальным приложением
Продукт "Дистрибутивы и лицензии" доступен только через Канальное приложение производственной платформы "Сфера".
Подготовка Json-файла с необходимыми параметрами
Пример структуры Json-файла
{
"code": "ppbd",
"path": "ppbd",
"title": "Дистрибутивы и Лицензии",
"description": "Храните",
"groupTitle": "Инженерные инструменты",
"icon": "app/ppbd/logo.svg",
"favorite": false,
"enabled": true,
"isPublic": false,
"internal": false,
"options": {
"type": "script",
"remoteName": "sfera_ppdl_container",
"remoteEntry": "app/ppbd/remoteEntry.js",
"exposedModule": "microFrontend"
},
"apiRoute": {
"url": "http://api-gateway.ppbd.svc.cluster.local:8000",
"filters": [
"StripPrefix=3"
],
"predicates": [
"/app/ppbd/**"
]
},
"mfRoute": {
"url": "http://ppdl-fe.ppbd.svc.cluster.local:8000",
"filters": [
"StripPrefix=2"
],
"predicates": [
"/app/ppbd/**"
]
},
"widgetApiRoute": null,
"widgetMfRoute": null,
"fileRoute": null
}
где:
| № п/п | Параметр | Описание | Пример |
|---|---|---|---|
| 1 | code | Мнемокод продукта | ppbd |
| 2 | path | Путь до ИС | ppbd |
| 3 | title | Наименование продукта, которое будет отображаться в плитке на главной странице канала, а также в боковом меню канала | Дистрибутивы и Лицензии |
| 4 | description | Описание продукта (будет отображаться в плитке на главной странице канала) | Храни |
| 5 | groupTitle | Категория продукта (от нее зависит в каком блоке бокового меню будет отображаться ИС) | Инженерные инструменты |
| 6 | icon | Иконка продукта (путь прописывается на стороне канала, сама иконка добавляется на стороне продукта) В путь app/{ppbd}/logo.svg нужно подставить код продукта | - |
| 7 | enabled | Признак отображения плитки в канальном приложении Допустимые значения: - true - плитка будет отображаться на главной, а также в боковом меню; - false - продукт будет скрыт с главной страницы канала и из бокового меню | true |
| 8 | options | Блок опций для интерфейсной части (frontend):
| |
| 9 | apiRoute | Блок опций для маршрутизации API:
| |
| 10 | mfRoute | Блок опций для маршрутизации микрофронтенда:
| |
| 11 | wsRoute | Блок опций для маршрутизации веб-сокетов | null |
Добавление ИС в канальное приложение
Для добавления ИС в Канальное приложение выполните следующую команду:
Команда
kubectl --kubeconfig ~/file_with_kube_config.crash -n ppch get pods \
-l app.kubernetes.io/instance=ppch-tenant-management-service \
-o name | xargs -I{} kubectl --kubeconfig ~/file_with_kube_config.crash \
-n ppch exec {} -- curl -X POST --location \
'http://localhost:7079/actuator/productmanager/add-product-config' \
--header 'Content-Type: application/json' \
--data '{
"code": "ppbd",
"path": "ppbd",
"title": "Дистрибутивы и Лицензии",
"description": "Храните",
"groupTitle": "Инженерные инструменты",
"icon": "app/ppbd/logo.svg",
"favorite": false,
"enabled": true,
"isPublic": false,
"internal": false,
"options": {
"type": "script",
"remoteName": "sfera_ppdl_container",
"remoteEntry": "app/ppbd/remoteEntry.js",
"exposedModule": "microFrontend"
},
"apiRoute": {
"url": "http://api-gateway.ppbd.svc.cluster.local:8000",
"filters": [
"StripPrefix=3"
],
"predicates": [
"/app/ppbd/**"
]
},
"mfRoute": {
"url": "http://ppdl-fe.ppbd.svc.cluster.local:8000",
"filters": [
"StripPrefix=2"
],
"predicates": [
"/app/ppbd/**"
]
},
"widgetApiRoute": null,
"widgetMfRoute": null,
"fileRoute": null
}'
Обновление кэша Канального приложения
Для обновления кэша Канального приложения выполните следующую команду:
kubectl --kubeconfig ~/ikuzminykh-kubeconf.crash -n ppch get pods \
-l app.kubernetes.io/instance=ppch-tenant-management-service \
-o name | xargs -I{} kubectl --kubeconfig ~/ikuzminykh-kubeconf.crash \
-n ppch exec {} -- curl -s http://localhost:7079/actuator/refresh -X POST
kubectl --kubeconfig ~/ikuzminykh-kubeconf.crash -n ppch get pods \
-l app.kubernetes.io/instance=ppch-gateway-ws-service \
-o name | xargs -I{} kubectl --kubeconfig ~/ikuzminykh-kubeconf.crash \
-n ppch exec {} -- curl -s http://localhost:7079/actuator/refresh -X POST
kubectl --kubeconfig ~/ikuzminykh-kubeconf.crash -n ppch get pods \
-l app.kubernetes.io/instance=ppch-gateway-mf-service \
-o name | xargs -I{} kubectl --kubeconfig ~/ikuzminykh-kubeconf.crash \
-n ppch exec {} -- curl -s http://localhost:7079/actuator/refresh -X POST
kubectl --kubeconfig ~/ikuzminykh-kubeconf.crash -n ppch get pods \
-l app.kubernetes.io/instance=ppch-gateway-service \
-o name | xargs -I{} kubectl --kubeconfig ~/ikuzminykh-kubeconf.crash \
-n ppch exec {} -- curl -s http://localhost:7079/actuator/refresh -X POST
Проверка работоспособности ИС
Для проверки работоспособности ИС перейдите в веб-вебраузере по URL-адресу http://sfera.apps.ocp.t1.demo.ru/app/ppdb/ (URL-адрес может быть другим, в зависимости от настроек, выполненных при установке ИС) – откроется стартовая страница приложения.
Планово-предупредительные мероприятия
Планово-предупредительные мероприятия проводятся с целью проверки работоспособности ИС и локализации неработающих компонентов.
| № п/п | Мероприятие | Рекомендуемая периодичность проведения | Ответственный |
|---|---|---|---|
| 1 | Мониторинг работоспособности различных компонентов системы | Определяется администратором | Прикладной администратор |
| 2 | Локализации неработающих компонентов системы | Определяется администратором | Прикладной администратор |
| 3 | Проверка наличия сертификатов | Перед запуском пилотного/целевого решения, перед релизом | Прикладной администратор |
| 4 | Проверка в консоли администратора k8s состояния подов (все поды запущены в требуемом количестве) | После запуска пилотного/целевого решения, после выпуска релиза | Прикладной администратор |
| 5 | Проверка лог-файлов запуска компонентов продукта (микросервисов) на наличие сообщений с типом «ERROR» | После запуска пилотного/целевого решения, после выпуска релиза | Прикладной администратор |
| 6 | Проверка работоспособности микросервисов на маршрутах (/healthcheck) | После запуска пилотного/целевого решения, после выпуска релиза | Прикладной администратор |
| 7 | Проверка работоспособности компонента Grafana | Раз в месяц | Прикладной администратор |
| 8 | Проверка работоспособности микросервисов | Ежедневно | Прикладной администратор |
| 9 | Проверка статуса системы. Статус запуска серверов | Ежедневно | Прикладной администратор |
| 10 | Проверка статуса системы. Мониторинг использования серверов | Раз в месяц | Прикладной администратор |
| 11 | Мониторинг использования серверов. Анализ статистики по лог-файлам | Раз в месяц | Прикладной администратор |
| 12 | Проверка статуса системы. Мониторинг выполнения задач планировщика | Ежедневно | Прикладной администратор |
Для просмотра лог-файлов микросервисов в кластере Kubernetes выполните следующие действия:
- авторизуйтесь в консоли Kubernetes под ролью администратора;
- перейдите на вкладку «Pods» в разделе «Workloads» и выберите раздел «Project»;
- перейдите на страницу необходимого пода и откройте вкладку «Logs».
Открылось окно с журналом выбранного микросервиса, в режиме реального времени отображается последняя тысяча строк.
Для раскрытия окна на весь экран нажмите на кнопку Expand.
Для скачивания лог-файла нажмите на кнопку Download.
Аварийное восстановление ИС
Критериями выявления наступления аварийной ситуации являются:
- Массовые обращение пользователей ИС в службу поддержки.
- Обращение Бизнес-администратора, Технолога или Аналитика ИС в службу поддержки.
- Выявление аварийного события в результате Планово-предупредительных мероприятий со стороны службы поддержки.
- Обращение со стороны сотрудников Мониторинга, Администраторов СУБД и серверов приложений.
- Отрицательный результат проверки работоспособности сервисов при вводе системы в эксплуатацию.
К возможным аварийным ситуациям могут относиться:
- Недоступность серверов приложений.
- Недоступность баз данных.
- Некорректная работа системы.
Порядок действий при выявлении аварийного события
- Диагностика возникшей ситуации, первичный сбор информации.
- При невозможности самостоятельного устранения проблемы, оповещение координатора, ответственного за выполнение аварийного восстановления.
- Определение специфики проблемы, привлечение специалистов.
- Выполнение действий по восстановлению согласно выбранному сценарию.
- Оповещение об аварийной ситуации:
- Потребители информации: Бизнес-заказчик, Технолог и Аналитик ИС;
- Канал направления информации: e-mail и sms/звонок (дополнительно: канал информирования на усмотрении службы поддержки);
- Содержание информации: данные о зарегистрированном инциденте (описание События, периметр События, возможные причины, плановые сроки устранения, возможные последствия).
К процессам поддержания и восстановления работоспособности системы должны быть привлечены следующие сотрудники:
- Прикладные Администраторы.
- Администраторы серверов Приложений (в части сопровождения и эксплуатации систем поддержки бизнеса).
Ролевая модель ИС
Ролевая модель реализована отдельно для каждого из модулей ИС:
Типы привилегий и действия в модуле "Дистрибутивы"
| Тип | Сегмент | Допустимые действия | Описание |
|---|---|---|---|
| Приложение | nexus:{name}:{actions} | create,read,update,delete | Управляет доступом к специфичным функциям продукта в интерфейсе администратора (например, nexus:blobstores:create,read разрешает доступ на создание и просмотр блоб-хранилищ) |
| Администратор репозитория | nexus:repository-admin:{format}:{repository}:{actions} | browse,read,edit,add,delete | Даёт право на управление конфигурацией приложения (например, nexus:repository-admin:nuget:nuget.org-proxy:browse,read предоставляет доступ на просмотр репозитория Nuget с именем "nuget.org-proxy") |
| Селекторы | nexus:repository-content-selector:{selector}:{format}:{repository}:{actions} | browse,read,edit,add,delete | Реализует детальный контроль над доступом к содержимому репозитория с помощью селектора содержимого (например, nexus:repository-content-selector:*:maven2:*:read предоставляет доступ к любому содержимому, соответствующему селектору с именем "maven2" |
| Просмотр репозитория | nexus:repository-view:{format}:{repository}:{actions} | browse,read,edit,add,delete | Даёт доступ к содержимому репозитория, без права настройки самого репозитория (например, nexus:repository-view:maven2:central:browse,read предоставляет доступ на просмотр содержимого репозитория формата "maven2" с наименованием "central") |
| Скрипты | nexus:script:{script name}:{actions} | browse,read,edit,add,delete,run | Привилегии для работы с groovy-скриптами |
Назначьте одно или несколько действий при создании новых привилегий (Действия — это функции, допускающие явное поведение, которое привилегия может выполнять со связанной функцией).
При назначении нескольких действий разделяйте каждое действие запятой, но не используйте пробелы после запятых (например, add,view,create). Тип привилегии, к которому вы применяете любое из этих действий, будет выполнять подразумеваемое поведение действия:
| Действие | Описание |
|---|---|
| add | Даёт права на добавление содержимого репозитория или скриптов |
| browse | Позволяет привилегии просматривать содержимое связанных репозиториев В отличие от чтения, типы привилегий с просмотром могут только просматривать и администрировать содержимое репозитория из пользовательского интерфейса |
| create | Позволяет привилегиям создавать применимые конфигурации в менеджере репозитория Поскольку для просмотра конфигурации требуется разрешение на чтение, это действие связано с большинством существующих прав на создание |
| delete | Даёт права на удаление конфигураций менеджера репозитория, содержимого репозитория и скриптов Действие чтения обычно связано с действиями удаления, поэтому субъект может просмотреть эти конфигурации, чтобы удалить их |
| edit | Даёт права на изменение скриптов, содержимого репозитория и настроек |
| read | Даёт права на просмотр различных списков конфигурации и сценариев Без чтения любое связанное с ним действие даст право просматривать эти списки, но не их содержимое Действие чтения также позволяет привилегиям использовать инструменты, которые могут просматривать содержимое из командной строки |
| update | Даёт права на обновление конфигураций менеджера репозитория Большинство существующих привилегий с обновлением включают действия чтения, поэтому при создании настраиваемых привилегий с обновлением рассмотрите вариант добавления чтения к привилегии, чтобы просматривать обновления конфигурации менеджера репозитория |
| * | Является обобщением, дающим возможность группировать все действия вместе Использование * применяет все другие используемые действия к привилегии |
Типы привилегий и действия в модуле "Лицензии"
В модуле лицензий привилегии реализуются через сервис engr-auth.
| Действие | Идентификатор (id) | Описание |
|---|---|---|
| Проверка библиотек | license:check | Видит модуль "Проверка лицензий", может зайти и проверить лицензию |
| Формирование отчетов | license:audit | Видит модуль "Аудит", может зайти и сформировать отчет |
| Просмотр политик | license:view_policy | Видит модуль "Управление политиками", может зайти и видеть политики, может перейти к просмотру детальной информации |
| Управление политиками | license:manage_policy | Видит модуль "Управление политиками", может зайти и видеть политики, может перейти к просмотру детальной информации и создавать/удалять политики |
Список ролей (описан в скрипте roles.sql, можно настроить другим при необходимости):
| Роль | Название | Действия |
|---|---|---|
| license:viewer | Пользователь | Проверка библиотек |
| license:auditor | Аудитор | Проверка библиотек Формирование отчетов |
| license:policy_viewer | Наблюдатель за политиками | Проверка библиотек Просмотр политик |
| license:policy_manager | Управляющий политиками | Проверка библиотек Просмотр политик Управление политиками |
| license:admin | Администратор | Все |
Журналирование
Журналирование ИС "Дистрибутивы и лицензии" реализуется стандартными средствами для Java-приложений на основе библиотеки logback.
Журналирование модуля "Дистрибутивы"
Настройки уровня логирования осуществляются через файл конфигурации библиотеки logback, расположенного в папке /nexus-data/etc/logback/logback.xml.
Включение логирования в json-формате осуществляется через переменные окружения:
logging.appender.console.json.level=DEBUG
logging.appender.console.plain.level=OFF
Структура лог-файлов в формате json:
{
"product": "ppdl", // название продукта
"serviceName": "ppdl-backend", // название сервиса
"serviceId": "83f1ee4a-dbbd-4e99-b0df-ae140890d10c", // идентификатор экземпляра сервиса
"serviceVersion": "v1.0.123", // версия сервиса
"localTime": "1686047487000", // отметка времени в милисекундах
"level": "INFO", // уровень логирования
"text": "Текст сообщения", // логируемое сообщение
"loggerName": "ru.t1.example.LoggMe", // имя логгера
"threadName": "thread-1", // поток
"stack": "" // опциональный cтек трассировки при ошибках в виде строки
}
Журналирование модуля "Лицензии"
Настройки уровня логирования осуществляются через файл конфигурации библиотеки logback.
Включение логирования в json-формате осуществляется через переменную окружения: LOGGING_CONFIG=classpath:logback-json.xml.
Включение логирования в режиме простого текста осуществляется через переменную окружения: LOGGING_CONFIG=classpath:logback-plain.xml.
Структура лог-файлов в формате json:
{
"product": "pplc", // название продукта
"serviceName": "pplc-lvcheck-front-service", // название сервиса
"serviceId": "83f1ee4a-dbbd-4e99-b0df-ae140890d10c", // идентификатор экземпляра сервиса
"serviceVersion": "v1.0.123", // версия сервиса
"localTime": "1686047487000", // отметка времени в милисекундах
"level": "INFO", // уровень логирования
"text": "Текст сообщения", // логируемое сообщение
"loggerName": "ru.t1.example.LoggMe", // имя логгера
"threadName": "thread-1", // поток
"stack": "" // опциональный cтек трассировки при ошибках в виде строки
}
Мониторинг ИС
В ИС мониторинг реализован отдельно для каждого из модулей ИС:
Мониторинг модуля "Дистрибутивы"
Для получения метрик сервиса ppdl-back обратитесь по URL-адресу http://host:port/service/metrics/prometheus. Сервис ppdl-back предоставляет метрики в формате Prometheus.
Для получения метрик требуется наличие прав на сбор метрик nx-metrics-all.
Мониторинг модуля "Лицензии"
Для получения метрик сервисов engr-auth, lvcheck-front-api, lvcheck-storage-service и lvcheck-aggregarot-service обратитесь по URL-адресу http://host:port/actuator/prometheus. Сервисы предоставляют метрики в формате Prometheus.
Для получения метрик сервиса scancode-service обратитесь по URL-адресу http://host:port/metrics. Сервис scancode-service также предоставляет метрики в формате Prometheus.
Глоссарий
В документе используются следующие термины и сокращения:
| Термин/Аббревиатура | Определение |
|---|---|
| AD | Active Directory (AD) — службы каталогов корпорации Microsoft, хранилище данных об объектах сети, имеющее иерархическую структуру; содержит централизованный список всех пользователей и групп в сети |
| API | Application programming interface, программный интерфейс управления |
| LDAP | Lightweight Directory Access Protocol – облегчённый протокол доступа к каталогам, открытый стандартизированный протокол, применяемый для работы с различным реализациям служб каталогов, в том числе и Active Directory |
| БД | База данных |
| ИС | Информационная система "Дистрибутивы и лицензии" |
| СУБД | Система управления базой данных |