Files
JARVISandClaude Opus 5.5 78ac06378e multica_agent_host: op shim reads the service account token (WDWL-37)
Deliver vault_op_service_account_claude to the agent hosts and install a
role-owned ~multica/.local/bin/op shim that exports OP_SERVICE_ACCOUNT_TOKEN
to /usr/bin/op only. op run / op plugin run get env -u spliced after "--"
so the child never sees the token. The daemon unit is untouched (WDWL-18).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 18:36:23 -05:00

82 lines
2.8 KiB
YAML

---
# Delivers the 1Password service account token to a file only the daemon user
# can read. It deliberately stops there: nothing here puts the token into the
# daemon's environment. The daemon's systemd user unit belongs to the multica
# CLI, so the role must not edit it, and exporting the token to the daemon
# would hand it to every agent process too. See the README.
# no_log: a failed assert would otherwise render the token it inspected.
- name: 1Password token | Require a service account token
ansible.builtin.assert:
that:
- multica_op_service_account_token | length > 0
- multica_op_service_account_token is match('^ops_')
fail_msg: >-
multica_op_deliver_token is true but multica_op_service_account_token is
not a 1Password service account token (ops_...).
quiet: true
no_log: true
- name: 1Password token | Create the token directory
ansible.builtin.file:
path: "{{ multica_op_token_file | dirname }}"
state: directory
owner: "{{ multica_user }}"
group: "{{ multica_group }}"
mode: "0700"
become: true
- name: 1Password token | Write the token file
ansible.builtin.copy:
dest: "{{ multica_op_token_file }}"
content: "{{ multica_op_service_account_token }}\n"
owner: "{{ multica_user }}"
group: "{{ multica_group }}"
mode: "0600"
no_log: true
become: true
# --- op shim -----------------------------------------------------------------
# `op` reads the token only from OP_SERVICE_ACCOUNT_TOKEN. The shim, first on
# the daemon unit's PATH, exports it for the real binary alone, so agents call
# plain `op` and the token never enters their shell environment. The daemon
# unit itself stays the CLI's (WDWL-18).
- name: 1Password token | Create the daemon user's bin directory
ansible.builtin.file:
path: "{{ multica_op_shim_path | dirname }}"
state: directory
owner: "{{ multica_user }}"
group: "{{ multica_group }}"
mode: "0755"
become: true
when: multica_op_shim | bool
- name: 1Password token | Install the op shim
ansible.builtin.template:
src: op-shim.sh.j2
dest: "{{ multica_op_shim_path }}"
owner: root
group: root
mode: "0755"
become: true
when: multica_op_shim | bool
# As the daemon user, through its own environment: plain `op` must resolve to
# the shim, and the token must not be in that environment.
- name: 1Password token | Check op resolves to the shim as the daemon user
ansible.builtin.shell:
cmd: 'command -v op; env | grep -c "^OP_SERVICE_ACCOUNT_TOKEN=" || true'
become: true
become_user: "{{ multica_user }}"
environment: "{{ _multica_user_env }}"
register: _multica_op_shim_check
changed_when: false
check_mode: false
failed_when: >-
_multica_op_shim_check.rc != 0
or _multica_op_shim_check.stdout_lines != [multica_op_shim_path, '0']
when:
- multica_op_shim | bool
- not ansible_check_mode