Skip to content

bitwarden

Installs the Bitwarden CLI (bw) and Secrets Manager CLI (bws) from GitHub releases, and writes their server configuration. Idempotent; architecture-aware for bws (x86_64 / aarch64). bw ships a generic Linux build.

Optionally distributes a BWS machine-account token to the host — see Host token distribution. That part is not in the role’s default flow.

VariableDefaultDescription
bitwarden_install_bwtrueInstall bw
bitwarden_install_bwstrueInstall bws
bitwarden_configuretrueWrite server configuration
bitwarden_install_path/usr/local/binWhere the binaries land
bitwarden_bw_version2026.7.0Bump to upgrade
bitwarden_bws_version2.1.0Bump to upgrade
bitwarden_server_urlhttps://vault.bitwarden.euServer URL for bw
bitwarden_bws_server_apihttps://api.bitwarden.euAPI endpoint for bws
bitwarden_bws_server_identityhttps://identity.bitwarden.euIdentity endpoint for bws
bitwarden_bws_config_path~/.config/bwsDirectory for the bws TOML config

Defaults are the European endpoints; for the US region use api.bitwarden.com and identity.bitwarden.com. Self-hosted instances only need bitwarden_server_url. See defaults/main.yml for the rest, including the repo and temp-dir overrides.

- hosts: all
roles:
- role: bitwarden
bitwarden_server_url: 'https://vault.example.com'

Installs a BWS machine-account token on the host so bws works with no per-user setup, for root and for members of the bws group. The tasks live in tasks/distribute_token.yml, which main.yml does not include — so provisioning installs the CLIs without touching the token, and rotating the token does not require a full provisioning run.

VariableDefaultDescription
bitwarden_bws_token_env_varBWS_HOST_ACCESS_TOKENController env var holding the token
bitwarden_bws_token_requiredfalseFail instead of skip when it is unset
bitwarden_bws_token_file/etc/bws/tokenOn-host token path (root:bws, 0640)
bitwarden_bws_token_groupbwsGroup granted read access
bitwarden_bws_token_users['{{ ansible_user_id }}']Accounts added to the bws group
bitwarden_bws_system_config_file/etc/bws/configSystem-wide config (BWS_CONFIG_FILE)
bitwarden_bws_write_root_configtrueAlso write /root/.config/bws/config
bitwarden_bws_write_user_configtrueWrite the per-user ~/.config/bws/config

Set the token on the controller, in ansible/.env:

Terminal window
BWS_HOST_ACCESS_TOKEN=0.<uuid>.<key>

Use a separate, read-only machine account scoped to just the projects the hosts need. Do not reuse BWS_ACCESS_TOKEN — that one stays on the controller for restart-docker-stacks.yml, and reusing it puts a broad credential on every host.

Terminal window
ansible-playbook -i inventory/proxmox.proxmox.yml playbooks/distribute-bws-token.yml \
--limit arcane # drop --limit for the whole fleet

That playbook sets bitwarden_bws_token_required: true, so a missing env var is an error rather than a silent skip.

PathOwner:GroupModeContents
/etc/bws/tokenroot:bws0640The access token
/etc/bws/configroot:root0644TOML with the region endpoints
/etc/profile.d/bws.shroot:root0644Exports both, if readable
/etc/fish/conf.d/bws.fishroot:root0644Same, written only where fish exists
/root/.config/bws/configroot:root0644Region endpoints for root
  • Group changes need a re-login. An account newly added to bws must log out and back in (or run newgrp bws) before $BWS_ACCESS_TOKEN appears.
  • Only login shells get the export. /etc/profile.d is not read by ssh host '<cmd>', cron, systemd units, or Ansible’s shell/command tasks. Use bash -lc '...', or read /etc/bws/token directly. Fish is unaffected — conf.d is sourced by every shell.
  • sudo strips the variable. Use sudo -i, or sudo BWS_ACCESS_TOKEN="$(cat /etc/bws/token)" bws .... Do not add an env_keep sudoers rule — that widens exposure to every sudo call.
  • Never put the token in /etc/environment — world-readable, and read for every session, which defeats the 0640 design.
  • Rotation rewrites the file on the next run, but open sessions keep the old value, and the old token still has to be revoked in the web vault by hand.

Both upstream repos are monorepos tagging several products, so /releases/latest returns a web, desktop, rust or python release rather than the CLI. Filter by tag prefix:

Terminal window
curl -s 'https://api.github.com/repos/bitwarden/clients/releases?per_page=100' \
| grep '"tag_name"' | grep cli-v | head -5 # bw
curl -s 'https://api.github.com/repos/bitwarden/sdk-sm/releases?per_page=100' \
| grep '"tag_name"' | grep bws-v | head -5 # bws

Version strings carry no v prefix: 2026.7.0, not v2026.7.0.