Files
org-buildout/agent-identity-bootstrap.md
T
mrcharles 8c76cf1bab docs: initial commit — Q2/Q3 transition planning docs
Planning documents for TSYS Group's COO→CTO handoff and AI agent
identity architecture. Shared publicly as a bootstrapping reference.

Includes: org prompts, transition map, agent identity bootstrap plan,
TechOps/K8s/SecOps context notes.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-08-13 10:43:48 -05:00

18 KiB

AI Agent Identity Bootstrapping — Provisioning Plan

Status: DRAFT — architecture confirmed, awaiting user prerequisites Date: 2026-08-13 Goal: Stand up dedicated AI agent identities with proper attribution, RBAC, and audit trails. Agents own their own credentials in Bitwarden (no shared ~/.creds/ env files).


1. Confirmed Architecture

┌─────────────────────────────────────────────────────────┐
│  CLOUDRON (tsys-cloudron.knel.net)                      │
│  Identity root — IdP for ALL apps except Uptime Kuma     │
│                                                          │
│  Agent identities (each a separate Cloudron user):       │
│    vp-techops, vp-secops, vp-techcompliance (Q3)         │
│    coo, svp-knel, svp-tctc, vp-finance, ... (Q4)        │
└────────────┬────────────────────────────────────────────┘
             │ Cloudron SSO (auto-provisions identity)
             ▼
┌─────────────────────────────────────────────────────────┐
│  CLOUDRON-MANAGED APPS                                  │
│  Gitea · Discourse · Redmine · + all other apps         │
│                                                          │
│  Each agent SSOs in → generates its OWN API keys →      │
│  stores in Bitwarden. Agents are fully independent.     │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  BITWARDEN (dedicated "COO" account)                    │
│  Credential vault — RCEO owns all creds/orgs/collections │
│                                                          │
│  Collections: vp-techops/, vp-secops/, shared/, etc.    │
│  Each item: service URL, username, password, API key,   │
│             TOTP secret, SSH private key                 │
│                                                          │
│  bw CLI authenticates via client_id/client_secret        │
│  (machine-to-machine, non-interactive)                  │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  COO LINUX ACCOUNT (orchestration layer)                │
│  Currently: reachableceo's workstation                   │
│  Soon: dedicated hardened VM on PFVCluster              │
│                                                          │
│  This is where Charles/AJ interact with agents.          │
│  Agents are "personalities" (Crush/Hermes sessions)     │
│  that run here, each sourcing its own creds from BW.    │
│                                                          │
│  NO key material on disk. SSH via BW SSH agent.         │
└─────────────────────────────────────────────────────────┘

Key principles

  1. Cloudron is the identity root. One invite = identity everywhere (SSO auto-provisions).
  2. Agents own their credentials. Each agent generates its own API keys after SSO login, stores them in Bitwarden. No shared ~/.creds/*.env files.
  3. Agents are fully independent. Each agent is a separate Cloudron user with its own SSO sessions, API keys, and Bitwarden collection. They do not share sessions or credentials.
  4. coo Linux account is the orchestration layer — where humans (Charles/AJ) launch and interact with agent sessions. Not where agents "live" — agents live as Cloudron identities.
  5. No key material on disk. All SSH private keys, passwords, API keys live in Bitwarden. SSH via BW SSH agent. (Aligns with SecOps note: only iPad enclave key + Bitwarden key.)

2. The Credential Migration (~/.creds/ → Bitwarden)

Current state (14 credential files)

~/.creds/
├── beszel.env          ├── librenms.env       ├── redmine.env
├── discourse.env       ├── oxidized.env       ├── switch-creds.env
├── grafana.env         ├── phpipam.env        ├── technitium.env
├── pushover.env        ├── prometheus.env     ├── unifi-creds.env
└── uptime-kuma.env

All CLIs invoked as: docker run --rm --env-file ~/.creds/<service>.env <cli-image> ... All using reachableceo's API keys. No per-agent credential separation.

Target state

Bitwarden org: "TSYS Group AI Agents"
├── vp-techops/          (collection)
│   ├── Cloudron         (login + TOTP)
│   ├── Gitea            (API token)
│   ├── Discourse        (API key)
│   ├── Redmine          (API key)
│   ├── SSH key          (Ed25519 private key)
│   └── <infra creds>    (LibreNMS, Grafana, etc. — scoped to TechOps)
├── vp-secops/
│   ├── Cloudron / Gitea / Discourse / Redmine / SSH
│   └── <security creds>
├── vp-techcompliance/
│   └── ...
├── shared/              (fleet-wide creds all agents need)
│   ├── Technitium DNS
│   ├── Pushover
│   ├── Switch credentials
│   └── Beszel
└── coo/ (Q4)
    └── ...

Migration path (3 stages)

Stage 1 — Parallel operation (Q3 start). New agent identities use BW-sourced credentials. The existing ~/.creds/ files remain for reachableceo's direct use. Both work side by side. No breakage.

Stage 2 — Agent adoption. Agent-facing tooling (CLI wrappers, Crush configs) source from BW. The ~/.creds/ files are only used by Charles directly. Agents never touch ~/.creds/.

Stage 3 — Full migration. ~/.creds/ files are deleted. Charles uses Bitwarden directly too. All credential access is through BW. (Aligns with Vault migration in P5 — Vault can later wrap BW or replace it for machine secrets.)

The credential sourcing layer

A wrapper script that replaces the --env-file ~/.creds/ pattern:

#!/usr/bin/env bash
# bw-run.sh — run a CLI command with credentials sourced from Bitwarden
# Usage: bw-run.sh <agent> <service> <image> [args...]
# Example: bw-run.sh vp-techops redmine redmine-cli:latest list --assigned-to-me -p 55

set -euo pipefail

AGENT="$1"; SERVICE="$2"; IMAGE="$3"; shift 3

# Ensure BW session is active
BW_SESSION="${BW_SESSION:-$(bw unlock --raw 2>/dev/null)}" || true
export BW_SESSION

# Fetch credential item from Bitwarden
ITEM_NAME="${AGENT} ${SERVICE}"
ENV_JSON=$(bw get item "$ITEM_NAME" | jq -r '
  .login |
  "URL=\(.uris[0].uri // "")\n" +
  "USERNAME=\(.username // "")\n" +
  "PASSWORD=\(.password // "")\n" +
  (.fields[]? | "\(.name)=\(.value)\n")
')

# Write to temp env file (cleaned up on exit)
ENVFILE=$(mktemp /tmp/bw-${AGENT}-${SERVICE}-XXXXXX.env)
trap 'rm -f "$ENVFILE"' EXIT
echo -e "$ENV_JSON" > "$ENVFILE"

# Run the CLI with BW-sourced credentials
docker run --rm --env-file "$ENVFILE" "$IMAGE" "$@"

This preserves the existing CLI invocation pattern (docker run --env-file ... <image>) while sourcing credentials from Bitwarden instead of static files. Agents call bw-run.sh vp-techops redmine ... instead of docker run --env-file ~/.creds/redmine.env ....

What needs to change in each project

Project Change Effort
TSYSGroupAIOS (meta) Add bw-run.sh to scripts/. Update BASELINE-PROMPT.md credential references. Document the BW credential model. Med
PFVCluster Update AGENTS.md CLI examples to use bw-run.sh. Add agent-profile system. Update scripts/check-rules.sh to enforce no ~/.creds/ refs in new code. Med
KNEL-AIMiddleware Update tooling-cli/*/AGENTS.md to document BW sourcing. Update KNELCredsManager to be the BW integration point. Med
All CLI containers No image changes needed — they still read env vars. The sourcing layer (bw-run.sh) is outside the container. None

3. Identity Roster

Q3 — TechOps Agents (stand up NOW)

Agent Cloudron user Redmine scope Gitea scope Discourse scope
vp-techops vp-techops@ 55, 59 KNEL, TechnicalOperations 74, 20
vp-secops vp-secops@ 55 (security) KNEL 74 + new VP SecOps cat
vp-techcompliance vp-techcompliance@ 55 (compliance) KNEL 75

Q4 — Business Agents (enroll in Cloudron now, activate in Q4)

Agent Redmine scope
coo 53, 62, 77
svp-knel 62, 55 (read)
svp-tctc 15 (TCTC), 31 (RedWFO)
vp-finance, vp-accounting, vp-investing, vp-treasury, vp-trading 15 (TCTC)

Recommendation: Enroll ALL identities in Cloudron during Q3 (cheap — just invite acceptance). Only provision API keys + system access for the 3 Q3 agents. Q4 agents get activated when business ops work begins.


4. Provisioning Pipeline

Phase 0 — Prerequisites (USER provides)

# Item Detail
1 Linux coo account useradd -m -s /bin/bash coo; add to docker group; mkdir ~/.ssh ~/.creds ~/projects
2 Bitwarden "COO" account Dedicated BW account. RCEO owns the org. Create collections per agent.
3 BW API credentials client_id + client_secret for non-interactive bw login --apikey. Place in a file the agent can read.
4 Cloudron invite manifest Text file, one line per identity: `agent-name
5 Discourse admin key (for VP SecOps category) Current API user (trust-4) cannot create categories. User creates VP SecOps category via web UI OR provides admin key.

Phase 1 — Cloudron Identity Enrollment (Playwright automation)

For each identity in the manifest:

1. Launch Playwright Docker (mcr.microsoft.com/playwright:v1.52.0-noble)
2. Navigate to Cloudron invite link
3. Generate strong password (bw generate -uluns --length 32)
4. Fill password fields, submit → identity created
5. Enable 2FA:
   a. Navigate to Cloudron account security settings
   b. Initiate TOTP enrollment
   c. Extract TOTP secret from QR code
   d. Store TOTP secret in Bitwarden
   e. Confirm with current TOTP code (bw code from stored secret)
6. Store Cloudron credential in Bitwarden:
   - Collection: <agent-name>
   - Name: "<agent-name> Cloudron"
   - URL: https://tsys-cloudron.knel.net
   - Username: <agent-name>@<domain>
   - Password: <generated>
   - TOTP: <secret>

Result: Agent identity exists in Cloudron. SSO works for all managed apps. No per-system account creation needed — SSO handles it.

Phase 2 — API Key Generation (agent logs in via SSO, creates keys)

For each agent, for each system (Gitea, Discourse, Redmine):

1. Launch Playwright
2. Navigate to the app URL → Cloudron SSO redirect
3. Complete SSO login (use agent's Cloudron creds from BW + TOTP from BW)
4. First-time SSO → account auto-provisioned in the app
5. Navigate to API key / access token settings:
   - Gitea: Settings → Applications → Generate New Token (scopes: api, repo, read:org)
   - Discourse: Preferences → API Keys → (may need admin to create user API key)
   - Redmine: My Account → API access key → Show
6. Copy the generated key
7. Store in Bitwarden:
   - Collection: <agent-name>
   - Name: "<agent-name> <SystemName>"
   - URL: <system URL>
   - Password field: <API key>
8. Verify: use the key to call the system's API (curl or CLI)

After Phase 2, each agent has:

  • Cloudron identity (login + TOTP) in BW
  • Gitea API token in BW
  • Discourse API key in BW
  • Redmine API key in BW
  • Ability to operate independently in all three systems

Phase 3 — SSH Key Provisioning

1. Generate Ed25519 keypair per agent: ssh-keygen -t ed25519 -f /tmp/<agent>-ed25519 -N ""
2. Store PRIVATE key in Bitwarden (as "Secure Note" or BW SSH Agent item)
3. Deploy PUBLIC key to fleet via KNELIAC:
   - Add to inventory/group_vars/all.yml managed_users
   - Run: ansible-playbook playbooks/setup_new_system.yml -t security_ssh --limit <targets>
4. Delete private key from /tmp (lives only in BW)
5. Configure BW SSH Agent on coo account: export SSH_AUTH_SOCK=... (bw agent)

Phase 4 — Agent Profile System (on coo Linux account)

Each agent has a profile that sets its identity context:

# ~/agents/vp-techops/profile.sh
export AGENT_NAME="vp-techops"
export AGENT_DISPLAY="VP TechOps"
export AGENT_EMAIL="vp-techops@turnsys.com"
export AGENT_BW_COLLECTION="vp-techops"
export GIT_AUTHOR_NAME="VP TechOps"
export GIT_COMMITTER_NAME="VP TechOps"
export GIT_AUTHOR_EMAIL="$AGENT_EMAIL"
export GIT_COMMITTER_EMAIL="$AGENT_EMAIL"
export REDMINE_PROJECT_SCOPE="55,59"
export GITEA_ORG_SCOPE="KNEL,TechnicalOperations"
export DISCOURSE_CAT_SCOPE="74,20"
# SSH: BW agent provides the key for this agent

Switching agent context:

source ~/agents/vp-techops/profile.sh   # become vp-techops
source ~/agents/vp-secops/profile.sh    # become vp-secops

Phase 5 — Operational Environment

1. Clone repos into /home/coo/projects/ (or the future hardened VM)
2. Copy/adopt TSYSGroupAIOS framework (check-rules.sh, hooks, etc.)
3. Install bw-run.sh credential sourcing layer
4. Set up per-agent Crush config directories:
   ~/.config/crush/vp-techops/
   ~/.config/crush/vp-secops/
5. Configure tea CLI per agent (separate logins = separate tokens)
6. Install git hooks (ticket-gate, pre-commit, pre-push)
7. Smoke test per agent:
   - Create a Redmine ticket (appears as agent identity)
   - Edit a Discourse topic (appears as agent identity)
   - Open a Gitea PR (appears as agent identity)
   - SSH to a host (appears in auth log as agent's key)

5. Playwright Automation Design

The Playwright script handles the browser-driven steps (Phases 1-2). Containerized — no browser on host.

provision-agent/
├── Dockerfile              # Based on mcr.microsoft.com/playwright:v1.52.0-noble
├── provision-agent.py      # Main script
├── bw-helper.py            # Bitwarden CLI wrapper (gen password, store item, get TOTP)
└── agents.yaml             # The manifest (invite links + agent config)

Flow:

for agent in manifest:
    # Phase 1: Cloudron enrollment
    browser  invite_link
    fill password (bw generate)
    enable 2FA  extract TOTP secret  store in BW
    
    # Phase 2: API keys (per system)
    for system in [gitea, discourse, redmine]:
        browser  system_url  SSO redirect  login with BW creds + TOTP
        navigate to API key page  generate  copy
        store in BW
    
    # Verify
    for system in [gitea, discourse, redmine]:
        api_call(system, key_from_bw)  assert success

Security: Playwright runs in Docker, no persistent browser state. Credentials are generated/stored via bw CLI (mounted into container). No credentials in browser memory after the script exits.


6. Security & Compliance Posture

Control How this design satisfies it
CMMC IA-2(1) (MFA for all accounts) Every agent identity has TOTP via Bitwarden
CMMC AU-2/AU-12 (audit events) Every action attributable to specific agent identity (Redmine, Discourse, Gitea, SSH auth logs)
CMMC AC-2/AC-3 (least privilege) Each agent scoped to its Redmine projects, Gitea orgs, Discourse categories, and fleet SSH access
CMMC IA-5(1) (authenticator management) No key material on disk. All in Bitwarden. SSH via BW agent.
Shared credential elimination Each agent has its own API keys and SSH keys — no more single key on "every single system"
ITAR/SCIF alignment Per-identity access control + audit trail for classified-adjacent systems

7. Implementation Timeline

Week What Who
Week 1 User provides Phase 0 prerequisites. Agent builds Playwright automation + bw-run.sh. Executes Phase 1-2 for 3 Q3 agents. User + Agent
Week 2 Phase 3 (SSH keys via KNELIAC). Phase 4-5 (agent profiles, coo env, smoke tests). Enroll Q4 identities in Cloudron (Phase 1 only). Agent
Week 3+ Agents begin operating from own identities on P1-P9 work. Charles reviews as himself. Agents @mention Charles in Redmine/Discourse. Agents open PRs for review. Agents + Charles

8. What I Need From You to Start

  1. Create the coo Linux account on this workstation.
  2. Create the Bitwarden account for AI agents; give me client_id + client_secret.
  3. Generate Cloudron invite links for the 3 Q3 agents (vp-techops, vp-secops, vp-techcompliance). Put in a manifest file:
    vp-techops | VP TechOps | https://tsys-cloudron.knel.net/invitation/<token> | Q3
    vp-secops | VP SecOps | https://tsys-cloudron.knel.net/invitation/<token> | Q3
    vp-techcompliance | VP TechCompliance | https://tsys-cloudron.knel.net/invitation/<token> | Q3
    
  4. Resolve the Discourse admin blocker — create the VP SecOps category via web UI (or give me an admin API key).
  5. (Optional) Generate invites for Q4 agents too (coo, svp-knel, svp-tctc) — Phase 1 only, no system access until Q4.

Once I have items 1-3, I build the Playwright automation and execute Phases 1-2.