Migrations-Plan

Phase 1 — ROT-Fixes (Aufwand: 30 min, Risiko: niedrig)

Wann: sofort, vor allem anderen.

1.1 GitHub PAT rotieren

  1. Token-Inventar prüfen: ist der claude.json-Token (gho_Pfcm...) derselbe wie der in AWS SM agent-platform/github-pat?

    aws --profile av-production secretsmanager get-secret-value \
      --secret-id agent-platform/github-pat \
      --query SecretString --output text

    Wenn identisch: ein Token, zwei Stellen. Wenn unterschiedlich: zwei Tokens, beide rotieren.

  2. GitHub.com → Settings → Developer settings → Personal access tokens:

    • Den alten Token revoken
    • Neuen Fine-Grained PAT erstellen: Scope nur das was Claude Code wirklich braucht (repo read + write auf eigene Repos). Lifetime: 90 Tage.
  3. Neuen Token in 1Password ablegen: Item „GitHub PAT — Claude Code”, Field credential mit Token.

  4. AWS SM aktualisieren (falls Lambda agents-platform es nutzt):

    aws --profile av-production secretsmanager put-secret-value \
      --secret-id agent-platform/github-pat \
      --secret-string '<neuer-token>'
  5. claude.json umstellen auf op run:

    # Erst die op-Item-ID des neuen 1P-Items rausfinden
    op item get "GitHub PAT — Claude Code" --format json | jq -r '.id'

    Dann claude.json patchen, sodass mcpServers.github so aussieht:

    {
      "command": "op",
      "args": ["run", "--", "docker", "run", "-i", "--rm",
               "-e", "GITHUB_PERSONAL_ACCESS_TOKEN",
               "ghcr.io/github/github-mcp-server"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "op://Personal/<item-id>/credential"
      }
    }
  6. Smoke-Test: Claude Code restarten → gh MCP-Tools fragen → muss funktionieren.

  7. Inventar-File updaten: claude.json-Zeile in claude-json—claude-json auf „op-Wrapper” ändern.

1.2 Akut-Check unbekanntes 1P-Item

  1. Item pu5tfghpcg26g6nxou6mozlnxm öffnen in 1Password GUI → notes lesen, Field Benutzername und Anmeldedaten checken.
  2. Klären: wofür ist das, wer/was verbraucht es, kann es weg.
  3. Inventar-Eintrag in 1password—vault-personal aktualisieren.

Phase 2 — Lokale .env.local zu op run (Aufwand: 1-2h, Risiko: niedrig)

Wann: diese Woche, nach Phase 1.

Ziel: alle lokalen MCP-Server starten ihre Secrets nicht aus .env.local-Files, sondern aus 1Password via op run --. Konsistent mit Hetzner-Pattern.

2.1 Pro MCP-Repo

Reihenfolge (einfachste zuerst):

MCPTokens1P-Item-Name (Vorschlag)
mcp-replicateREPLICATE_API_TOKEN„Replicate API — Claude Code”
mcp-runwayRUNWAYML_API_SECRET„Runway ML API — Claude Code”
mcp-calcomCALCOM_API_KEY„Cal.com API — Claude Code”
mcp-lexware-officeLEXWARE_OFFICE_API_KEY„Lexware Office API”
mcp-sevdeskSEVDESK_API_TOKEN„SevDesk API”
agentic-ventures/.env.localELEVENLABS_API_KEY„ElevenLabs API — Claude Code”

Schritte pro MCP:

  1. 1P-Item anlegen mit dem Token-Wert

  2. Start-Skript des MCP umstellen (typisch start.sh oder Makefile):

    # vorher:
    uv run python -m app.server
    # nachher:
    op run -- uv run python -m app.server

    Oder Env-Var-Referenz direkt im Wrapper:

    export TOKEN="op://Personal/<item-id>/credential"
    op run --no-masking -- python -m app.server
  3. .env.local löschen (oder zu .env.local.example umbenennen mit Platzhalter-Wert)

  4. Test: MCP-Server lokal starten, ein Tool aufrufen

2.2 Sub-MCPs in mcp-vf-hosted (hybrid)

Für mcp-vf-hosted/.env (lokal-dev, dupliziert mit AWS SM mcp-vf-hosted/upstream-tokens): Wrapper-Skript schreiben das beim lokalen Start die Werte aus AWS SM holt:

#!/usr/bin/env bash
# mcp-vf-hosted/scripts/start-local.sh
set -euo pipefail
SECRET_JSON=$(aws --profile av-production secretsmanager get-secret-value \
  --secret-id mcp-vf-hosted/upstream-tokens --query SecretString --output text)
export PAPIERKRAM_TOKEN=$(echo "$SECRET_JSON" | jq -r '.papierkram_token')
export TICKETPAY_API_KEY=$(echo "$SECRET_JSON" | jq -r '.ticketpay_api_key')
export M365_CLIENT_ID=$(echo "$SECRET_JSON" | jq -r '.m365_client_id')
export M365_CLIENT_SECRET=$(echo "$SECRET_JSON" | jq -r '.m365_client_secret')
export M365_TENANT_ID=$(echo "$SECRET_JSON" | jq -r '.m365_tenant_id')
exec uv run python -m app.main

.env löschen.

Phase 3 — AWS SM Cleanup (Aufwand: 30min, Risiko: niedrig)

Wann: parallel zu Phase 2.

  1. tmp/owui-admin-key prüfen:

    aws --profile av-production secretsmanager describe-secret --secret-id tmp/owui-admin-key

    Wenn unused (kein VersionsToStages, keine GetSecretValue-Calls in CloudTrail letzte 30 Tage): löschen mit 7-Tage-Recovery:

    aws --profile av-production secretsmanager delete-secret \
      --secret-id tmp/owui-admin-key --recovery-window-in-days 7
  2. stirling-pdf-vf/cloudflared-token prüfen: Stirling läuft cert-basiert (siehe av-tools), Token-Secret unused. Analog löschen.

  3. secrets-manager.md Inventar im Vault entsprechend updaten.

Phase 4 — 1P-Pointer-Layer aufbauen (Aufwand: 1h, Risiko: keine)

Wann: nach Phase 1-3, wenn das aufgeräumte AWS SM stabil ist.

Ziel: für jeden AWS-SM-Secret existiert in 1Password ein Read-Only-Index-Item, das als Recovery-Pointer dient. Falls AWS SSO/Login mal nicht geht, findest du übers 1P-Pointer den Secret-Namen + manuellen Recovery-Pfad.

Pro AWS-SM-Secret (z.B. cloudflare/api-token):

  1. 1P-Item-Type Secure Note, Titel [AWS SM] cloudflare/api-token

  2. Felder:

    • aws_account: av-production (425924867359)
    • aws_region: eu-central-1
    • secret_name: cloudflare/api-token
    • purpose: Zweck (aus AWS SM Description kopieren)
    • last_rotated: Datum
    • next_rotation: Datum (siehe rotation-kalender)
    • recovery_cmd: aws --profile av-production secretsmanager get-secret-value --secret-id cloudflare/api-token
  3. Tag aws-sm-pointer für alle Index-Items → in 1P leicht filterbar

Automatisierung: Skript scripts/sync-aws-sm-to-1p.sh das alle AWS-SM-Secret-Metadata in 1P spiegelt (ohne Werte). Nice-to-have, nicht Phase-4-blockierend.

Phase 5 — Rotation-Disziplin (Aufwand: 30min, Risiko: keine)

Wann: nach Phase 4.

  1. rotation-kalender mit Schedule pro Secret ausarbeiten
  2. Kalender-Reminder anlegen im Calendar (hello@) für die next_rotation-Daten
  3. Quartalsweise Audit-Routine in tages-planung-Skill ergänzen: alle 3 Monate „Secret-Rotation-Check” als Task

Phase 6 — CLAUDE.md Rule 8 erweitern (Aufwand: 10min)

Rule 8 aktuell: „Secrets pruefen. Bevor du etwas committest das wie Schluessel/Token/Passwort aussieht: STOP, fragen.”

Ergänzung: konkrete Tier-Verweise.

8. **Secrets pruefen.** Bevor du etwas committest das wie Schluessel/Token/Passwort aussieht: STOP, fragen.
   - Service-Secrets (Fargate/Lambda/CDK) → AWS SM in av-production
   - Lokale CLI / MCP-stdio → 1Password via `op run --`
   - Plaintext in claude.json / settings.json / .env nicht .local: VERBOTEN
   - Detail: [[intern/projekte/secret-konsolidierung/_index]]

Out-of-Scope (bewusst)

  • Doppler / Infisical / Bitwarden Secrets Manager Evaluation — AWS SM tut’s für dein Scale.
  • HashiCorp Vault — Overkill für 1-Person-Shop.
  • Auto-Rotation via Lambda für API-Keys — kommt, wenn Volumen steigt. Aktuell manuell mit Reminder.
  • Customer-Secret-Vault (separater AWS-Account für Becker/VF-Customer-Tokens) — eigene Initiative, nicht hier.

Definition of Done

Projekt ist done, wenn:

  1. Keine Klartext-Tokens mehr in claude.json / settings.json / .env außerhalb von .env.local-Files
  2. Alle Service-Secrets in AWS SM, alle lokalen Secrets in 1P via op run
  3. Jeder AWS-SM-Secret hat einen 1P-Pointer
  4. Jeder Secret hat ein next_rotation-Datum im Kalender
  5. CLAUDE.md Rule 8 erweitert
  6. inventar aktualisiert, Akut-Findings alle grün