Introducción
MarketLedger necesita un informe de liquidación para sus pequeños vendedores del mercado. El informe debe leer los totales de ayer, no las direcciones de correo de los clientes ni las referencias bancarias, y no debe escribir pedidos. Su política actual de creación de cuentas es más amplia de lo que necesita ese trabajo.
Limitarás esa política, obtendrás un inicio de sesión temporal real de PostgreSQL mediante OpenBao y guardarás un informe completo separado por tabulaciones usando la consulta suministrada. Necesitas conocimientos básicos de terminal y rutas. Los permisos SQL, los archivos de credenciales y las opciones relevantes de los comandos se explican antes de usarlos; no se requiere programación en Python ni una cuenta en la nube.
Observa la tienda y el informe que necesita
En este paso empezarás con el negocio en funcionamiento y un informe normal antes de cambiar permisos. Usa Terminal durante todo este laboratorio. cd cambia de directorio; una ruta absoluta funciona desde cualquier lugar:
cd /home/labex/project/market-report
PostgreSQL es la base de datos preparada. OpenBao es un servicio de secretos preparado que puede pedir a esa base de datos que cree un nuevo inicio de sesión durante un tiempo limitado. Son procesos reales en el contenedor de este laboratorio. No son una base de datos alojada ni un despliegue de secretos de producción.
El shop.py preparado es un cliente pequeño del servicio de tienda en funcionamiento. Ejecutarlo no requiere escribir Python. list muestra los pedidos de hoy:
python3 shop.py list
Inicialmente se espera una lista vacía, []. Realiza un pedido normal. --order identifica el pedido, --vendor identifica a su vendedor y --cents da el importe como un número entero de céntimos:
python3 shop.py place --order O201 --vendor V101 --cents 600
Se espera un pedido guardado y pagado para la fecha comercial sintética 2026-10-29. Si repites el comando, el servicio rechaza el ID duplicado; usa list para ver el pedido existente en lugar de eliminarlo o sobrescribirlo.
La liquidación abarca la fecha anterior, 2026-10-28. El nuevo pedido de hoy no debe alterar los totales de ayer. cat muestra un archivo de texto; inspecciona el informe de ejemplo funcional preparado:
cat demo.tsv
Se esperan tres filas de vendedores:
vendor_id vendor_name paid_orders total_cents
V101 Birch Pantry 2 4700
V102 Elm Bakery 1 2000
V103 Maple Kitchen 1 2700
Los separadores son caracteres de tabulación, por eso el nombre del archivo termina en .tsv. Cuatro pedidos pagados suman 9400 céntimos. Se excluye el pedido cancelado de Elm. La demostración se leyó con un lector preparado independiente; copiarla no demuestra que tu nueva identidad de base de datos pueda ejecutar el informe.
Una vista es una consulta de base de datos con nombre que expone resultados seleccionados. reporting.daily_settlement une los nombres de vendedores con los totales de pedidos pagados y omite las direcciones de correo de clientes y las referencias bancarias. Los registros originales permanecen en las tablas privadas public.orders y public.vendors. Aquí reporting y public son nombres de esquemas que agrupan objetos de base de datos; la palabra public no significa que todos los roles deban tener acceso.
Puedes editar role.sql, registrar el rol de OpenBao settlement-report, obtener las credenciales de ese rol y crear tus archivos de informe y credenciales. Conserva sin cambios la tienda, los registros originales de la base de datos, el otro rol de informes, la consulta suministrada, el archivo de entorno, el token del operador y el entorno de ejecución preparado. No necesitas una contraseña de administrador de base de datos ni un token raíz de OpenBao.
Ante un error ordinario No such file or directory, vuelve con el cd absoluto anterior, usa ls para comprobar los nombres reales de los archivos y reintenta. No restablezcas el entorno para corregir un error de escritura.
Limita la política de creación de cuentas a la vista de liquidación
En este paso eliminarás permisos que el informe no necesita. Empieza en Terminal, en /home/labex/project/market-report.
Lee las sentencias actuales de creación de cuentas:
cat role.sql
OpenBao sustituye tres marcadores cuando emite credenciales: {{name}} pasa a ser un nuevo nombre de usuario de base de datos, {{password}} una contraseña generada y {{expiration}} la hora de caducidad de la cuenta. Conserva estos marcadores; no los sustituyas por tu propio nombre de usuario o contraseña fijos.
CREATE ROLE ... WITH LOGIN crea un inicio de sesión de PostgreSQL. VALID UNTIL limita cuándo puede su contraseña autenticar una nueva conexión. No termina todas las conexiones que ya estaban abiertas. Estudiarás la revocación explícita y la caducidad natural de las concesiones en el siguiente laboratorio guiado.
GRANT concede un permiso. USAGE ON SCHEMA reporting permite buscar objetos en ese esquema. SELECT ON reporting.daily_settlement permite leer esa única vista. Los permisos adicionales actuales sobre public permiten leer tablas privadas y cambiar pedidos; este informe no necesita ninguna de esas capacidades.
La línea final ALTER ROLE ... SET log_statement = 'all' habilita la auditoría SQL nativa para cada nuevo inicio de sesión de informes. Consérvala: las consultas realizadas con esa identidad deben seguir siendo atribuibles. Las sentencias de gestión para crear cuentas, que contienen contraseñas, no se registran mediante este ajuste por inicio de sesión. El registro de auditoría preparado de OpenBao también aplica hash a los valores secretos.
Sustituye el archivo por las sentencias más limitadas siguientes. cat > role.sql redirige el texto suministrado a ese archivo. <<'ROLESQL' inicia un here-document; el marcador entre comillas conserva exactamente el texto encerrado hasta la línea que contiene solo 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
Vuelve a leerlo:
cat role.sql
El rol tiene un inicio de sesión generado, una vigencia limitada para la contraseña, permiso para buscar en el esquema y acceso de lectura a una vista. No tiene acceso a tablas originales, permisos de escritura ni atributos de administrador. Un permiso sobre una vista es útil aquí porque la vista suministrada omite intencionadamente los datos privados; una vista que expusiera esos campos privados no ofrecería el mismo límite.
Si el terminal espera más entrada porque omitiste el marcador final, escribe ROLESQL solo en una línea. Si el archivo guardado está incompleto, repite el bloque entero. Esto solo cambia tu archivo de política, todavía no la base de datos en funcionamiento.
Registra la política con el operador restringido de OpenBao
En este paso registrarás tu política de cuentas sin usar una identidad de administrador del servicio de secretos. Permanece en Terminal.
Lee el archivo de entorno preparado antes de cargarlo:
cat env.sh
source env.sh ejecuta esas asignaciones en el shell actual de este terminal. export pone un valor a disposición de los comandos hijos. El archivo añade la herramienta bao preparada a PATH, la lista de búsqueda de comandos del shell, y establece las direcciones locales de OpenBao y PostgreSQL. $(cat ...) lee el token del operador preparado desde su archivo privado; no se muestra el token. Estos ajustes pertenecen a esta sesión de terminal. Un terminal nuevo debe cargarlos otra vez:
source env.sh
Un token de operador de OpenBao autoriza solicitudes al servicio de secretos. No es un nombre de usuario ni una contraseña de PostgreSQL. Este token puede gestionar y obtener credenciales de settlement-report y revocar las concesiones exactas de ese rol. No puede leer la conexión de gestión de la base de datos ni gestionar el informe de inventario independiente.
bao write escribe configuración en la ruta de OpenBao indicada. db_name=market selecciona la conexión de base de datos preparada. creation_statements=@role.sql lee tu archivo SQL como valor de ese campo; @ es la sintaxis de entrada de archivo de OpenBao. default_ttl=10m concede diez minutos por defecto a las nuevas concesiones y max_ttl=15m limita su configuración de duración. Un TTL es un tiempo de vida. Usa estos límites breves para el informe en lugar de horas o una cuenta ilimitada:
bao write database/roles/settlement-report db_name=market creation_statements=@role.sql default_ttl=10m max_ttl=15m
Se espera la confirmación de que se escribieron datos en database/roles/settlement-report. Esto cambia la política de creación; todavía no ha emitido un inicio de sesión de base de datos. Un cambio de política afecta a cuentas futuras. No retira permisos a un inicio de sesión ya emitido. Después de cualquier cambio de política registrado, obtén una nueva credencial y regenera tu informe con ella. La comprobación final exige que la identidad del informe se haya emitido después del registro definitivo de tu política. No dejes activo un inicio de sesión anterior de informes con permisos excesivos; la recuperación condicional del siguiente paso muestra cómo terminar su concesión exacta antes de sustituir su archivo de credenciales.
La autocomprobación de política lee la política registrada actual y prueba su SQL en un entorno de prueba desechable de PostgreSQL. No emite una concesión, modifica la base de datos activa ni ejecuta tu informe real. sudo permite a este comprobador preparado inspeccionar la configuración protegida y ejecutar su cuenta ordinaria aislada; tus comandos normales de OpenBao y base de datos usan las identidades restringidas:
sudo python3 /opt/labex-report/verify.py policy
Si informa de un permiso adicional o de una caducidad ausente, corrige role.sql y regístralo otra vez. Conserva los marcadores y la cláusula de auditoría. Se aceptan sentencias de permisos equivalentes que implementen el límite indicado; la comprobación no exige un editor ni una escritura SQL concretos.
Obtén un inicio de sesión temporal y ejecuta el informe real
En este paso usarás una identidad de base de datos recién emitida para producir tu archivo de liquidación. Empieza en la misma sesión de Terminal, con env.sh cargado.
Una respuesta de credenciales contiene tres elementos diferentes: un ID de concesión que identifica esta emisión en OpenBao, un nombre de usuario generado de PostgreSQL y su contraseña. El token del operador del paso anterior autorizó la emisión; no es una de estas credenciales de base de datos.
Mantén privados los archivos de credenciales. umask 077 hace que los archivos nuevos solo puedan ser leídos y escritos por tu cuenta; no cambia archivos existentes:
umask 077
bao read solicita credenciales para el rol. -format=json elige una salida JSON estructurada. > guarda esa salida en lease.json, sustituyendo un archivo existente con ese nombre. Este comando crea realmente un nuevo inicio de sesión de PostgreSQL y pone en marcha el reloj de su concesión; no lo ejecutes repetidamente solo para inspeccionar la misma concesión:
bao read -format=json database/creds/settlement-report > lease.json
jq selecciona campos JSON. -r muestra valores de cadena sin las comillas de JSON. Lee la identidad no secreta, el ID de concesión y su duración; no muestres la contraseña:
jq '.lease_id, .lease_duration, .data.username' lease.json
Se espera un ID de concesión database/creds/settlement-report/..., una duración de 600 segundos y un nombre de usuario generado. Sus sufijos aleatorios serán distintos en cada ocasión.
El cliente de PostgreSQL psql lee PGUSER y PGPASSWORD del entorno. Las sustituciones $(...) entre comillas los establecen a partir de esta emisión. Estos valores permanecen en esta sesión de terminal y sus comandos hijos:
export PGUSER="$(jq -r .data.username lease.json)"
export PGPASSWORD="$(jq -r .data.password lease.json)"
psql -X ignora personalizaciones de inicio personales de psql, -v ON_ERROR_STOP=1 detiene la ejecución ante errores SQL y -c suministra un comando SQL. SELECT current_user pregunta a PostgreSQL qué identidad usa realmente esta conexión:
psql -X -v ON_ERROR_STOP=1 -c 'SELECT current_user;'
Se espera el mismo nombre de usuario generado de lease.json, no el escritor de la tienda, el lector de demostración ni el administrador de la base de datos.
El report.sql preparado selecciona las cuatro columnas públicas del informe, ordena las filas por ID de vendedor y las copia a la salida estándar como datos separados por tabulaciones con encabezado. Conserva la consulta sin cambios. -f lee SQL de ese archivo, mientras que > guarda únicamente su salida de informe:
psql -X -v ON_ERROR_STOP=1 -f report.sql > settlement.tsv
Lee tu resultado real:
cat settlement.tsv
Sus tres filas de vendedores deben coincidir con el ejemplo empresarial anterior: Birch 2 / 4700, Elm 1 / 2000, Maple 1 / 2700. No debe aparecer ningún correo de cliente ni referencia bancaria. El total sigue siendo 9400 céntimos porque el pedido O201 de hoy queda fuera de la liquidación de ayer.
Si una conexión posterior falla con password authentication failed, puede que la concesión de diez minutos haya caducado mientras leías. Es un fallo de credenciales, no una consulta a tabla denegada. Repite una vez el comando de emisión de credenciales, vuelve a cargar tanto PGUSER como PGPASSWORD desde el nuevo archivo y ejecuta otra vez los comandos de identidad e informe. Se espera un nuevo nombre de usuario. No edites el nombre de usuario registrado ni amplíes manualmente la caducidad.
La recuperación es diferente si cambiaste la política después de emitir credenciales. Esa cuenta anterior conserva sus permisos originales. Antes de sustituir su lease.json, ejecuta bao lease revoke "$(jq -r .lease_id lease.json)". La sustitución entre comillas proporciona ese ID de concesión guardado exacto; no es un nombre de usuario de base de datos ni un prefijo de concesiones. Nunca revoques el informe de inventario ni un prefijo completo de concesiones. Después de terminar la emisión anterior, solicita una nueva credencial, vuelve a cargar ambas variables de base de datos y regenera el informe con los comandos anteriores. Esto evita dejar utilizable un inicio de sesión anterior con permisos excesivos junto al nuevo inicio de sesión limitado.
Confirma que los datos privados y las escrituras siguen sin estar disponibles
En este paso probarás el límite de la cuenta conservando la tienda y sus datos originales. Usa el mismo Terminal con tu identidad emitida de PostgreSQL.
La siguiente lectura debe fallar. SELECT * solicita todas las columnas; la política debe detener esta cuenta antes de que pueda leer los pedidos originales:
psql -X -v ON_ERROR_STOP=1 -c 'SELECT * FROM public.orders;'
Se espera un error de PostgreSQL permission denied para el esquema o la tabla privados. $? es el estado de salida del comando inmediatamente anterior; echo lo muestra. Léelo inmediatamente:
echo $?
Se espera 1, una consulta SQL rechazada. Un fallo de conexión con estado 2 no demuestra este límite de permisos; usa la recuperación de reemisión y recarga del paso anterior si la concesión caducó.
Ahora intenta una escritura inocua para los datos: UPDATE ... WHERE false no coincide con ninguna fila, por lo que no podría cambiar pedidos incluso si la cuenta tuviera incorrectamente permisos excesivos. Aun así, debe rechazarse por permisos insuficientes:
psql -X -v ON_ERROR_STOP=1 -c 'UPDATE public.orders SET amount_cents = 0 WHERE false;'
echo $?
De nuevo se espera un error de permisos y estado 1. La cuenta puede leer la vista prevista, pero no puede leer datos privados originales ni escribir pedidos.
El cliente de tienda preparado usa la identidad de escritor independiente del servicio de tienda, en lugar de tus credenciales de informe. Confirma que el pedido que hiciste sigue disponible:
python3 shop.py list
Ejecuta la comprobación final de solo lectura. Primero lee la evidencia nativa existente de emisión de OpenBao y consultas de PostgreSQL; después comprueba tu informe real y los datos empresariales conservados. No crea un inicio de sesión ausente ni genera el informe por ti:
sudo python3 /opt/labex-report/verify.py result
Ahora tienes una liquidación completa producida con una identidad de base de datos real, limitada y emitida dinámicamente. El siguiente laboratorio independiente empieza con la política correcta de permisos y se centra en terminar el acceso y observar fallos de nuevas conexiones.
Resumen
Has registrado una política limitada de creación de cuentas, obtenido un nuevo inicio de sesión de PostgreSQL mediante un operador restringido de OpenBao y utilizado esa identidad para guardar una liquidación real. Su vista expone los totales empresariales necesarios mientras que las tablas privadas, las escrituras y los privilegios de administrador permanecen fuera del alcance del informe.
El token del operador, el ID de la concesión y las credenciales de base de datos tienen funciones distintas. Este ejercicio sigue dependiendo de componentes de gestión preparados de confianza; las cuentas temporales no eliminan esa confianza inicial. El siguiente laboratorio examina la revocación de una concesión exacta, la caducidad natural y la recuperación mediante una nueva emisión.


