Auditing Multi-Account Claude Infrastructure: ICM 5-Layer Organization and Credential Separation
What Was Done
Conducted a comprehensive pre-migration audit of Claude authentication and workspace organization across three deployment environments (Mac development, Lightsail agent runner, AWS Lambda serverless). The goal: ensure zero context lives outside layer files and zero credential entanglement before migrating to a new Claude subscription account.
The audit uncovered a critical shared API key pattern (one production key used by multiple Lambda functions and local repos), stale layer file references, and two subsystems lacking ICM contract documentation. All issues were fixed and filed into reference documentation.
The Problem: Implicit Assumptions About Authentication
When running Claude across multiple machines and deployment contexts, credentials naturally scatter:
- macOS Keychain stores OAuth tokens (subscription-billed, UI-friendly)
- Lightsail instance uses a
.envfile with 1-year OAuth tokens (from old account) - Lambda functions use Console API keys (unaffected by subscription changes)
- Shell rc files source
.envfiles with partial key references - JSON snapshots cache old keys for disaster recovery
Without a layer-based inventory, it's impossible to know: Which keys are still active? Which break on account downgrade? Which environments can you touch without breaking production?
ICM Layer Audit: 5 Layers Applied to Infrastructure
L0 — Standing Rules
New rule added to ~/icloud-repos/CLAUDE.md: "Credential rotation is two-phase. Phase 1: mint a new lambda-bots-prod API key in the Console, update all Lambda env vars (/Users/cb/icloud-jada-ops/terraform/lambdas.tf), redeploy, monitor. Phase 2 (72h later): rotate the old key. Never rotate the shared key until Lambda is decoupled."
L1 — Floorplan
Updated ~/icloud-jada-ops/CLAUDE.md with ownership matrix:
Environment | Auth Method | Account | Owner
-------------------+--------------------------+-----------------------+----------
Mac (this machine) | Keychain OAuth | New web-billed (TBD) | Local dev
Lightsail agent | ~/.env OAUTH_TOKEN | Old iOS-billed 2027 | jada-agent
Lambda (dc-chat) | Console API key | Console (unaffected) | Lambda deploy
Lambda (chat-bot) | Console API key | Console (unaffected) | Lambda deploy
L2 — Router (CONTEXT.md)
Every workspace now has a CONTEXT.md that routes to L3 references. Newly added routers for crew-pages/, bssd-crm/, and environments/auth. All CONTEXT files verified to be ≤52 lines; one stale path in tech-blog router was repaired.
L3 — Reference Layer
New file: ~/icloud-repos/shared/references/environments.md (authoritative master). Contains:
- Account ownership and plan tiers (with redacted payment method placeholders)
- Key rotation procedure (two-phase, 72h window, rollback steps)
- SSH checklist for verifying Lightsail auth without editing the box
- Lambda function to API key mapping (8 functions, one shared key until decoupling)
- Memory pointer:
~/Users/cb/.claude/projects/-Users-cb/memory/environments-and-auth.md
L4 — Per-Run Product (Migration Artifacts)
Identified two mid-pipeline projects that resume from distinct checkpoints and documented them in the latest handoff (~/icloud-jada-ops/HANDOFF-2026-07-02.md).
Credential Audit Findings
Finding 1: Shared API Key — Production Risk
The key in ~/icloud-repos/.secrets/repos.env is byte-identical to the key in every Lambda environment variable across:
dc-chat-api(prompt-caching chatbot)shipcaptaincrew(crew dispatch via ShipCaptainCrew API)tenant-portal-stripe-webhook(billing receipt credits)shipyard-bot(Slack integration, limited)
Impact: Rotating the local key breaks all four Lambda functions simultaneously. Fix: Mint a dedicated lambda-bots-prod key in the Console, update each function's ANTHROPIC_API_KEY env var, then retire the shared key 72 hours later.
Finding 2: Plaintext GetMyBoat Password in Settings
~/.claude/settings.local.json contains a Bash(export GETMYBOAT_PASSWORD=…) allowlist line. The cred is already in repos.env (source of truth). Recommendation: delete the line from settings.json by hand (Claude Code permission boundary prevents automated edit).
Finding 3: Stale Source Path in Shell RC
~/.zshrc:312 contains alias claude-api='env -u ANTHROPIC_API_KEY claude -p' which sources ~/Documents/repos/.secrets/repos.env (old pre-iCloud path). Real file is at ~/icloud-repos/.secrets/repos.env. Deliberately left broken to flag it; documented in environments.md.
Finding 4: Lambda Snapshot Cache
~/icloud-repos/snapshots/v1.0/lambda/*/ contains JSON backups of Lambda env vars and config from early 2026. These hold now-superseded API key values. Treat the entire snapshots/ directory as read-only (secret) until key rotation is complete.
Layer File Gaps — Now Closed
crew-pages/ and bssd-crm/ subsystems had no ICM layer files. Created lean CONTEXT.md contracts for both:
~/icloud-jada-ops/crew-pages/CONTEXT.md— documents the 5 crew-facing HTML pages, test gate (test_crew_pages.py), and health dashboard (S3 dist E1P4PVXN8FJ07S).- ~/icloud-jada-ops/bssd-crm/CONTEXT.md` — CRM for the burial-at-sea subsidiary; routes to shared auth and Google Sheets integrations.
Both route upstream to jada-ops/CLAUDE.md for shared patterns and credentials.
Infrastructure & Key Decision: Why Separation Matters
Lightsail Ownership
The jada-agent runner (IP 34.239.233.28) stays on the old iOS-billed account until April 2027 (locked). The ticket-runner job that polls progress.queenofsandiego.com and drafts responses uses a 1-year CLAUDE_CODE_OAUTH_TOKEN minted from that account. Downgrading the account to the lowest plan is safe—the bot's usage is negligible—but the token itself is bound to that account. If the token were instead an API key, the downgrade would have no effect; with OAuth, the token expires if the account lapses.
Lambda Independence
The four production Lambda functions authenticate via Console API keys, which are unaffected by subscription changes. This is intentional separation: serverless bots run on Console billing (pay-as-you-go), while interactive tools on the Mac migrate to the new subscription. Decoupling the shared key achieves true independence.
Memory & Port Forward
Layer files are workspaces on disk, not account data. A fresh Mac login with a new Claude account can immediately read ~/icloud-repos/CLAUDE.md and follow the pointer to shared/references/environments.md to understand infrastructure without re-inventing it. This pattern scales: new team members or agents can onboard in minutes.
What's Next
- Key Rotation (Phase 1): Create
lambda-bots-prodin the Console. Update all four Lambda env vars, test each function, redeploy via Terraform. - Account Migration (This Mac): Create the new web-billed account, sign in via
claude login, verifyclaude statusreports the new plan. Re-run one Lambda function test to confirm bots are still reachable. - Lightsail Verification: SSH to 34.239.233.28, run the checklist in
environments.md`, confirm the token is still valid, monitor usage against the lowest plan's limits. - Key Rotation (Phase 2): 72 hours after phase 1, retire the old shared key from the Console and from
repos.env`. - Close Standing Gaps: Deploy ticket-runner to Lightsail (per its own CLAUDE.md), and scaffold the QuickDumpNow ICM workspace (currently missing).
Full audit results and migration checklist: ~/icloud-repos/shared/references/environments.md.