# bao-secrets — fetch OpenBao secrets in one step Composite action for Gitea Actions (spikersoft-issues#545). AppRole-logs in to OpenBao, reads the KV v2 paths you list, and exports them as **masked** env vars for the rest of the job — so workflows stop carrying a pile of per-repo Actions secrets. ## One-time setup per repo 1. Provision the repo's AppRole (once, by an admin): ```sh export BAO_ADDR=https://bao.spikersoft.com BAO_TOKEN= cd /mnt/infrastructure/openbao && bash provision-ci-approles.sh ``` It prints a `role_id` and `secret_id` per repo. 2. In the repo's **Settings → Actions → Secrets**, set exactly two: `BAO_ROLE_ID` and `BAO_SECRET_ID`. These replace `DOCKER_PASSWORD`, `*_S3_SECRET_KEY`, `ACCESS_TOKEN_GITEA`, `DISCORD_*`, `HF_TOKEN`, … — delete those once the workflow is migrated. ## Use it in a workflow ```yaml steps: - uses: spikerj/spikersoft-infrastructure/.gitea/actions/bao-secrets@master with: role-id: ${{ secrets.BAO_ROLE_ID }} secret-id: ${{ secrets.BAO_SECRET_ID }} secrets: | DOCKER_PASSWORD secret/ci/shared/registry password VIDEOS_S3_KEY secret/ci/backend/minio/videos secret_key # DOCKER_PASSWORD and VIDEOS_S3_KEY are now normal (masked) env vars: - run: echo "$DOCKER_PASSWORD" | docker login git.spikersoft.com -u ci --password-stdin ``` ### `secrets` format One mapping per line: **`ENV_NAME `**, whitespace-separated. The path is exactly what you'd pass to `bao kv get`. Blank lines and `#` comments are ignored. Multiline values (PEM keys, etc.) are handled. ### Inputs | input | required | default | notes | |---|---|---|---| | `role-id` | yes | — | `${{ secrets.BAO_ROLE_ID }}` | | `secret-id` | yes | — | `${{ secrets.BAO_SECRET_ID }}` | | `secrets` | yes | — | the mapping block above | | `bao-addr` | no | `https://bao.spikersoft.com` | override for testing | ## Notes - Tokens issued to CI are **short-lived (15m)** and **read-only**, scoped to the repo's own tree + `secret/ci/shared/*` by its policy. The action revokes its token when done. - If a path is outside the role's policy the step **fails loudly** (`permission denied`) rather than exporting an empty value — verified in `provision-ci-approles.sh`'s policy scoping. - Runner needs `curl` and `jq` (present on the standard act_runner images). - Rotation: `secret_id`s expire in 90 days — re-run `provision-ci-approles.sh` and update the two Actions secrets; nothing else changes.