Предварительная настройка со стороны DPD
Для интеграции со службой доставки DPD необходимо получить клиентский номер и интеграционный ключ. Для этого зайдите в личный кабинет DPD. В правом верхнем углу будет указан «Номер клиента». В левом меню перейдите в раздел «Получение ключа интеграции» и следуйте инструкциям. После получения интеграционный ключ будет отображаться в этом разделе.
Предварительная настройка системы
Перед подключением модуля требуется выполнить следующие настройки в системе:
- Указать время работы и адрес для складов (Настройки — Магазины — Склады), которые будут использованы в работе при оформлении заказов
- В настройках магазина (Настройки — Магазины) необходимо указать страну (она будет по умолчанию устанавливаться в карточке заказа) и доступные склады.
Подключение
Примечание
Обратите внимание, что при подключении нового интеграционного модуля доставки, в системе автоматически создается новый тип доставки, связанный с этим модулем. В карточке заказа при оформлении доставки, требуется выбирать новый созданный тип справочника, чтобы использовать интеграцию со службой доставки DPD.
Модуль интеграции со службой DPD располагается в «Настройках» системы в разделе «Маркетплейс», в блоке «Доставки». Кликните по модулю интеграции, а затем по кнопке «Подключить» для перехода к настройкам. При первом подключении нужно будет пройти несколько шагов:
Настройки подключения DPD
На этом шаге нужно ввести клиентский номер и ключ, который Вы получили на этапе предварительной настройки DPD. В поле «Дополнительная информация аккаунта» можно ввести строку, определяющую данное подключение в системе.
Сопоставление статусов
Настройте соответствие статусов DPD статусам заказа системы. Данное сопоставление позволяет автоматически изменять статус заказа в системе в зависимости от статуса доставки. Указывать соответствия всем статусам необязательно. Для разных статусов DPD допускается указание одинаковых статусов системы.
Code | Name | Code | Name |
---|---|---|---|
no-data-found | Заказ не найден | 2407 | Получатель отсутствует на адресе доставки |
OrderPending | Заказ отправлен на ручную обработку | 2408 | Указан неправильный адрес доставки |
OrderDuplicate | Дубль заказа | 2409 | Задержано на таможне |
OrderError | Заказ не может быть создан | 2410 | Другие проблемы при доставке |
1001 | Получена заявка | 2411 | Отказано в таможенном оформлении по причине неуплаты таможенных пошлин |
1101 | В заявке присутствует ошибка | 3701 | Заказ поврежден |
1201 | Запрошены паспортные данные получателя | 2501 | Услуга не оказана |
1301 | Отмена заявки | 2601 | Произведен предварительный расчет стоимости доставки |
1401 | Заказ создан | 2602 | Выставлен счет |
1501 | Заказ ожидает дату приема | 2701 | Наложенный платёж принят у получателя |
1601 | Заказ принят у отправителя | 2801 | Наложенный платёж перечислен интернет-магазину |
1701 | Заказ прибыл в страну доставки | 2901 | Заказ отменен |
1801 | Закончено таможенное оформление | 3001 | Произведен расчет стоимости за платное хранение |
1802 | Прибыл на первый сортировочный комплекс DPD | 3201 | Перенос даты доставки по инициативе DPD |
2101 | Заказ следует по маршруту до терминала доставки | 3202 | Изменены условия доставки получателем во время доставки |
2102 | Заказ следует по маршруту до терминала возврата | 3203 | Изменены условия доставки получателем через веб-службу «Управление доставкой |
2201 | Заказ готов к выдаче на пункте | 3204 | Изменены условия доставки получателем через call-centre |
2202 | Заказ готов к передаче курьеру для доставки | 3205 | Изменена дата доставки |
2203 | Заказ на возврат готов к выдаче | 3206 | Изменена дата доставки по инициативе DPD |
2204 | Заказ на возврат готов к передаче курьеру для доставки | 3211 | Перенос даты доставки по инициативе DPD(уменьшение) |
2205 | Таможенное оформление в стране отправления | 3216 | Изменена дата доставки по инициативе DPD(уменьшение) |
2301 | Заказ доставляется получателю | 3301 | Заказ утилизирован |
2302 | Таможенное оформление закончено в стране отправления | 3302 | Посылка не востребована |
2303 | Отправка на транзитном терминале за рубежом | 3303 | Заказ утерян |
2304 | Доставляется получателю за рубежом | 3304 | Заказ доставлен до двери |
2305 | Возвращается отправителю из-за рубежа | 3305 | Заказ выдан на ПВЗ |
2306 | Заказ готов к доставке за рубежом | 3306 | Заказ на возврат доставлен |
2307 | Проблема при доставке за рубежом | 3401 | Накладная в электронном архиве |
2309 | Заказ доставляется отправителю | 3501 | N-я повторная бесплатная доставка |
2310 | Передано спецперевозчику | 3601 | N-я повторная платная доставка |
2401 | Истек срок бесплатного хранения заказа | 3901 | Направлено сообщение Email |
2402 | Оплата за товар по заказу не произведена получателем | 4001 | Звонок получателю |
2404 | Отказ от заказа в момент доставки | 4101 | Направлено сообщение SMS |
2405 | Отказ от заказа по желанию получателя через веб-службу «Управление доставкой | crmDeleted | Удален |
2406 | Отказ от заказа по желанию получателя через контакт центр |
Доступные типы оплат
На этом шаге укажите, какие типы оплат будут доступны для нового типа доставки. Флаг в колонке «Наложенным платежом» означает, что с этим способом оплаты можно отправлять заказ наложенным платежом.
Склады
На шаге «Склады» можно для каждого склада указать точное соответствие города из справочника DPD, терминал, который по умолчанию будет подставляться при оформлении заказа, номер телефона склада, а также номер регулярного заказа. Номер регулярного заказа нужен, если используете доставку на регулярной основе. Уточните этот номер у своего менеджера DPD. В случае, если используется несколько номеров регулярных заказов для одного склада используйте опцию «Номера регулярных заказов». При отправке товара с терминала отгрузки, то на странице требуется указать сопоставление склада, созданного в системе, с терминалом и городом отгрузки DPD (является обязательным для заполнения). Выбор доступных городов появляется при вводе любого символа в соответствующее поле.
Опция «Номера регулярных заказов» позволяет добавлять и изменять список номеров регулярных заказов. При заполнении опции, то есть при добавлении одного или более номеров регулярных заказов в модуле, в карточке заказа в системе появляется поле «Номер регулярного заказа». С помощью этого поля для конкретного заказа в системе можно выбрать один из добавленных номеров заказа в настройках модуля, либо выбрать использование номера регулярного заказа (вариант «По умолчанию»), который указан в настройках соответствия склада в модуле. Поле не является обязательным для заполнения. При отсутствии заполнения поведение модуля то же, что и при выборе варианта «По умолчанию». Если в модуле опция не заполнена, то в карточке заказа в системе поле «Номер регулярного заказа» отображаться не будет.
Список терминалов отгрузки зависит от города, указанного в настройках склада в системе.
Уведомление «Не найдены терминалы» может быть отображено, если в настройках склада в системе неверно задан адрес (он должен быть связан с Geohelper), проверьте заполнение полей «Регион» и «Город».
Настройки интеграции
Заполните настройки интеграции.
Поле «Тип плательщика по умолчанию» — можно указать, кто будет по умолчанию оплачивать заказ: «Отправитель» (магазин) или «Получатель» (клиент).
Поле «Стоимость доставки» позволяет выбрать два варианта:
- «Рассчитывается автоматически службой доставки» — стоимость будет передаваться автоматически из DPD при выборе типа доставки и сохранении заказа.
- «Задается вручную» — стоимость доставки указывается вручную или же передается по API.
При включенной настройке «Нулевая объявленная стоимость по умолчанию» объявленная стоимость товаров в заказе при оформлении будет равна нулю.
«По умолчанию не синхронизировать со службой доставки» — при активации данной настройки заказ будет добавляться с включенным флагом «Не синхронизировать со службой доставки», то есть изменения заказа не будут передаваться в DPD при сохранении заказа.
Для указания даты приёма груза, в том случае, когда эта дата не совпадает с датой отгрузки, нужно включить настройку «Отображать поле «Дата приема груза»»
Настройка «Отображать поля «Общее количество грузомест» и «Общий объём»». При её включении в карточке заказа дополнительно отображаются два поля:
- «Общее количество грузомест (посылок)» — позволяет указать общее количество грузомест, если в составе заказа имеется составной товар (одна позиция товара содержит несколько грузомест). Поле не является обязательным для заполнения. При отсутствии значения, число грузомест будет сформировано по количеству упаковок в заказе.
- «Общий объём (куб. м)» — позволяет указать общий объём всех грузомест в заказе. Поле не является обязательным для заполнения. При отсутствии значения, общий объём будет расчитан по габаритам всех упаковок.
Опция «Отображать фильтр по типу ПВЗ в карточке заказа». При активации опции, в системе появится дополнительное поле «Доступные типы ПВЗ при расчете» со списком значений: «Все типы», «Пункты приема/выдачи посылок (ПВП)», «Постаматы (П)», «Терминалы». При выборе конкретного значения, в списке тарифов будет выводиться только этот тип ПВЗ. Также доступно указать значение по умолчанию для этого поля на странице модуля «Значения по умолчанию».
Следующими тремя настройками можно регулировать учет комиссии за наложенный платеж: включить комиссию в стоимость доставки, указать ставку и минимальную сумму комиссии.
Пример использования комиссии за наложенный платёж: сумма заказа 10’000р., сумма доставки 500 р., комиссия 5%:
- Настройка «Добавлять комиссию за наложенный платеж в стоимость доставки» не включена. Тогда с покупателя будет взята сумма в размере 10’500 р., из которых продавец платит комиссию 5% = 525 р. и сумму доставки 500 р. Итоговый доход = 9’475 р.
- Настройка «Добавлять комиссию за наложенный платеж в стоимость доставки» включена. Тогда покупателю будет выставлена сумма 11’052,63 р., из которых продавец платит комиссию 5% = 552,63 р. и сумму доставки 500 р. Итоговый доход = 10’000 р.
Для использования дополнительных услуг «Электронное сообщение о доставке груза получателю» и «Электронное сообщение о приеме заказа» необходимо заполнить «E-mail для получения уведомлений».
Опции «Статус для возвращенных товаров» и «Статус для доставленных товаров» позволяют передавать статус товара при полной и частичной доставке.
В случае полной доставки или полного возврата, соответствующий статус проставляется всем товарам. Если в заказе были товары в статусе отмены, модуль их игнорирует. В случае частичной доставки, статусы передаются соответствующим товарам.
Важно!
API DPD не работает с маркированными товарами. Поэтому при частичной доставке, если есть несколько единиц позиции с маркировкой, позиция будет разделена и будут установлены соответствующие статусы, но конкретные маркировки в итоговых позициях будут распределены случайным образом.
Возможные ошибки и причины пропуска обработки частичной доставки:
- Наличие в заказе системы нескольких товаров с одинаковым артикулом и названием.
- Если товар из DPD не был найден в заказе системы (по артикулу и названию).
Условия для обработки частичной доставки в заказе:
- Заказ в DPD перешел в конечный статус;
- Заказ в DPD перешел в конечный статус, и в нем имеется список товаров;
- Установлен хотя бы один из двух статусов для товаров в настройках («Статус для возвращенных товаров» /«Статус для доставленных товаров»)
- Успешная обработка частичной доставки может проходить только один раз (с обновлением списка товаров в заказе системы)
Важно!
Для корректной работы частичной доставки необходимо включить в настройках системы (Настройки — Системные — Заказ) опцию «Возможность добавлять в заказ одинаковые торговые предложения как разные позиции» — это нужно для возможности разбивки одинаковых товарных позиций на несколько, для указания разных статусов, при неполном возврате.
Значения по умолчанию
На этой вкладке можно указать значения по умолчанию для заполняемых во время формирования заказа полей, указать интервалы времени приема и доставки груза, комментарий к заказу и отметку «ценный груз», означающую, что товары заказа требуют дополнительных мер безопасности, снижающих риск их утери или повреждения при перевозке.
Также по умолчанию можно задать дополнительные услуги, которыми ваш магазин чаще всего пользуется. Рассмотрим некоторые из них:
- SMS и email уведомления — выберите опции, и адресат будет информирован о местонахождении отправки и готов к ее получению.
- Возврат документов отправителю — воспользуйтесь опцией, если необходимо вернуть сопроводительные документы на груз (товарную накладную, акты приема-передачи), заверенные получателем.
- Температурный режим — выберите услугу, если при транспортировке ваших посылок и грузов по России необходимо обеспечить температуру не ниже +5°C.
- Возврат части отправки — например, покупатель может примерить товары и выбрать те, которые готов оплатить. Остальное будет возвращено отправителю. Услуга доступна только в РФ и РБ.
- Доставка крупногабаритных посылок — воспользуйтесь разгрузкой крупногабаритных и тяжелых посылок и подъемом их в то или иное место на любом этаже вашего здания.
- Обрешетка — жесткая упаковка для посылки в виде деревянного каркаса. Активируйте опцию для перевозки хрупких, бьющихся, крупногабаритных и нестандартных грузов. С другими опциями можно ознакомиться на сайте DPD.
При включении дополнительной услуги «Ожидание на адресе» можно указать причину ожидания: «С примеркой», «Простая» и/или «С проверкой работоспособности». Для дополнительной услуги «Возврат части отправки» можно указать тип комплектности, сумму за доставку и минимальную сумму выкупа.
Завершение установки
При нажатии на кнопку «Завершить установку», настройка модуля будет завершена. После, откроется форма личного кабинета, где будет отображен весь список подключенных аккаунтов.
Управление аккаунтами
На странице «Личный кабинет» выводится список подключенных аккаунтов DPD. Перейти в режим редактирования аккаунта можно нажав на кнопку «Редактировать». Добавить новый аккаунт можно нажав на кнопку «Добавить аккаунт».
Важно!
Если ранее вы пользовались данными из справочника объектов для DPD, то чтобы данные поля работали для нового модуля, требуется брать наименование полей из Данных службы доставки, подключенной через API. Данные поля могут быть использованы в печатных формах, письмах, SMS, триггерах, пользовательской валидации, типах цен, быстрых ответах в чате.
Интеграционные сервисы
Унифицированный подход к интеграции наших программных продуктов между собой и с другими системами, основан на единых принципах:
- SrAPI— открытый программный интерфейс наших продуктов, реализованном на языке хранимых процедур Oracle PL/SQL, построенный на уровне БД
- SrEchelonGateway— универсальный интеграционный сервис, построенный на технологии J2EE, позволяющий гибко настраивать форматы и количество внешних сервисов-респондентов, построенный на уровне БД
- SrServiceBus— многофунциональная сервисная шина построена на уровне сервера приложений, которая может быть сконфигурирована нами “под ключ” для выполнения задач любой сложности — как внутренняя корпоративная шина предприятия, как шлюзовое решение для интеграции сторонних систем, обращение к внешним информационным сервисам и т.п.
Эксплуатируемые в банках разработанные нами интеграционные решения позволяют нам автоматизировать как входящие информационные запросы, так и исходящие, такие как отчетность, рассылка сообщений, обращения к внешним сервисным шинам, сервисам и API всех типов.
Возможна как поставка универсальных шлюзовых сервисов с открытым кодом для настройки API, так и разработка “под ключ” заказных решений в виде шин или комплексов специализированных WEB-сервисов, таких как комплексная интеграция с процессингом платежных карт, порталы систем мобильного банкинга, шлюзы с государственными реестрами и сервисными сайтами, такими как Prozorro.
Как тестировать API, или Postman для чайников
Привет! Меня зовут Игорь Гросс, я руководитель проектов в Test IT — это такая система управления тестированием. В этом посте я расскажу об одном интересном инструменте тестировщика — Postman — а также о том, как с его помощью решать распространённый тип задач — тестирование API.
Что это вообще такое?
API — это Application Programming Interface, или программный интерфейс приложения, с помощью которого одна программа может взаимодействовать с другой. API позволяет слать информацию напрямую из одной программы в другую, минуя интерфейс взаимодействия с пользователем.
Как это работает? Представьте, что вы сидите в ресторане, выбираете блюдо в меню. Подходит официант, и вы делаете заказ. Официант передаёт ваш заказ на кухню, там происходит магия, и через некоторое время перед вами появляется готовое блюдо. API работает по такому же принципу — принимает ваш запрос, передаёт информацию системе, обрабатывает её и возвращает ответ.
Какие бывают? API может быть внутренним, частным — когда программные компоненты связаны между собой и используются внутри системы. А может быть открытым, публичным — в таком случае он позволяет внешним пользователям или другим программам получать информацию, которую можно интегрировать в свои приложения.
Чтобы программам общаться между собой, их API нужно построить по единому стандарту. Одним из них является REST — стандарт архитектуры взаимодействия приложений и сайтов, использующий протокол HTTP. Особенность REST в том, что сервер не запоминает состояние пользователя между запросами. Иными словами, идентификация пользователя (авторизационный токен) и все параметры выполнения операции передаются в каждом запросе. Этот подход настолько прост и удобен, что почти вытеснил все другие.
Как тестировать API?
Тестирование API проводят, основываясь на бизнес-логике программного продукта. Тестирование API относится к интеграционному тестированию, а значит в ходе него можно отловить ошибки взаимодействия между модулями системы или между системами. Для тестирования используют специальные инструменты, где можно отправить входные данные в запросе и проверить точность выходных данных. Одним из таких инструментов как раз и является Postman. Вот что он умеет:
- Составлять и отправлять запросы;
- Сохранять запросы в папки и коллекции;
- Параметризовать запросы;
- Добавлять к вызову API контрольные точки;
- Создавать разные окружения для одних и тех же запросов;
- Запускать коллекции с помощью Collection Runner и использовать их как автоматизированные тесты.
Чтобы рассказать, как использовать Postman, напишем несколько тестов на базе реального проекта, используя для этого API системы управления тестированием Test IT.
Работа с запросами и отправка запросов в Postman
У Postman есть графический интерфейс, что выгодно отличает его от ряда других инструментов тестирования. Чтобы создать запрос, нужно нажать на кнопку New и выбрать пункт Request.
Запросы Postman хранятся в коллекциях, поэтому нужно не только придумать название и описание запроса, но и создать коллекцию, где он будет храниться.
Создадим запрос на получение проектов. Назовём его соответственно: /api/v2/projects
По умолчанию открывается форма создания GET-запроса:
Для удобства мы указали на иллюстрации выше пункты, соответствующие порядку действий:
1. Выбираем тип запроса. Postman предлагает внушительный список, нам нужен GET.
2. Указываем URL запроса. Первая часть ссылки должна содержать адрес сервера, где развёрнута наша TMC. Мы используем публичное API Test IT, а при составлении запросов опираемся на Swagger-документацию. В нашем случае полная ссылка будет выглядеть так: https://testit.geekbrains.ru/api/v2/projects.
3. На вкладке параметров указываем ключи и значения запроса. Мы хотим получить только удалённые проекты, и API Test IT предоставляет нам такую возможность. Укажем в параметрах isDeleted=true.
4. Переходим на вкладку Authorization, указываем данные для идентификации пользователя. Postman поддерживает множество типов авторизации, параметры для каждого из них отличаются. Используем авторизацию по API Key, полученному из личного кабинета в Test IT.
Мы заполнили все необходимые данные. Теперь выполним запрос, нажав кнопку Send.
Видим, что запрос прошёл успешно: код 200, тело ответа, время ответа и сколько занимают полученные данные. Правда, в нашем случае тело ответа будет пустое, поскольку удалённых проектов у нас нет. Советуем в ключ isDeleted ставить значение true.
Отправляемый запрос или ответ мы можем сохранить с помощью меню справа:
Параметризация запросов, переменные окружения
У нас есть коллекция запросов, и мы хотим использовать их на разных окружениях. Допустим, выполнять их локально, на тестовом стенде и на проде. Посмотрим, что предлагает Postman, и как это работает.
В меню создания выбираем Environment
В ранее созданном запросе выделим в переменные два параметра — URL стенда, к которому мы обращаемся, и токен для авторизации. Назовём наше окружение Test Environment. Создаём две переменные url и token и укажем их значения. На скриншоте ниже их значения скрыты из соображений безопасности.
Сохраняем созданное окружение кнопкой Add. Мы всегда сможем вернуться и отредактировать окружение с помощью кнопки Manage Environments (шестерёнка в правом верхнем углу основного экрана).
Устанавливаем Test Environment в качестве текущего окружения: выбираем из выпадающего списка и вносим параметры в запрос. Переменные указываются в двух фигурных скобках. Postman подсказывает названия переменных окружения при вводе.
После того как мы использовали параметры из переменных окружения, повторим запрос, чтобы проверить, что нигде не ошиблись.
Запрос вновь прошёл успешно, значит, всё сделали правильно.
Теперь создадим другое окружение, с другими URL и token, и поменяем их с помощью переключения в выпадающем списке. Протестируем продукт на двух разных окружениях, используя одну коллекцию запросов.
Создание тестов в Postman
Мы познакомились с отправкой и параметризацией запросов, а когда же приступим к тестированию? Мы на пороге написания первого теста в Postman.
Уже в знакомом нам запросе находим вкладку Tests и переходим в неё.
Открывается окошко для написания кода на JavaScript. Postman предлагает множество готовых сниппетов, которые можно применить для тестирования API. Здесь можно валидировать коды и содержание ответов, парсить и сохранять значения в переменные окружения или глобальные переменные, проверять их соответствие заданным значениям и т.д. Подробнее о написании тестовых скриптов в Postman можно прочитать в документации или статье на Хабре.
Остановимся на создании простого тестового скрипта: проверим, что код ответа 200. Для этого используем готовый сниппет.
Postman автоматически добавил код на JS, который проверяет, что код ответа равен 200.
Помимо этого, напишем проверку. В списке, который мы получили в данном запросе, отсутствуют проекты с параметром isDeleted = false. Надо парсить ответ, в цикле проходить все объекты полученного массива и проверять, что isDeleted = true.
Вот какой код теста получился:
pm.test("All projects is deleted", function () var jsonData = JSON.parse(responseBody); for (var i = 0; i jsonData.length; i++) pm.expect(jsonData[i].isDeleted).to.eql(false) > >);
Мы написали в коде false, а не true, потому что у нас есть только созданные проекты, а удалённых нет. Если оставить true, тест будет провален. Если поменять значение на false — тест будет пройден. Отправим запрос и проверим, что тесты прошли. Результаты тестов и их названия отображаются на вкладке Test Results.
В тренировочном запросе два теста. Чтобы создать ещё один GET-запрос, данные для авторизации и проверку на код ответа 200 нужно продублировать. Чтобы сэкономить время, внесём эти данные на уровень всей коллекции.
Переходим в редактирование коллекции.
Видим уже знакомый интерфейс для настройки авторизации, переносим сюда данные из теста.
А на вкладку Tests перемещаем проверку, что код ответа равен 200.
В запросе убираем продублированную проверку, а на вкладке авторизации укажем «Inherit auth from parent». Сохраняем запрос и отправляем.
Запрос прошёл: с авторизацией всё в порядке, и у нас отображаются 2 теста, хотя один из них мы удалили. Мы вынесли авторизацию и один тест на уровень всей коллекции, и теперь авторизация и тест на код ответа 200 будут применяться ко всем тестам внутри этой коллекции.
Коллекции можно экспортировать, чтобы делиться ими с командой. Если вы авторизуетесь в Postman, то сможете хранить коллекцию в облаке и иметь доступ с разных устройств.
Запуск коллекций тестов в Postman
В Postman есть встроенный компонент Collection Runner, с его помощью можно запустить наполненную запросами и тестами коллекцию.
Нажимаем пиктограмму треугольника на коллекции. Открывается дополнительное окно, в котором выбираем Run. В открывшемся окне выбираем окружение, количество итераций в запуске и задержку между отправкой запросов. Также здесь стоит настроить логирование запросов, хранение переменных и cookies.
Укажем значение Iterations равным 10 и пройдём наши тесты.
Далее можно посмотреть на результаты тестов по каждому запросу, экспортировать результаты по кнопке Export Results либо пролистать их в кратком виде по кнопке Run Summary.
Заключение
Итак, мы познакомились с базовыми возможностями инструмента Postman:
- Составили и отправили запросы;
- Задали параметры в запросах;
- Создали и переключались между окружениями;
- Написали базовые тесты;
- Создали и отредактировала коллекции;
- Выполнили запуск тестов.
Это только малая часть полезных и интересных функций Postman, при помощи которых можно тестировать API. Понравилась статья — поделитесь с коллегами 😉
Если вы хотите освоить не только Postman, но также и другие инструменты ручного и автоматизированного тестирования ПО — приглашаем вас на факультет тестирования ПО GeekUniversity!
Как правильно работать с сѝкретами в проекте
Сѝкрет, с ударением на первый слог (си-и-и-икрет), это производная от английского слова secret. Просто если писать секрет, вместо сикрета, то на ум приходит шпионская тайна, а не доступы до продакшена.
Что такое сикреты
- Любого вида параметры конфигурации сервисов (особенно продакшена)
- любого вида внутренние пароли (например, до базы)
- .env файлы, которые конфигурируют ваши докеры
- файлы сертификатов (например для let’s encrypt)
- ключи до апишек (например выданным вам API_KEY и API_SECRET)
- файлы конфигурации внешнего сервиса (например client_secret.json от Гугла)
- урлы до внутренних продакшен сервисов (10.10.30.1:8080)
- и многое другое, считай, любая конфигурируемая sensitive информация
Когда меня спрашивают, что такое сикреты, я предлагаю людям представить, что у них проект, главной ценностью которого являются данные. Код проекта не несёт в себе большой ценности и может быть опубликован в OpenSource. Так вот, все те данные, которые должны быть заменены на sample или зашифрованы, и являются сикретами.
В общем, все те данные, которые мы обычно прячем как снаружи, так и внутри. Те данные, которые конфигурируют наш сервис. Учитывая то, что в современном мире мы часто используем внешние интеграции, то количество сикретов с каждым днем становится больше.
Проблема
Проблема в том, что мы не можем хранить в открытом виде сикреты в нашем репозитории. Это не безопасно. Даже если ваш репозиторий приватный и не торчит наружу, то, все равно, держать все конфиги внутри приватного репо страшно… Мало ли что может сделать с этими доступами, например, технический писатель или стажер.
Из-за приватных репозиториев современные разработчики расслабились. Организация сикретов в некоторых проектах сегодня оставляет желать лучшего, порой они просто влеплены в код, доступы на продакшн могут лежать почти в открытом виде. Все мы помним недавнюю историю из Gitlab, где ключи от ПРОДАКШЕНА лежали в хендбуке новичка.
Исторически так сложилось, что разработчики суют в .gitignore конфиги, а админы держат их где-то в другом отдельном защищенном месте: в отдельной папочке в гугл драйве, списком в таблице, на флешке в сейфе, в корпоративном 1password.
Это все приводит к двум жопам:
- чтобы новому разработчику запустить интеграционные тесты или как-то поднять сервис, чтобы протыкать, нужно ходить по команде и выпрашивать сикреты. Выясняется, что полный доступ ко всем сикретам только у админа, а он непонятно где. Либо хуже того, никто не знает, где взять те или иные сикреты для работы.
- когда мы добавляем в проект новую интеграцию и кладём в свои сикреты доступы, то нам нужно распинать всю команду, чтобы все обновили свои сикреты. Этого, конечно, толком никто не делает и в результате разрабы утром спуливают проект, запускают, а он не работает.
Обратите внимание на картинку ниже
Решение
Все очень просто: необходимо держать сикреты в репозитории, там где они и должны быть, но в зашифрованном виде. Сикреты расшифровываются либо командой, либо на лету. Расшифровка и шифровка сикретов доступна только определенным юзерам, для этого используется GnuPG (gpg). Такие сикреты можно держать даже в публичном репо.
Давайте еще раз… Мы прямо-таки меняем парадигму отношения к репозиторию, не разносим сикреты по секретным местам, а коммитим и пушим их прямиком в репку проекта.
Сикреты лежат там, где они и должны лежать. Нет больше файла `config.example.yml`. Есть просто `config.yml` где лежит все то, что нужно для работы сервиса. Ок, `config.example.yml` может остаться для того, чтобы те, кто не может расшифровать секрет (джун, тестер или технический писатель) могли понять что там в настройках может находиться. Но рядом с `config.example.yml` лежит зашифрованный `config.yml`. Хотя самым правильным вариантом является следующее: есть полноценный README проекта, где описаны все параметры настроек, что они значат, как их юзать и куда складывать.
Возможен вариант с двумя и более конфигами:
- config.local.yml — локальный настроенный конфиг, не шифрованный, значения могут переопределяться разработчиком через переменные окружения.
- config.testing.yml — конфигурации для тестового окружения, файл подхватывается тестами, не шифрованный. Файл может лежать в репке, а может быть создан самими разрабами, где каждый прописал свои личные данные, например.
- config.production.yml (или config.yml) — шифрованный файл, где хранятся реальные сикреты для прода, используется при деплое. Расшифровывать могут только те, кто отвечает за продакшен.
- ⚠️ эти варианты даны лишь для примера понимания разделения конфигов на шифрованные или не шифрованные, а не для того, как нужно конфигурировать проект. Конфиги могут быть разными, и политика шифрования может быть строже. В этом вопросе каждый проект должен решать самостоятельно, исходя из политики безопасности команды и удобства разработчиков.
Как работает магия GnuPG (gpg)
GnuPG
Перед тем как спускаться в конкретику давайте поймем концепт решения. На рынке есть более-менее три зрелые тулзы для работы с сикретами в гите (git-secret, git-crypt и blackbox — о них ниже) и все они работают с gpg (GnuPG).
Что такое gpg и почему используется именно он? Все просто! gpg шифрует сообщения, используя асимметричные пары ключей, генерируемые пользователями gpg. Открытые ключи шифрования можно, не боясь, передавать друг другу, в то время как зашифрованные сообщения, могут быть расшифрованы только закрытыми ключами, которые каждый пользователь хранит у себя. Подробно ознакомиться можно в Википедии в статье “Криптосистема с открытым ключом”.
Помимо этого gpg позволяет производить шифрование несколькими открытыми ключами, давая возможность пользоваться зашифрованными данными группой лиц, где каждый обладает только своим закрытым ключом. Идеальное решение для команды разработчиков.
В результате у нас появляется шифрованная информация, и при этом нет одного общего пароля, для ее расшифровки. Если мы при шифровании указали открытые ключи Алисы и Боба, то только Алиса и Боб, своими приватными ключами могут расшифровать информацию. Если нужно убрать Боба и добавить Кэрол, то сообщение перешифровывается с ключами Алисы и Кэрол, и без ключа Боба. В результате Боб уже не может расшифровать новую версию зашифрованного сообщения, а Алиса и Кэрол могут.
Особенности работы с gpg
Для начала работы, нам нужно создать нашу пару ключей через gpg. Есть очень подробная дока от Гитхаба на этот счет -> https://help.github.com/articles/generating-a-new-gpg-key/
Это очень краткая, но понятная дока. Однако есть нюанс. На одной из моих машин генерация ключа была настолько долгой, что я подумал о том, что система зависла. В результате оказалось, что настройки железа и ядра системы не дают той энтропии для генерации случайных чисел, чтобы ключ можно было сгенерировать быстро. Для ускорения на stack overflow предлагаются разные решения, вплоть до активного чтения диска через sudo file / и записью в /dev/null данных из /dev/urandom.
Имеем решение простое, нужно установить rng-tools и ключ после этого начинает генерится быстро. rng-tools — это демон для генерации случайных чисел, который для энтропии использует несколько источников. В результате повышается уникальность генерируемых значений и скорость.
Привожу две ссылки для тех, кто столкнется с этой проблемой:
- Начало исследования тут https://serverfault.com/questions/471412/gpg-gen-key-hangs-at-gaining-enough-entropy-on-centos-6.
- Продолжение тут https://serverfault.com/questions/214605/gpg-does-not-have-enough-entropy
Утилиты
Git-crypt
Рассмотрим первый тул из списка: git-crypt https://github.com/AGWA/git-crypt. Особенность, отличающая его от blackbox в том, что он шифрует и расшифровывает ваши сикреты на лету, прозрачно, без явного вызова команд и встраивается в git. Таким образом у вас появляется новая команда в гите: git crypt.
Процесс настройки простой (он весь описан в ридмишке проекта, там очень просто):
- вы создаете файл .gitattributes и в нем прописываете список файлов сикретов либо явно, либо по маске
- добавляете своего gpg юзера
- дальше процесс происходит прозрачно, можно смело пушить конфиги в репо, они будут зашифрованы
Я пару раз ловил себя на мысли, что при пуше очкую, вдруг файл не включится в процесс шифрования, вдруг не сработала маска или криво описал все в .gitattributes. На этот счет я перед пушем запускаю команду git-crypt status -e которая показывает список файлов, которые будут зашифрованы. Вижу там свой файл, успокаиваюсь и пушаю.
Когда выгодней юзать git-crypt?
Когда в проекте всего два участника: вы и ваша CI (или сервер, где вы делаете git pull для деплоя), использовать его — одно удовольствие. Но в git-crypt есть две большие проблемы, которые мешают проекту быть использованным большой командой для серьезной работы:
- Он не поддерживается мейнтейнером вот уже год, а форка-преемника пока не появилось.
- Нет опции удаления пользователей из группы, которая шифрует и дешифрует сикреты. Вот тут: https://github.com/AGWA/git-crypt/issues/47 автор объясняет почему это сложно. Хотя мне кажется, что процедурно не сложно вообще. Как только ты убираешь из группы человека, то есть он выходит из проекта, надо менять все сикреты. Автор считает, что сикреты менять не надо, надо хранить историю… Автор живет в своем виртуальном мире.
Git-secret
Помучив git-crypt и поняв, что он не годится для командной работы выбор пал на очередной тул git-secret. Судя по активности в репозитории и по фичам все очень удобно. Есть нужная функция удаления пользователя и повторной шифровки репозитория после удаления, при этом удаленный пользователь доступов не имеет, а оставшимся не нужно менять свои ключи.
Вот на этом скринкасте автор подробно показывает как работать с продуктом: https://asciinema.org/a/41811
Однако, после того как решил использовать git-secret на интеграционной машине вылезла очень неприятная проблема, давно кем-то описанная в этой ишью: https://github.com/sobolevn/git-secret/issues/136
Вкратце, на машине где идет разработка стоит gpg 2.2.4, а на интеграционной gpg 2.1. Файлы, зашифрованные через git-secret на одной машине могут быть расшифрованны на другой машине только если версии gpg на боксах совпадают.
Казалось бы, давайте обновим версию 2.1 до последней из ветки 2.2, но выясняется, что это не просто сделать, особенно если у вас на сервере не совсем свежая версия дистрибутива. Извратиться, конечно, можно. Вот тут даже есть пошаговая инструкция: https://gist.github.com/vt0r/a2f8c0bcb1400131ff51. Плохо то, что в ней слишком много фрикций. И представьте, если у вас распределенная команда из 10 человек с разным опытом и бэкграундом, с разными операционками на рабочих машинах… Это слишком сложный способ.
Вот тут ребята из git-secret явно намекают, что быстрого фикса не будет https://github.com/sobolevn/git-secret/issues/228. Можно попытаться поэкспортить ключи в разных форматах, можно использовать gpg нужной версии через Докер, можно дождаться, когда в git-crypt запилят фичу Stable public key storage: https://github.com/sobolevn/git-secret/blob/master/RFC/RFC001.md
Blackbox
Нет, это не оконный менеджер https://en.wikipedia.org/wiki/Blackbox. Это система управления сикретами от StackExchange https://github.com/StackExchange/blackbox и, пожалуй, она максимально хорошо задокументирована. Помимо описания работы команд описываются еще и методологические особенности подхода к управлению сикретами. Их ридмишка обязательна к прочтению.
Однако, у blackbox точно такая же болячка, как и у git-secret — несовместимость gpg версий. У меня, следуя дефолтному мануалу, не получилось расшифровать сикреты на интеграционке, ровно по той же причине, что и у git-secret. Но если у git-secret эти проблемы описаны в ишьюсах, то у blackbox я их не нашел… Видимо есть способ использовать ключи в разных форматах.
Разбираться в этом не стал, так как blackbox показался слегка заброшенным и немного древним проектом.
Вывод
Если вы хотите менеджить сикреты для себя одного, то идеальный вариант — это git-crypt. Если у вас команда и есть возможность легко управлять версиями GPG на машинах разработчиков и на серверах — git-secret ваш помощник. У blackbox можно почитать ридми, она самая подробная в концептуальном плане.
Если у кого-то есть успешный опыт починки проблем с разными версиями GPG, то поделитесь этим в комментариях. Если вы встречали людей, которые успешно решили эту проблему, скиньте ссылку на них или на их статьи, пожалуйста. Вы используете для управления сикретами успешно тулзы вне перечисленного списка — будет интересно о них узнать.
Спасибо Павел Калашников за помощь в написании материала.