- provision-agent-host.yml: multica_pat now comes from vault_multica_pats[inventory_hostname_short], one daemon-<host> token per host. A pre_task asserts the key exists (never prints the value) so a missing entry fails by host name instead of as a no_log "censored". - provision-wong-host.yml: spaceship-earth only. Grows the root partition, PV and LV/filesystem with growpart + community.general.lvg/lvol; idempotent (second run changed=0). Then applies obsidian_headless. - roles/obsidian_headless: Obsidian's official headless Sync client (obsidian-headless 0.0.14) as system user obsync under a sandboxed systemd unit with UMask=0077. Vault at /srv/obsidian/vault: everpure/ and wip/ obsync-only, inbox/ granted to multica via access + default ACLs, vault root traverse-only. Verifies the isolation as multica. Sign-in to Obsidian Sync stays manual (see the role README). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
2.9 KiB
YAML
67 lines
2.9 KiB
YAML
---
|
|
# Example playbook. The role takes multica_pat as a VALUE — pick ONE of the
|
|
# lookups below (or any other) and delete the rest. Changing secret provider
|
|
# later is a change to this file only; the role is untouched.
|
|
- name: Provision Multica agent hosts
|
|
hosts: multica_agent_hosts
|
|
become: true
|
|
|
|
vars:
|
|
multica_server_url: "https://multica.wdw-labs.cloud"
|
|
multica_app_url: "https://multica.wdw-labs.cloud"
|
|
multica_version: "0.6.5"
|
|
multica_node_version: "24.22.1"
|
|
multica_workspaces_root: "/opt/multica/workspaces"
|
|
# No NAS mount under the workspaces root yet, so the mount guard is off.
|
|
# When utilidor is mounted, switch both lines together — never set the
|
|
# root onto a mount without also setting the guard, or a play that runs
|
|
# while the mount is down fills the root filesystem instead of failing.
|
|
# multica_workspaces_root: "/mnt/utilidor/multica/workspaces"
|
|
# multica_workspaces_root_mount: "/mnt/utilidor"
|
|
multica_agent_clis:
|
|
- claude
|
|
|
|
# --- Secret source ----------------------------------------------------
|
|
# This homelab keeps Ansible secrets in ansible-vault encrypted files, so
|
|
# that is the live form. One PAT per host (named daemon-<host>), held in
|
|
# the global vault (group_vars/all/vault) as a dictionary keyed by short
|
|
# hostname:
|
|
# vault_multica_pats: { haunted-mansion: mul_…, spaceship-earth: mul_… }
|
|
# A host with no entry fails the pre_task below, by name, before anything
|
|
# runs. The indirection keeps the name greppable and the file swappable.
|
|
multica_pat: "{{ vault_multica_pats[inventory_hostname_short] }}"
|
|
#
|
|
# Alternatives, if the backend ever consolidates. Each is a one-line
|
|
# change here; the role is untouched by any of them.
|
|
#
|
|
# HashiCorp Vault (community.hashi_vault):
|
|
# multica_pat: "{{ lookup('community.hashi_vault.vault_kv2_get',
|
|
# 'multica/agent-host').secret.pat }}"
|
|
#
|
|
# 1Password (community.general):
|
|
# multica_pat: "{{ lookup('community.general.onepassword',
|
|
# 'Multica Agent Host PAT', field='credential') }}"
|
|
#
|
|
# Environment variable on the control node:
|
|
# multica_pat: "{{ lookup('env', 'MULTICA_PAT') }}"
|
|
|
|
# The role's own PAT assert is no_log, so a missing dictionary entry would
|
|
# surface there only as "censored". This checks key presence, never the
|
|
# value, so its failure can name the host.
|
|
pre_tasks:
|
|
- name: Require a per-host Multica PAT in the vault
|
|
ansible.builtin.assert:
|
|
that:
|
|
- vault_multica_pats is defined
|
|
- vault_multica_pats is mapping
|
|
- inventory_hostname_short in vault_multica_pats
|
|
fail_msg: >-
|
|
No Multica PAT for {{ inventory_hostname_short }}: add
|
|
vault_multica_pats['{{ inventory_hostname_short }}'] to
|
|
group_vars/all/vault.
|
|
quiet: true
|
|
tags: [always, multica_pat_check]
|
|
|
|
roles:
|
|
- role: multica_agent_host
|