Skip to content

Service accounts

In progress

A service account lets software read a vault with no person there: a GitHub Actions job, a GitLab pipeline, a server at startup. It has its own token, bound to one shared vault, and it’s read-only unless you say otherwise.

You need the manage role on a shared vault. Personal vaults can’t have service accounts: their key can’t be rotated, so access could never really be taken back. Make a shared vault that holds only what the job needs.

Terminal window
octapass service-account create --vault CI --name "Deploy job"

Or open the vault under Sharing and use Service accounts. The token (opsa1_…) is shown once, and Octa Pass can’t show it again.

Option Meaning
--write It can save items too. Without it, it can only read.
--expires 90d It stops working after that long (12h, 90d). Without it, it lasts until revoked.

Keep the token in your CI system’s secret store. The token is a key: whoever has it can read the vault, so treat it as you would a password to that vault.

Set OCTAPASS_SERVICE_ACCOUNT_TOKEN, and the commands that read work with no sign-in, keyring or master password:

Terminal window
export OCTAPASS_SERVICE_ACCOUNT_TOKEN=opsa1_…
octapass read "octapass://CI/Deploy key/password"
octapass run --env shop-api:production -- ./deploy.sh

list, get, totp, read, run, inject, env list, env show, env export, env diff, oauth token, aws, kube and docker-credential get work this way. Anything else is refused while the variable is set.

- uses: ./integrations/github-action
with:
token: ${{ secrets.OCTAPASS_SERVICE_ACCOUNT_TOKEN }}
secrets: |
DATABASE_URL=octapass://CI/Shop database/url
STRIPE_KEY=octapass://CI/Stripe/password
- run: ./deploy.sh

Values are masked in the logs and exported to later steps. The action calls an octapass binary already on the runner.

include:
- local: integrations/gitlab/octapass.gitlab-ci.yml
deploy:
extends: .octapass
variables:
DATABASE_URL: octapass://CI/Shop database/url
script:
- octapass run -- ./deploy.sh

Add OCTAPASS_SERVICE_ACCOUNT_TOKEN as a masked, protected CI/CD variable.

No plugin needed. Both read environment variables, so octapass run is all it takes:

Terminal window
export TF_VAR_database_password=octapass://CI/Shop database/password
octapass run -- terraform apply
export PULUMI_CONFIG_PASSPHRASE=octapass://CI/Pulumi/password
octapass run -- pulumi up

Each fetch and each save appears in the security log of whoever made the service account, with its id. A revoked or expired token that’s still being tried appears too.

The log records that the vault was read, not which secret. The server sends ciphertext and can’t know which item a runner decrypted.

Terminal window
octapass service-account list --vault CI
octapass service-account revoke <id> --vault CI

Revoking ends it at once: live sessions go, and it can’t sign in. Then your device rotates the vault’s key, as it does when a member is removed.

Anything it already read stays known to whoever held the token, so if a token leaked, change the secrets in that vault too.

If another manager rotates the vault’s key, tokens made by someone else stop working and show needs a new token. A token only trusts its creator’s signature, so that a server can’t hand it a key of its own. Revoke it and make a new one.

  • One vault per token. Make one per job.
  • Files attached to items can’t be read yet.
  • A service account can never manage members or rotate keys, whatever its role.

See what the server sees and the design in the threat model.