Дайте расчётному отчёту только необходимые данные

PostgreSQLBeginner
Практиковаться сейчас

Введение

MarketLedger нужен расчётный отчёт для продавцов небольшого рынка. Отчёт должен читать вчерашние итоги, а не адреса электронной почты клиентов или банковские реквизиты, и не должен изменять заказы. Текущая политика создания учётных записей шире, чем требуется этой задаче.

Вы сузите политику, получите настоящий временный логин PostgreSQL через OpenBao и сохраните полный отчёт с разделением табуляцией, используя предоставленный запрос. Нужны базовые навыки работы с терминалом и путями. Права SQL, файлы учётных данных и соответствующие параметры команд объясняются до использования; программирование на Python и облачная учётная запись не требуются.

Изучите магазин и необходимый ему отчёт

На этом шаге вы начнёте с работающего бизнеса и обычного отчёта, прежде чем менять права. На протяжении занятия используйте Terminal. cd меняет каталог; абсолютный путь работает откуда угодно:

cd /home/labex/project/market-report

PostgreSQL — подготовленная база данных. OpenBao — подготовленный сервис секретов, который может попросить эту базу создать новый логин на ограниченное время. Это настоящие процессы в контейнере занятия. Они не являются размещённой у провайдера базой данных или промышленной системой секретов.

Подготовленный shop.py — небольшой клиент работающего сервиса магазина. Для его запуска не нужно писать Python. list показывает сегодняшние заказы:

python3 shop.py list

Вначале ожидайте пустой список, []. Создайте один обычный заказ. --order задаёт заказ, --vendor — его продавца, а --cents — сумму целым числом центов:

python3 shop.py place --order O201 --vendor V101 --cents 600

Ожидайте сохранённый оплаченный заказ за учебную торговую дату 2026-10-29. При повторении команды сервис отклонит дубликат ID; используйте list, чтобы увидеть существующий заказ, а не удалять или перезаписывать его.

Расчёт охватывает предыдущую дату, 2026-10-28. Новый сегодняшний заказ не должен менять вчерашние итоги. cat выводит текстовый файл; изучите подготовленный рабочий пример отчёта:

cat demo.tsv

Ожидайте три строки продавцов:

vendor_id vendor_name paid_orders total_cents
V101 Birch Pantry 2 4700
V102 Elm Bakery 1 2000
V103 Maple Kitchen 1 2700

Разделителями служат символы табуляции, поэтому имя файла заканчивается на .tsv. Четыре оплаченных заказа дают итог 9400 центов. Отменённый заказ Elm исключён. Пример прочитан отдельной подготовленной учётной записью; его копирование не доказывает, что ваша новая идентичность базы может выполнить отчёт.

Представление — именованный запрос базы данных, предоставляющий выбранные результаты. reporting.daily_settlement объединяет имена продавцов с итогами оплаченных заказов и исключает адреса электронной почты клиентов и банковские реквизиты. Исходные записи остаются в приватных таблицах public.orders и public.vendors. Здесь reporting и public — имена схем, группирующих объекты базы; слово public не означает, что доступ должна иметь каждая роль.

Вы можете редактировать role.sql, регистрировать роль OpenBao settlement-report, получать её учётные данные и создавать файлы отчёта и учётных данных. Не меняйте магазин, исходные записи базы, другую роль отчёта, предоставленный запрос, файл среды, токен оператора и подготовленную среду выполнения. Пароль администратора базы или корневой токен OpenBao вам не нужны.

При обычной ошибке No such file or directory вернитесь приведённой выше абсолютной командой cd, проверьте фактические имена файлов через ls и повторите команду. Не сбрасывайте среду для исправления опечатки.

Ограничьте политику создания учётных записей расчётным представлением

На этом шаге вы удалите права, не нужные отчёту. Начните в Terminal, в /home/labex/project/market-report.

Прочитайте текущие инструкции создания учётных записей:

cat role.sql

При выдаче учётных данных OpenBao подставляет три значения: {{name}} становится новым именем пользователя базы, {{password}} — сгенерированным паролем, а {{expiration}} — временем истечения срока учётной записи. Сохраните эти заполнители; не заменяйте их собственными фиксированными именем или паролем.

CREATE ROLE ... WITH LOGIN создаёт логин PostgreSQL. VALID UNTIL ограничивает время, когда его пароль может аутентифицировать новое соединение. Он не завершает все уже открытые соединения. Явный отзыв и естественное истечение срока аренды вы изучите в следующем занятии с инструкциями.

GRANT даёт право. USAGE ON SCHEMA reporting разрешает поиск объектов этой схемы. SELECT ON reporting.daily_settlement разрешает чтение одного этого представления. Текущие дополнительные права на public разрешают чтение приватных таблиц и изменение заказов; этому отчёту не нужно ни то ни другое.

Последняя строка ALTER ROLE ... SET log_statement = 'all' включает встроенный аудит SQL для каждого нового логина отчёта. Сохраните её: запросы этой идентичности должны оставаться атрибутируемыми. Управляющие инструкции создания учётных записей, содержащие пароли, не журналируются этой настройкой отдельного логина. Подготовленный журнал аудита OpenBao также хеширует секретные значения.

Замените файл приведёнными ниже более узкими инструкциями. cat > role.sql перенаправляет переданный текст в файл. <<'ROLESQL' начинает here-document; маркер в кавычках сохраняет заключённый текст точно до строки, содержащей только ROLESQL:

cat > role.sql <<'ROLESQL'
CREATE ROLE "{{name}}" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';
GRANT USAGE ON SCHEMA reporting TO "{{name}}";
GRANT SELECT ON reporting.daily_settlement TO "{{name}}";
ALTER ROLE "{{name}}" SET log_statement = 'all';
ROLESQL

Прочитайте сохранённый файл:

cat role.sql

У роли есть сгенерированный логин, ограниченный срок действия пароля, право поиска в схеме и чтение одного представления. Нет доступа к исходным таблицам, прав записи или атрибутов администратора. Право на представление полезно здесь потому, что предоставленное представление намеренно исключает приватные данные; представление с такими приватными полями не обеспечило бы ту же границу.

Если терминал ожидает ввод из-за пропущенного завершающего маркера, введите ROLESQL в отдельной строке. Если сохранённый файл неполон, повторите весь блок. Это меняет только файл политики, но пока не работающую базу.

Зарегистрируйте политику через ограниченного оператора OpenBao

На этом шаге вы зарегистрируете политику учётных записей без использования идентичности администратора сервиса секретов. Оставайтесь в Terminal.

Прочитайте подготовленный файл среды перед загрузкой:

cat env.sh

source env.sh выполняет эти присваивания в текущей оболочке терминала. export делает значение доступным дочерним командам. Файл добавляет подготовленный инструмент bao в PATH, список поиска команд оболочки, и задаёт локальные адреса OpenBao и PostgreSQL. $(cat ...) читает подготовленный токен оператора из закрытого файла; сам токен не выводится. Эти настройки принадлежат текущему сеансу терминала. В новом терминале их нужно загрузить снова:

source env.sh

Токен оператора OpenBao разрешает запросы к сервису секретов. Он не является именем пользователя или паролем PostgreSQL. Этот токен может управлять ролью settlement-report, получать её учётные данные и отзывать точные аренды этой роли. Он не может читать управляющее соединение базы или управлять отдельным отчётом инвентаризации.

bao write записывает конфигурацию по указанному пути OpenBao. db_name=market выбирает подготовленное соединение базы. creation_statements=@role.sql читает ваш SQL-файл как значение этого поля; @ — синтаксис чтения файла OpenBao. default_ttl=10m задаёт новым арендам десять минут по умолчанию, а max_ttl=15m ограничивает настройку их срока жизни. TTL — время жизни. Используйте для отчёта эти короткие пределы вместо часов или бессрочной учётной записи:

bao write database/roles/settlement-report db_name=market creation_statements=@role.sql default_ttl=10m max_ttl=15m

Ожидайте подтверждение записи в database/roles/settlement-report. Это меняет политику создания; логин базы ещё не выдан. Изменение политики влияет на будущие учётные записи. Оно не удаляет права уже выданного логина. После любого изменения зарегистрированной политики получите новые учётные данные и пересоздайте отчёт с ними. Проверка завершения требует, чтобы идентичность отчёта была выдана после окончательной регистрации политики. Не оставляйте активным предыдущий логин отчёта с избыточными правами; условное восстановление на следующем шаге покажет, как закончить его точную аренду до замены файла учётных данных.

Самопроверка политики читает текущую зарегистрированную политику и испытывает её SQL в одноразовой тестовой среде PostgreSQL. Она не выдаёт аренду, не меняет рабочую базу и не запускает ваш рабочий отчёт. sudo позволяет подготовленной проверке изучать защищённую конфигурацию и запускать изолированную обычную учётную запись; ваши обычные команды OpenBao и базы используют ограниченные идентичности:

sudo python3 /opt/labex-report/verify.py policy

Если сообщается о лишнем праве или отсутствующем сроке действия, исправьте role.sql и зарегистрируйте снова. Сохраните заполнители и условие аудита. Эквивалентные инструкции прав, реализующие указанную границу, принимаются; проверка не требует конкретного редактора или написания SQL.

Получите временный логин и выполните настоящий отчёт

На этом шаге вы создадите файл расчётов с помощью вновь выданной идентичности базы. Начните в том же сеансе Terminal, загрузив env.sh.

Ответ с учётными данными содержит три разные вещи: идентификатор аренды, обозначающий эту выдачу в OpenBao, сгенерированное имя пользователя PostgreSQL и его пароль. Токен оператора с предыдущего шага разрешил выдачу; он не является одним из этих учётных данных базы.

Сохраняйте файлы учётных данных закрытыми. umask 077 делает вновь создаваемые файлы доступными для чтения и записи только вашей учётной записи; существующие файлы это не меняет:

umask 077

bao read запрашивает учётные данные роли. -format=json выбирает структурированный вывод JSON. > сохраняет этот вывод в lease.json, заменяя существующий файл с таким именем. Эта команда действительно создаёт новый логин PostgreSQL и запускает отсчёт его аренды; не запускайте её повторно только для изучения той же аренды:

bao read -format=json database/creds/settlement-report > lease.json

jq выбирает поля JSON. -r выводит строки без кавычек JSON. Прочитайте несекретную идентичность, ID аренды и длительность аренды; не выводите пароль:

jq '.lease_id, .lease_duration, .data.username' lease.json

Ожидайте ID аренды database/creds/settlement-report/..., длительность 600 секунд и сгенерированное имя пользователя. Их случайные суффиксы каждый раз различаются.

Клиент PostgreSQL psql читает PGUSER и PGPASSWORD из среды. Подстановки $(...) в кавычках задают их из этой выдачи. Значения остаются в текущем сеансе терминала и его дочерних командах:

export PGUSER="$(jq -r .data.username lease.json)"
export PGPASSWORD="$(jq -r .data.password lease.json)"

psql -X игнорирует персональные настройки запуска psql, -v ON_ERROR_STOP=1 останавливает выполнение при ошибках SQL, а -c передаёт одну команду SQL. SELECT current_user спрашивает PostgreSQL, какую идентичность фактически использует это соединение:

psql -X -v ON_ERROR_STOP=1 -c 'SELECT current_user;'

Ожидайте то же сгенерированное имя пользователя, что и в lease.json, а не учётную запись записи магазина, чтения примера или администратора базы.

Подготовленный report.sql выбирает четыре общедоступных столбца отчёта, упорядочивает строки по ID продавца и копирует их в стандартный вывод как данные с разделением табуляцией и заголовком. Не меняйте запрос. -f читает SQL из этого файла, а > сохраняет только вывод отчёта:

psql -X -v ON_ERROR_STOP=1 -f report.sql > settlement.tsv

Прочитайте фактический результат:

cat settlement.tsv

Три строки продавцов должны совпадать с предыдущим бизнес-примером: Birch 2 / 4700, Elm 1 / 2000, Maple 1 / 2700. Адресов электронной почты клиентов и банковских реквизитов быть не должно. Итог остаётся 9400 центов, потому что сегодняшний заказ O201 не входит во вчерашний расчёт.

Если последующее соединение не проходит с password authentication failed, возможно, десятиминутная аренда истекла, пока вы читали. Это ошибка учётных данных, а не запрещённый запрос к таблице. Повторите команду выдачи учётных данных один раз, загрузите и PGUSER, и PGPASSWORD из нового файла и повторите команды определения идентичности и отчёта. Новое имя пользователя ожидаемо. Не редактируйте записанное имя и не продлевайте срок вручную.

Если вы изменили политику после выдачи учётных данных, восстановление другое. Предыдущая учётная запись сохраняет исходные права. До замены её lease.json выполните bao lease revoke "$(jq -r .lease_id lease.json)". Подстановка в кавычках передаёт именно сохранённый ID аренды; это не имя пользователя базы и не префикс аренды. Никогда не отзывайте отчёт инвентаризации или весь префикс аренд. После завершения предыдущей выдачи запросите новые учётные данные, загрузите обе переменные базы и пересоздайте отчёт приведёнными выше командами. Так рядом с новым ограниченным логином не останется доступного старого логина с избыточными правами.

Подтвердите недоступность приватных данных и записи

На этом шаге вы испытаете границу учётной записи, сохранив магазин и исходные данные. Используйте тот же Terminal с выданной идентичностью PostgreSQL.

Следующее чтение должно завершиться ошибкой. SELECT * запрашивает все столбцы; политика должна остановить эту учётную запись до чтения исходных заказов:

psql -X -v ON_ERROR_STOP=1 -c 'SELECT * FROM public.orders;'

Ожидайте ошибку PostgreSQL permission denied для приватной схемы или таблицы. $? — код выхода непосредственно предыдущей команды; echo выводит его. Прочитайте его сразу:

echo $?

Ожидайте 1, отказ SQL-запроса. Ошибка соединения с кодом 2 не демонстрирует эту границу прав; если аренда истекла, используйте восстановление с повторной выдачей и загрузкой из предыдущего шага.

Теперь попробуйте безопасную для данных запись: UPDATE ... WHERE false не выбирает строк, поэтому не смогла бы изменить заказы даже при ошибочно избыточных правах. Она всё равно должна быть отклонена из-за недостаточных прав:

psql -X -v ON_ERROR_STOP=1 -c 'UPDATE public.orders SET amount_cents = 0 WHERE false;'
echo $?

Снова ожидайте ошибку прав и код 1. Учётная запись может читать предназначенное ей представление, но не может читать исходные приватные данные или изменять заказы.

Подготовленный клиент магазина использует отдельную идентичность записи сервиса магазина, а не ваши учётные данные отчёта. Подтвердите доступность созданного вами заказа:

python3 shop.py list

Запустите проверку завершения, выполняющую только чтение. Сначала она читает существующие встроенные свидетельства выдачи OpenBao и запросов PostgreSQL, затем проверяет фактический отчёт и сохранённые бизнес-данные. Она не создаёт недостающий логин и не генерирует отчёт за вас:

sudo python3 /opt/labex-report/verify.py result

Теперь у вас полный расчётный отчёт, созданный настоящей динамически выданной ограниченной идентичностью базы данных. Следующее независимое занятие начинается с правильной политики прав и посвящено прекращению доступа и наблюдению отказов новых соединений.

Резюме

Вы зарегистрировали ограниченную политику создания учётных записей, получили новый логин PostgreSQL через ограниченного оператора OpenBao и использовали эту идентичность для сохранения настоящего расчётного отчёта. Его представление предоставляет необходимые бизнес-итоги, а приватные таблицы, запись и права администратора остаются вне области отчёта.

Токен оператора, ID аренды и учётные данные базы выполняют разные задачи. Это упражнение по-прежнему опирается на доверенные подготовленные компоненты управления; временные учётные записи не устраняют это исходное доверие. Следующее занятие посвящено отзыву точной аренды, естественному истечению срока и восстановлению через новую выдачу.