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
This commit is contained in:
2026-08-13 10:43:48 -05:00
commit 8c76cf1bab
7 changed files with 876 additions and 0 deletions
+382
View File
@@ -0,0 +1,382 @@
# 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:
```bash
#!/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@<cloudron-domain> | 55, 59 | KNEL, TechnicalOperations | 74, 20 |
| **vp-secops** | vp-secops@<cloudron-domain> | 55 (security) | KNEL | 74 + new VP SecOps cat |
| **vp-techcompliance** | vp-techcompliance@<cloudron-domain> | 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 | display-name | invite-link | priority` |
| 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:
```bash
# ~/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:
```bash
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:**
```python
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.