Skip to main content
Version: 2023.2.0

Руководство администратора

Данное руководство администратора содержит описание настройки и разворачивания продукта "Дистрибутивы и лицензии", а также особенности администрирования и эксплуатации ИС.

Сервисы ИС​

Для корректной эксплуатации ИС "Дистрибутивы и лицензии" требуется установка следующих сервисов, входящих в продукт:

СервисОписаниеОбраз (версии есть в релизах)Требуется файловая система и точки монтирования
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Нет

Базы данных​

Если названия баз данных будут отличаться от описанных в текущем разделе, то учитывайте это при настройке сервисов, использующих данные БД.

Тип БДНазваниеГде используется
PostgreSQLlicenselvcheck-storage-service
lvcheck-aggregator-service
PostgreSQLlicense_frontlvcheck-front-api
PostgreSQLengr_authengr-auth

Настройка ИС​

Настройка ИС "Дистрибутивы и лицензии" включается в себя настройку каждого сервиса продукта через переменные окружения Docker-контейнеров, подробнее о настройке параметров установки сервисов ИС см. разделы:

Настройка сервиса ppbd-gateway​

Заполните следующие переменные окружения сервиса ppbd-gateway:

ПеременнаяОписаниеЗначение по умолчанию
APPLICATION_AUTHENTICATION_SERVICE_URLURL-адрес сервиса аутентификацииhttp://common-gateway.ppch.svc.cluster.local:8000
APPLICATION_ROUTES_LICENSE_FRONT_URLURL-адрес сервиса проверки лицензий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_URLURL-адрес сервиса репозиториевhttp://ppdl-back:80
SERVER_PORTПорт сервиса репозиториев80

Рекомендуемые лимиты ресурсов:

РесурсЗначение
CPU500m
RAM500Mi

Настройка сервиса 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

Рекомендуемые лимиты ресурсов:

РесурсЗначение
CPU1000m
RAM1500Mi

Настройте БД после развёртывания сервиса, выполнив скрипт 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'Добавление роли пользователю
  • user – идентификатор пользователя
  • role – идентификатор роли
curl -X DELETE 'http://host:port/api/v1/user-space-roles/user/:user/space/*/role/:role'Удаление роли у пользователя
  • user – идентификатор пользователя
  • role – идентификатор роли
curl -X PUT 'http://host:port/api/v1/space-group-roles/space/*/group/:group/role/:role'Добавление роли группе пользователей
  • group – идентификатор группы
  • role – идентификатор роли
curl -X DELETE 'http://host:port/api/v1/space-group-roles/space/*/group/:group/role/:role'Удаление роли у группы пользователей
  • group – идентификатор группы
  • role – идентификатор роли
curl -X POST 'http://host:port/api/v1/sync/ldap'Синхронизация пользователей с LDAP-

Настройка сервиса ppdl-back​

Убедитесь, что значение порта сервиса ppdl-back равно 8081 (нередактируемое значение).

Рекомендуемые лимиты ресурсов:

РесурсЗначение
CPU500m
RAM4096Mi

После развёртывания сервиса выполните первоначальную настройку, запустив следующий скрипт инициализации:

Скрипт инициализации 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_urlURL-адрес установленного сервиса (используется скриптом для доступа к сервису)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_realmRealm неавторизованного пользователяNexusAuthorizingRealm
auth_headerЗаголовок авторизации, в котором сервис api-gateway передает имя пользователя (должно быть идентичным значению, заданным в конфигурации api-gateway)X_AUTH_USER
auth_capability_commentКомментарий к Nexus capability, создаваемой через заголовок auth_headerSfera proxy header
ldap_usernameИмя пользователя LDAP, используемый сервисом ppdl-back для аутентификации пользователей-
ldap_passwordПароль пользователя LDAP-
ldap_hostХост LDAP-
ldap_portПорт LDAP389
ldap_protocolПротокол LDAP (LDAP/LDAPS)LDAP
ldap_searchbaseLDAP 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-apiSfera licensing firewall

Настройка сервиса ppdl-fe​

Заполните следующие переменные окружения сервиса ppdl-fe:

ПеременнаяОписаниеЗначение по умолчанию
REACT_APP_API_PATHДополнительный путь к сервисам API, относительно текущего URL-адреса расположения сервиса ppdl-feapp/ppbd/api

Убедитесь, что значение порта сервиса ppdl-fe в контейнере равно 8000 (нередактируемое значение).

Рекомендуемые лимиты ресурсов:

РесурсЗначение
CPU500m
RAM500Mi

Настройка сервиса lvcheck-front-api​

Заполните следующие переменные окружения сервиса lvcheck-front-api:

ПеременнаяОписаниеЗначение по умолчанию
PATH_TO_STORAGE_SERVICEURL-адрес сервисаhttp://lvcheck-storage-service:80
POSTGRES_HOSTХост ИС-
POSTGRES_PORTПорт ИС-
POSTGRES_DBNAMEИмя БДlicense_front
POSTGRES_USERИмя пользователя БД-
POSTGRES_PASSWORDПароль пользователя БД-
SERVER_PORTПорт сервиса80

Рекомендуемые лимиты ресурсов:

РесурсЗначение
CPU500m
RAM500Mi

Настройка сервиса lvcheck-storage-service​

Заполните следующие переменные окружения сервиса lvcheck-storage-service:

ПеременнаяОписаниеЗначение по умолчанию
PATH_TO_AGGREGATOR_SERVICEURL-адрес сервисаhttp://lvcheck-aggregator-service:80
POSTGRES_HOSTХост ИС-
POSTGRES_PORTПорт ИС-
POSTGRES_DBNAMEИмя БДlicense
POSTGRES_USERИмя пользователя БД-
POSTGRES_PASSWORDПароль пользователя БД-
SERVER_PORTПорт сервиса80

Рекомендуемые лимиты ресурсов:

РесурсЗначение
CPU500m
RAM500Mi

Настройка сервиса lvcheck-aggregator-service​

Заполните следующие переменные окружения сервиса lvcheck-aggregator-service:

ПеременнаяОписаниеЗначение по умолчанию
PATH_TO_LICENSE_MATCHER_SERVICEURL-адрес сервиса scancode-servicehttp://scancode-service:80
POSTGRES_HOSTХост ИС-
POSTGRES_PORTПорт ИС-
POSTGRES_DBNAMEИмя БДlicense
POSTGRES_USERИмя пользователя БД-
POSTGRES_PASSWORDПароль пользователя БД-
VTB_NEXUS_URLURL-адрес репозитория Maven-

Рекомендуемые лимиты ресурсов:

РесурсЗначение
CPU500m
RAM500Mi

Настройка сервиса scancode-service​

Заполните следующие переменные окружения сервиса scancode-service:

ПеременнаяОписаниеЗначение по умолчанию
SERVER_PORTПорт сервиса80

Рекомендуемые лимиты ресурсов:

РесурсЗначение
CPU600m
RAM1500Mi

Настройка прокси для 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
}

где:

№ п/пПараметрОписаниеПример
1codeМнемокод продуктаppbd
2pathПуть до ИСppbd
3titleНаименование продукта, которое будет отображаться в плитке на главной странице канала, а также в боковом меню каналаДистрибутивы и Лицензии
4descriptionОписание продукта (будет отображаться в плитке на главной странице канала)Храни
5groupTitleКатегория продукта (от нее зависит в каком блоке бокового меню будет отображаться ИС)Инженерные инструменты
6iconИконка продукта (путь прописывается на стороне канала, сама иконка добавляется на стороне продукта)
В путь app/{ppbd}/logo.svg нужно подставить код продукта
-
7enabledПризнак отображения плитки в канальном приложении
Допустимые значения:
- true - плитка будет отображаться на главной, а также в боковом меню;
- false - продукт будет скрыт с главной страницы канала и из бокового меню
true
8optionsБлок опций для интерфейсной части (frontend):
  • type – script
  • remoteName – название переменной из remoteEntry.js
  • remoteEntry – app/{path}/remoteEntry.js (подставить код продукта)
  • explosedModule – microFrontend

{
"type": "script",
"remoteName": "sfera_ppdl_container",
"remoteEntry": "app/ppbd/remoteEntry.js",
"exposedModule": "microFrontend"
}
9apiRouteБлок опций для маршрутизации API:
  • id – код ИС
  • predicates – [“/app/{path}/**”], путь по которому будет проксироваться ИС
  • filters – [StripPre x=3], удаляет первые три значения в пути (нужно для корректной маршрутизации)
  • url – url-адрес шлюза продукта (gateway)

{
"url": "http://api-gateway.ppbd.svc.cluster.local:8000",
"filters": [
"StripPrefix=3"
],
"predicates": [
"/app/ppbd/**"
]
}
10mfRouteБлок опций для маршрутизации микрофронтенда:
  • id – код ИС
  • predicates – [“/app/{path}/**”], путь по которому будет проксироваться ИС
  • filters – [StripPre x=2], удаляет первые два значения в пути (нужно для корректной маршрутизации)
  • url – url-адрес интерфейсной части продукта (frontend)

{
"url": "http://ppdl-fe.ppbd.svc.cluster.local:8000",
"filters": [
"StripPrefix=2"
],
"predicates": [
"/app/ppbd/**"
]
}
11wsRouteБлок опций для маршрутизации веб-сокетов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.

Аварийное восстановление ИС​

Критериями выявления наступления аварийной ситуации являются:

  1. Массовые обращение пользователей ИС в службу поддержки.
  2. Обращение Бизнес-администратора, Технолога или Аналитика ИС в службу поддержки.
  3. Выявление аварийного события в результате Планово-предупредительных мероприятий со стороны службы поддержки.
  4. Обращение со стороны сотрудников Мониторинга, Администраторов СУБД и серверов приложений.
  5. Отрицательный результат проверки работоспособности сервисов при вводе системы в эксплуатацию.

К возможным аварийным ситуациям могут относиться:

  1. Недоступность серверов приложений.
  2. Недоступность баз данных.
  3. Некорректная работа системы.

Порядок действий при выявлении аварийного события​

  1. Диагностика возникшей ситуации, первичный сбор информации.
  2. При невозможности самостоятельного устранения проблемы, оповещение координатора, ответственного за выполнение аварийного восстановления.
  3. Определение специфики проблемы, привлечение специалистов.
  4. Выполнение действий по восстановлению согласно выбранному сценарию.
  5. Оповещение об аварийной ситуации:
    • Потребители информации: Бизнес-заказчик, Технолог и Аналитик ИС;
    • Канал направления информации: e-mail и sms/звонок (дополнительно: канал информирования на усмотрении службы поддержки);
    • Содержание информации: данные о зарегистрированном инциденте (описание События, периметр События, возможные причины, плановые сроки устранения, возможные последствия).

К процессам поддержания и восстановления работоспособности системы должны быть привлечены следующие сотрудники:

  • Прикладные Администраторы.
  • Администраторы серверов Приложений (в части сопровождения и эксплуатации систем поддержки бизнеса).

Ролевая модель ИС​

Ролевая модель реализована отдельно для каждого из модулей ИС:

  1. Дистрибутивы.
  2. Лицензии.

Типы привилегий и действия в модуле "Дистрибутивы"​

ТипСегментДопустимые действияОписание
Приложение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тек трассировки при ошибках в виде строки
}

Мониторинг ИС​

В ИС мониторинг реализован отдельно для каждого из модулей ИС:

  1. Дистрибутивы.
  2. Лицензии.

Мониторинг модуля "Дистрибутивы"​

Для получения метрик сервиса 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.

Глоссарий​

В документе используются следующие термины и сокращения:

Термин/АббревиатураОпределение
ADActive Directory (AD) — службы каталогов корпорации Microsoft, хранилище данных об объектах сети, имеющее иерархическую структуру; содержит централизованный список всех пользователей и групп в сети
APIApplication programming interface, программный интерфейс управления
LDAPLightweight Directory Access Protocol – облегчённый протокол доступа к каталогам, открытый стандартизированный протокол, применяемый для работы с различным реализациям служб каталогов, в том числе и Active Directory
БДБаза данных
ИСИнформационная система "Дистрибутивы и лицензии"
СУБДСистема управления базой данных