End Database Access When the Report Is Finished

PostgreSQLBeginner
Practice Now

Introduction

A settlement report needs database access while it runs. Once the job finishes, its saved credential should stop opening new connections. An acceptance message from a secrets service is not enough evidence of that result.

This independent MarketLedger environment starts with the correct view permissions. You will run the report, revoke its exact OpenBao lease, observe a separate lease expire naturally, and recover by obtaining a new login. The shop and its independent inventory report must remain usable. The previous guided lab taught the credential fields and limited report policy; no files or session state carry over.

Start from the Working Shop and Correct Report Policy

In this step, you will identify the normal business and the two report roles before starting either lease clock. Use Terminal throughout. Enter the independent workspace:

cd /home/labex/project/market-report

cat prints the prepared working example:

cat demo.tsv

The settlement covers 2026-10-28: Birch has two paid orders totaling 4700 cents, Elm one totaling 2000, and Maple one totaling 2700. The cancelled order is excluded. The report uses reporting.daily_settlement; private customer emails and bank references are outside its scope.

The prepared shop client talks to the real shop service. Its arguments identify a new order, vendor and amount in cents. Place a normal order for the next synthetic trading date, 2026-10-29:

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

This later order does not belong in yesterday's settlement. If you repeat the command, the service refuses the duplicate; use python3 shop.py list to see the existing order instead of deleting it.

The supplied env.sh contains the local service addresses and reads the restricted operator token from its private file. source loads those assignments into the current shell; export makes them available to child commands. A new terminal must load them again:

source env.sh

The operator token authorizes OpenBao requests; it is not a database password. This token can obtain and revoke the settlement-report and settlement-short roles' exact leases. It cannot manage the independent inventory report or read the database administrator connection.

Read the correct account-creation statements:

cat role.sql

They create a generated login with the supplied password expiry, grant schema lookup and read access to the settlement view, and retain native SQL auditing. Keep these statements and both role configurations unchanged in this lab.

The normal report role defaults to ten minutes. A separate prepared settlement-short role lasts thirty seconds and has the same view permissions. Neither clock starts until you request credentials. You do not need to race through the lesson before setup-created credentials expire.

You may issue these roles' credentials, run the supplied report query, save the report and private credential responses, and revoke the exact report leases you obtained. Preserve the original database records, shop, independent inventory role and lease, supplied query, environment, operator token and prepared runtime. Never revoke a whole lease prefix.

For a path typo, return with the absolute cd above, run ls, and retry with the actual filename. The same recovery works without resetting the environment.

Run the Settlement with a New Temporary Login

In this step, you will produce a real report before ending that job's access. Stay in Terminal, with env.sh loaded.

umask 077 makes newly created files private to your account. bao read -format=json requests a real dynamic credential and emits JSON; > saves it in a file instead of printing its password. This issuance starts the ten-minute lease clock:

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

jq selects JSON fields. Read the non-secret lease ID, duration and generated database username:

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

The lease ID identifies this issuance in OpenBao; the username identifies its PostgreSQL login. Neither is the operator token. Do not overwrite this response merely to inspect it again: you will need its exact lease ID when ending access.

The -r option removes JSON quote marks. Quoted command substitutions load the generated username and password into the database client's environment without printing the password:

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

psql -X ignores personal psql startup files, -v ON_ERROR_STOP=1 stops on SQL errors, and -c supplies a SQL command. Ask the real connection which identity it uses:

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

Expect your newly generated username. -f report.sql reads the prepared query; > saves its actual tab-separated output:

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

Expect all three vendor rows with the same paid-order counts and totals as the working example. Run the read-only result check:

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

The prepared checker uses sudo to read protected native evidence and test policy SQL in an isolated ordinary-account fixture. It does not issue your live credentials or generate the report. A copied demo without a real report query under the issued identity does not pass.

If you read slowly and the login expires before the report runs, request a replacement only once, reload both database variables, and rerun the identity and report commands. For an existing issuance you still intend to end explicitly, retain its response under a separate filename before requesting another. Every replacement used to run the report must also have its own exact lease ended; completion uses the latest real report execution.

Revoke the Finished Job's Exact Lease

In this step, you will end the report job's access and test a new connection with the saved old credential. Stay in Terminal.

bao lease revoke requests revocation of one issuance. The quoted $(jq -r .lease_id lease.json) substitution supplies the complete saved lease ID. Use that exact ID, not a database username and not a prefix containing other leases. If this ten-minute issuance already expired while you were reading, revocation may report that its lease is no longer found. For the explicit-revocation exercise, retain that old response, obtain a replacement normal-role credential under a new filename, reload both database variables, rerun the report, and use the replacement's filename in the command and probe below. An already-expired issuance is not evidence of your explicit revocation:

bao lease revoke "$(jq -r .lease_id lease.json)"

The CLI may say revocation operations were queued. That response alone does not establish that PostgreSQL has refused the old login.

The prepared access.py probe reads the saved credential and opens a new password-authenticated TCP connection. --wait-denied 10 allows up to ten seconds for a password rejection. It distinguishes that rejection from an unavailable database or a refused SQL query; stopping the server cannot satisfy it:

python3 /opt/labex-report/access.py lease.json --wait-denied 10

Expect PostgreSQL's password authentication failed message followed by confirmation that this saved credential cannot open a new connection. The probe reports the native psql status 2. The probe itself returns success only after confirming the expected denial.

echo $? prints the immediately preceding command's exit status. Here expect 0: the probe successfully confirmed the intended failure, rather than psql successfully connecting:

echo $?

Check the completed job:

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

The check requires a native successful exact-lease revocation, the corresponding completed revocation event, a later new authentication failure and an actually unusable PostgreSQL login. It also keeps the complete report and independent shop/report functions intact. It does not revoke anything for you.

This exercise tests fresh connections made by short-lived client commands. Password expiry does not force every already-open connection to close, and this lesson does not claim to clear all production connection pools.

Observe a Separate Lease Expire Naturally

In this step, you will distinguish natural expiry from your explicit revocation. Use Terminal with the same restricted OpenBao operator.

The prepared settlement-short role has a thirty-second TTL. You will request its credential and immediately test a real permitted read in one operation, so reading the following explanation does not consume its useful time. && runs the probe only if credential issuance succeeds:

bao read -format=json database/creds/settlement-short > short-lease.json && python3 /opt/labex-report/access.py short-lease.json

Expect a generated username, the actual three-row settlement view, and Native psql exit: 0. This is a different username and lease ID from the explicitly revoked job. The read-only probe does not create your report file or complete the report job for you.

Now let this lease expire by itself. Do not revoke or renew short-lease.json. The following probe repeatedly opens fresh connections, waiting up to forty seconds for a real password-authentication denial:

python3 /opt/labex-report/access.py short-lease.json --wait-denied 40

If you took more than thirty seconds to read before this command, denial can appear immediately. That is still natural expiry: the previous combined operation already proved the credential initially worked. Otherwise the probe waits until expiry. Expect the native PostgreSQL failure and the probe's confirmation, just as before.

A connection error saying the server is unavailable is not proof of expiry. If initial issuance or its immediate read failed, inspect that error before retrying the combined operation. Do not present an unused, invalid password as evidence that a working credential expired. The final check requires the actual successful short-role read, native expiry event and later authentication refusal.

The lease clock was started by your request, not by setup, and no step requires you to type within an incidental startup window.

Recover with a New Login and End Its Access Too

In this step, you will complete a later report attempt after the old credentials have stopped working. Stay in Terminal. Recovery means obtaining a new credential through the authorized service; editing an old response does not renew its database identity.

Save the new normal-role issuance under a different name so the previous evidence is retained:

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

Load that new identity and run the same actual report:

export PGUSER="$(jq -r .data.username recovery-lease.json)"
export PGPASSWORD="$(jq -r .data.password recovery-lease.json)"
psql -X -v ON_ERROR_STOP=1 -f report.sql > settlement.tsv
cat settlement.tsv

The complete business result is unchanged. The database username is new, which is the expected recovery path after an old issuance ends.

End this replacement job's exact lease too:

bao lease revoke "$(jq -r .lease_id recovery-lease.json)"
python3 /opt/labex-report/access.py recovery-lease.json --wait-denied 10

If you rerun the report using another replacement login, end that exact lease as well. The completion check uses the identity behind the latest real report execution, so an earlier revoked account does not prove a later job has ended.

The prepared shop client uses its independent writer identity. Confirm today's normal order remains:

python3 shop.py list

Run the final lifecycle check:

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

It reads the existing native issuance, query, revocation and authentication events before making read-only preservation probes. Expect confirmation of distinct explicit-revocation, natural-expiry and replacement-login recovery evidence, with the tested old credentials unable to open new connections. The original report data, shop and independent inventory credential must remain intact.

If a report command fails because a replacement expired while you were reading, retain that response, request another replacement under a new filename, reload its database variables, rerun the report and end that new exact lease. Use the same taught commands with that filename. Do not extend the old username's expiry or revoke a whole role prefix.

Summary

You ran a real report, ended its exact lease, observed a separate credential expire naturally, and recovered with a newly issued identity whose job access you also ended. You distinguished a queued request from actual database denial and a stopped service from a refused password.

The result is deliberately scoped to new password-authenticated connections in this prepared environment. It does not claim that every already-open session or production pool has been terminated. The challenge combines the permission policy and completed-job lifecycle for a different reporting view.