Skip to content

Credential Model — Itachi-Direct + Vaultwarden (CT103)

Naming note 2026-06-11: "Bitwarden" throughout this doc reads as Vaultwarden (self-hosted, CT103, 192.168.1.250) per the 2026-06-10 supersede block at the end of this file. project: hinata-infrastructurestatus: livingowner: michael + itachicreated: 2026-05-26

Decision (live 2026-05-26)

Itachi-direct stays the default through the home-lab bring-up. Bitwarden adoption deferred to the first month after Pi + Z2 are operational, then adopted as a SPLIT model — not a replacement.

Original deferral (2026-05-24): "until self-hosting equipment is delivered." That trigger fires this week — Z2 arrived 2026-05-26, Pi arrives 2026-05-27. Re-evaluation date for full Bitwarden activation: 2026-06-15 (3 weeks of operational data from the new hosts).

Why a split, not a replacement

Itachi-direct has a property Bitwarden doesn't: vault-native + offline-readable + no daemon dependency. Bitwarden has a property Itachi doesn't: scale + sync-to-VMs + per-credential audit trail. The right move is to route by risk profile.

Routing rules

Credential classStorageWhy

Root credentials, recovery keys, legal/family docsItachi-directLow rotation, high trust, single-reader-on-Mac. Vault offers offline + iCloud sync without a sync daemon. Per-VM users, SSH host keys for home-lab boxesItachi-direct (boot-time) → Bitwarden (runtime)Mac script reads Itachi to deploy at provision time; the VM itself runs Bitwarden CLI for its own runtime needs. Per-service API keys (Monzo, TrueLayer, Anthropic, Telegram bot)Itachi-direct today; Bitwarden post-2026-06-15Rotation cadence is medium; volume is growing. Ephemeral lab creds (Postgres roles, Ollama dev keys, n8n webhooks)Bitwarden from day one (post-2026-06-15 activation)High churn, high count. Putting these in the vault pollutes git history. Cloudflare API token, Tailscale auth-keyItachi-directSingle-rotation per year; vault-native is fine. Database passwords (jimmy-vps Postgres, Z2 Proxmox root)Bitwarden post-activationPer-host rotation needs; multiple consumers; Bitwarden audit trail wins here.

Trade-off table

PropertyItachi-directBitwarden hostedVaultwarden (self-hosted on Pi)

Friction per accessLow (read file)Medium (CLI + unlock)Medium (CLI + unlock) Sync across devicesiCloud (free, slow)Native, sub-secondLAN-only (until Tailscale extends it) Sync to VMsManual (scp / git)Native via CLINative via CLI Audit trailGit log (coarse)Per-credential access logPer-credential access log Vault portabilityMarkdown — perfectJSON exportJSON export Monthly cost£0£0 (free tier)£0 (hosted on Pi) Offline readYes (iCloud cached)No (without local cache)No (if Pi off) Daemon dependencyNoneBitwarden CLI + browser extVaultwarden process on Pi

Vaultwarden rejected for now — adds a host-dependency layer when Pi is already carrying cron orchestration; one extra responsibility per host is the threshold.

Bitwarden migration checklist (activates 2026-06-15)

  1. (blocker) Provision Bitwarden account + install CLI on Mac (1hr).

  2. Migrate ANTHROPIC_API_KEY first as proof — out of any plist EnvironmentVariables block, into Bitwarden, daemon reads from bw get item at start. Validate before moving anything else.

  3. Migrate TELEGRAM_BOT_TOKEN next — same pattern.

  4. Audit every LaunchAgent plist for plaintext credentials in EnvironmentVariables blocks. Mechanical scan for token-shape strings, no credential values logged.

  5. Per-credential migration thereafter — never big-bang. One per session, validate consumer, then move on.

  6. Itachi *.json files for migrated credentials get a frontmatter flag migrated: bitwarden YYYY-MM-DD and the credential field is replaced with migrated → bw://item-id. The Itachi file stays for git audit history.

Pre-activation hardening (do before Pi arrives)

  • .gitignore already excludes *.token, *.key, tokens_*.json. Re-verify against new file shapes (Z2 BIOS export, Pi user creds).

  • Add a pre-commit hook to the vault that refuses to commit files containing bearer-token-shape strings.

  • feedback_never_print_credentials is the operational rule — re-affirm at top of each Pi/Z2 SSH session.

Stop conditions

* Do NOT print credential VALUES at any point — names, lengths, locations only.

* Do NOT rotate existing credentials during migration.

* Do NOT activate Bitwarden before 2026-06-15 without re-reading this doc.

Re-evaluation triggers

  * 2026-06-15 (Bitwarden activation review)

  * Credential count in Itachi exceeds 30 (threshold for forced reconsideration)

  * Any LaunchAgent plist needs a credential rotation more than once per quarter

Amendment (2026-06-10, Michael ruling — 800124)

Hosted Bitwarden is deprecated. The store is self-hosted Vaultwarden at 192.168.1.250 (CT103 on Z2) — same bw CLI protocol, same split-model routing rules: every "Bitwarden" above now reads "Vaultwarden". Activation is live as of 2026-06-10, ahead of the 2026-06-15 review (Michael migrating credentials in; the new Telegram bot token is the first canonical entry). Known cleanup: duplicate anthropic_api_key entries observed during migration — dedupe owned by Michael + Itachi; never auto-rotate, never print values. 192.168.1.250 is a LAN address — Tailscale-bind hardening belongs to the binds task (800127), not unilateral change.

◆ hinata · projects/hinata-infrastructure/credential-model.html · phase-19 conversion

Canonical paths (2026-06-14, Michael ruling — credential paths uniform is itachi plan)

Itachi owns auth strategisation. The flat-file/Vaultwarden split below is the law; deviations are violations, not patterns.

Path law

ClassStorageCanonical locationWhy
Secret-class (API tokens, OAuth client_id/client_secret, bot tokens, DB passwords)Vaultwardenitem name e.g. hinata_[commander]_[service]_tokenAudit trail, no plaintext on disk, cross-container reachable via bw get
OAuth refresh-token cache (polling agents that re-mint access tokens)Filesystem flat-file/mnt/data/hinata/data/[commander]/tokens_[service].json on Z2Pollers must read locally without bw-unlock loop; container bind reads at runtime
Mac-bound OAuth callback caches (browser localhost flow)Filesystem flat-file (Mac)~/Sandpit/hinata-sandpit/data/[commander]/tokens_[service].json then synced to Z2 canonical pathBrowser callback only resolves to Mac localhost; cache is intermediate, Z2 path is source-of-truth post-sync

Deprecated paths (2026-06-14 — DO NOT recreate)

  • /opt/jimmy-brain-ops/secrets/ — entire folder evicted; never write secrets under /opt/ again. Scripts must read from /mnt/data/hinata/data/[commander]/ only.
  • /mnt/data/itachi-credentials/ — evicted; canonical path collapsed to /mnt/data/hinata/data/[commander]/.
  • Any per-script secrets/ subdirectory under a script's install path.
  • ~/.config/[service]/credentials* for hinata-owned services on Z2 — must move into the canonical /mnt/data/hinata/data/ tree.

Naming law

  • Vaultwarden item names: hinata_[commander]_[service]_[purpose]. Examples: hinata_bulma_trading_212_token, hinata_studio_access.
    • Michael owns naming. Agents NEVER bw create / bw edit (per feedback_no-auto-vaultwarden-writes). Agents propose names; Michael writes.
  • Flat-file names: tokens_[service].json (refresh-token cache) or [service]_credentials.json (Mac-bound OAuth callback intermediate only).
  • One token-class per file. No mixed structures.

Read pattern

ConsumerHow it reads
Mac scripts (any)read-credentials.sh → SSH to Z2 → bw get item [name]
Z2 container pollerlocal file at /mnt/data/hinata/data/[commander]/tokens_[service].json (bind-mounted)
Z2 container at startup (non-poller)bw get item [name] via CT103 SSH/pct exec
CT106 (telegram bot)/etc/hinata/telegram.env env file backed by Vaultwarden

Migration of historic loose credentials

Any flat-file matching *credentials*.json / *token*.json / .env* outside the canonical paths above is non-compliant. Migration triage:

  1. KEEP — file lives at canonical path AND is OAuth-refresh-cache class (correct usage).
  2. MIGRATE — file is at non-canonical path; relocate to canonical path; update consumer.
  3. VAULTWARDEN — file holds secret-class material (client_id/client_secret, raw API tokens that aren't refresh-rotated); Michael moves to Vaultwarden manually, file deleted post-confirm.
  4. DELETE — vestigial duplicate or pre-collapse remnant.

Audit: 2026-06-14 audit.

Enforcement (Itachi standing rules)

  • New script written by any agent that introduces a credential path MUST land under /mnt/data/hinata/data/[commander]/ on Z2 (or the Mac-bound equivalent for callback paths only). Reviewers reject otherwise.
  • Any reference to /opt/jimmy-brain-ops/secrets/ or /mnt/data/itachi-credentials/ in active code is a defect. Tombstone and replace.
  • Credentials in source files (_middleware.js, .env*, config) must not be modified by any agent without explicit Michael instruction — see feedback_no-credential-in-code-modification.
  • Vault commits that print credential values fail review on sight per feedback_no-credential-print.

Ownership (2026-06-14 ruling)

Michael ruling, verbatim:

"jimmy why would jimmy have ownership of any secrets or tokens in cache ? is that necessary ? is itachi not supposed to own all credential auth flows why is json for credentials anywhere else?"

Itachi is the sole owner of every credential surface. This is total ownership across the federation — no other captain, commander, or colonel holds credential authority in their domain.

Surfaces Itachi owns

SurfaceWhat Itachi owns
Vaultwarden itemsNaming proposals (Michael writes), rotation cadence, retirement, audit
Flat-file token cachesPath, filename, format schema, refresh policy, rotation triggers
OAuth callback flowsCallback host, redirect URI, intermediate cache path, sync-to-Z2 protocol
In-container env filesEnvironmentFile path, key naming, backing source (Vaultwarden CLI vs flat-file)
Source-file credential refsAuthorisation of any change per feedback_no-credential-in-code-modification
Rotation policyQuarterly cadence (per Itachi credential-rotation-brief), trigger thresholds
Auth-flow designOAuth client architecture, scopes, token TTL, refresh strategy

Per-consumer-commander paths are Itachi-OWNED-BY-POLICY

The canonical path /mnt/data/hinata/data/[commander]/tokens_[service].json lives under a commander-named directory for read-locality only — the bind-mount lets that commander's container read locally without an unlock loop. The consumer reads what Itachi sanctions. The path, filename, format, and rotation are Itachi's. The consumer-commander does not author, rename, or restructure the file.

Example: /mnt/data/hinata/data/bulma/tokens_monzo.json is Itachi-owned. Bulma's poll-monzo.py reads it. Bulma does not declare schema, does not author rotation cadence, does not change filename. If Bulma's needs require a schema change, Bulma raises it to Itachi.

Forbidden — other agents declaring credential ownership

No captain or commander may declare a credential surface in their context file. If a federation context contains language like "X owns the secrets for service Y" outside Itachi's context, it is a violation — see feedback_itachi-owns-all-credential-paths. Such declarations get tombstoned to "credentials via Itachi" with a wiki-link here.

Path bans (re-affirmed)

  • /opt/jimmy-brain-ops/secrets/ — forbidden by name. Will not be re-created under any circumstance. This path was never Itachi-named — its existence was a domain-overreach by Jimmy and is permanently evicted.
  • /mnt/data/itachi-credentials/ — deprecated despite being Itachi-named. The structure was non-canonical (single flat directory rather than per-consumer-commander subtree). Collapsed into /mnt/data/hinata/data/[commander]/ on 2026-06-14. Will not be re-created.
  • /opt/itachi/credentials/ (CT102, CT103) — transitional during Vaultwarden backfill; once empty, the directory itself is retired, not re-stocked.