Project · gcp-mcp-standalone · Runbooks

Runbook — Rotate Broker Secrets

type runbookstatus activesecurity · secrets · rotation · runbook

When to use

A credential is suspected compromised (e.g. pasted in plaintext), on a routine rotation schedule, or when a provider secret is regenerated. Covers the broker's OAuth client secrets and the Telegram bot token.

Principle

Every secret follows the same path: regenerate at the source → update where it lives → redeploy. OAuth client secrets live in Secret Manager and reach the box via Ansible; the Telegram bot token lives in a file on the VM. Existing OAuth access tokens keep working after a client-secret rotation — the new secret is exercised on the next token refresh or reconnect.

OAuth client secrets (GitHub, Notion, …)

  1. Regenerate at the provider (GitHub → Developer settings → OAuth Apps → Generate a new client secret; Notion → integrations → regenerate secret).
  2. Store the new value as a new Secret Manager version (deploy always fetches latest): pbpaste | gcloud secrets versions add <secret-name> --project=bob-mcp-project-2026 --data-file=- Secret names: github-oauth-client-secret, notion-oauth-client-secret, tailscale-oauth-client-secret, gitlab-token, adzuna-app-id, adzuna-app-key.
  3. Redeploy the broker (re-fetches into .env, restarts): cd ansible && ansible-playbook -i inventory.ini install.yml -e cloudflare_tunnel_token="$(cat ~/.cf-tunnel-token)"
  4. Validate without a browser reconnect — confirm the deployed value matches Secret Manager and has the right shape (catches a clipboard swap: GitHub secrets are 40 hex chars; Notion secrets start secret_): ssh ubuntu@gcp-mcp-broker "sudo grep '^GITHUB_CLIENT_SECRET=' /home/ubuntu/mcp-broker/.env | cut -d= -f2- | grep -qE '^[0-9a-f]{40}$' && echo shape-ok" For 100% proof, disconnect + reconnect the connector (browser OAuth) — that exercises the new secret directly.

Telegram bot token

The bot token is not in Secret Manager — it lives in /home/claudebot/.config/telegram.env (TELEGRAM_BOT_TOKEN) and the source of truth is ~/.tg-bot-token on the Mac (read by claudebot.yml on deploy). 1. @BotFather → /revoke → pick the bot → copy the new token. 2. Update the live file + restart the service, and keep the Mac source of truth in sync (otherwise a rebuild restores the old token): ssh -t ubuntu@gcp-mcp-broker 'read -rs T && sudo sed -i "s|^TELEGRAM_BOT_TOKEN=.*|TELEGRAM_BOT_TOKEN=$T|" /home/claudebot/.config/telegram.env && sudo systemctl restart claude-telegram.service && echo done' # then sync the Mac source of truth: ssh ubuntu@gcp-mcp-broker "sudo grep '^TELEGRAM_BOT_TOKEN=' /home/claudebot/.config/telegram.env | cut -d= -f2-" > ~/.tg-bot-token && chmod 600 ~/.tg-bot-token

Gotchas

  • Deploy fetches latest — if you add a wrong value, it goes live on the next deploy. Verify shape (above) before trusting it.
  • gcloud CLI vs ADCgcloud secrets needs a live CLI login (gcloud auth login); Terraform needs the ADC login (gcloud auth application-default login). They expire independently.
  • Mac ↔ VM drift for the bot token — always re-sync ~/.tg-bot-token after rotating the Telegram token, or the next claudebot.yml run restores the old one.

Sources

Compiled from wiki/projects/gcp-mcp-standalone/runbooks/rotate-secrets.md · git is the source of truth