Auditing and Access Control

Access control decides what may happen; auditing proves what did. s3.sh reads three logs after the runs above: Airflow 129 's event log (/api/v2/eventLogs, the Audit Log page in the UI), the API server's access log, and OpenBao's audit device:

s3.sh (excerpt): the newest eight entries of Airflow's event logShell
curl -s "$B/api/v2/eventLogs?order_by=-when&limit=${N:-8}" -H "Authorization: Bearer $T" \
  | jq -r '.event_logs[] | [.when[11:19], .event, .owner, .dag_id, .task_id] | join(" ")'
Output
04:56:36 trigger_dag_run airflow booknest_secure
04:56:32 cli_users_create default
04:56:23 failed airflow booknest_secure read_emails
...
04:56:23 success airflow booknest_secure load
04:56:06 cli_dag_test default booknest_secure
...
04:56:37 403 POST /api/v2/dags/booknest_secure/dagRuns
04:56:41 401 POST /auth/token
{"time":"04:56:23","who":"approle","policies":["airflow-read","default"],"uri":"hmac-sha256:dfe
  4ea...

The event log records what succeeded, with the user, DAG and task, but not the analyst's refused trigger or the failed login: only the access log has those, with the client address and no user name. Ship both to your log platform and alert on bursts of 401 and 403. OpenBao's entry shows the AppRole reading the loader's connection the second the load task started, with the secret replaced by an HMAC, so you can match a value without the log revealing it. Archive event-log rows before airflow db clean deletes them, review who holds Op and Admin every quarter, and rotate the secret_id, Fernet key and JWT secret on a schedule.