Skip to content

About

A skill for Claude Code on the Web that bootstraps cloud provider credentials (GCP, AWS, Azure) and stores them encrypted in your repo.

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Repository files navigation

cloud-bootstrap

Version License: MIT Claude Skill Providers

Encrypted cloud credentials that survive Claude Code sessions — set up once, authenticate forever.

A skill for Claude Code on the Web that bootstraps cloud provider credentials (GCP, AWS, Azure) and stores them encrypted in your repo. One install, and every future session auto-authenticates in seconds.


Features at a Glance

  • Zero-touch session auth — SessionStart hook decrypts and authenticates automatically, every session
  • Multi-provider — GCP, AWS, and Azure in the same repo, each with independent credentials
  • Multi-team — Each team member has their own encrypted key and passphrase, no secrets shared
  • AES-256-CBC encryption — Credentials are encrypted with OpenSSL; only the passphrase stays outside the repo
  • Automatic key rotation warnings — Flags credentials older than 180 days
  • Minimal IAM footprint — Proposes least-privilege roles, never escalates on its own
  • 7 built-in workflows — Setup, onboarding, authentication, rotation, escalation, multi-provider, and uninstall
  • One-line install — curl | bash and you're done

How It Compares

Approach Persistent across sessions? Works in Claude Code Web? No external service needed? Per-user encryption?
cloud-bootstrap Yes Yes Yes Yes
GCP Secret Manager Yes Needs API access first No No
AWS Secrets Manager Yes Needs API access first No No
HashiCorp Vault Yes No (requires server) No Configurable
.env files No (wiped each session) Partially Yes No
Paste token each session No Yes Yes N/A

cloud-bootstrap solves the chicken-and-egg problem: you need credentials to access a secret manager, but you need the secret manager to store credentials.


The Problem

Claude Code on the Web has no persistent storage across sessions except the repo itself. If your project needs cloud access, you need a way to store credentials that:

  • Survives across sessions
  • Travels with the repo
  • Doesn't expose secrets in git history
  • Lets the agent authenticate without human intervention each session

How It Works

First user (one-time setup):

  1. You tell the agent which cloud provider and project to use
  2. The agent proposes minimum roles; you approve
  3. You generate a short-lived token locally and paste it in
  4. The agent creates a service account, encrypts the key with openssl, and commits the encrypted file
  5. In future sessions, the agent decrypts and authenticates automatically

Additional team members:

  1. A teammate opens the repo in Claude Code on the Web
  2. The agent sees the existing cloud config but no credentials for this user
  3. The teammate generates a short-lived token and pastes it in
  4. The agent creates a new key for the same service account, encrypted with the teammate's own passphrase
  5. No passwords are shared between team members

Each person's encrypted credentials are stored as .cloud-credentials.<git-email>.enc. The service account, roles, and project config are shared.

The only secret not in the repo is the encryption passphrase, which you set as an environment variable in Claude Code on the Web. You can use a provider-specific variable (GCP_CREDENTIALS_KEY, AWS_CREDENTIALS_KEY, AZURE_CREDENTIALS_KEY) or a universal one (CLOUD_CREDENTIALS_KEY). The skill checks the provider-specific variable first and falls back to the universal one.

This means if you work with multiple providers across different repos, you can use distinct passphrases per provider. If you only use one provider, just set CLOUD_CREDENTIALS_KEY and forget about it.

Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Your Repository                          │
│                                                             │
│  .cloud-config.json          ← provider, project, roles    │
│  .cloud-credentials.*.enc   ← AES-256-CBC encrypted keys   │
│  .claude/hooks/cloud-auth.sh ← SessionStart auto-auth      │
│  .claude/skills/cloud-bootstrap/SKILL.md ← this skill      │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│                    Each Session                              │
│                                                             │
│  1. SessionStart hook fires                                 │
│  2. Decrypts credentials using env var passphrase           │
│  3. Activates cloud CLI (gcloud/aws/az)                     │
│  4. Deletes plaintext key immediately                       │
│  5. Cloud access ready — no human intervention              │
└─────────────────────────────────────────────────────────────┘

Quick Start

# 1. Install the skill (from your repo root)
curl -sSL https://raw.githubusercontent.com/ipeirotis/cloud-bootstrap/main/install.sh | bash

# 2. Set your encryption passphrase in Claude Code on the Web
#    (Settings → Environment Variables)
#    CLOUD_CREDENTIALS_KEY = <your-secret-passphrase>

# 3. Tell Claude:
#    "Set up GCP credentials for project my-project-id"

# That's it. Every future session authenticates automatically.

Install

One-liner (from your repo root):

curl -sSL https://raw.githubusercontent.com/ipeirotis/cloud-bootstrap/main/install.sh | bash

Manual install (if you prefer to see each step):

# From the repo root
# Every file from one commit: main can move between downloads
# Resolved with git, not GitHub's REST API, whose unauthenticated quota is
# shared by everyone behind the same IP address
SHA=$(git ls-remote https://github.com/ipeirotis/cloud-bootstrap.git refs/heads/main | cut -f1)
printf '%s' "$SHA" | grep -qxE '[0-9a-f]{40}' || { echo "ERROR: could not resolve the current release commit."; exit 1; }
BASE=https://raw.githubusercontent.com/ipeirotis/cloud-bootstrap/$SHA
DEST=.claude/skills/cloud-bootstrap

# MANIFEST lists every distributed file (including scripts/discard-credential.sh,
# which the workflows call when a new credential has to be revoked)
# Download everything to a temp dir first; install only if every file arrived,
# so a failed download never leaves a mix of old and new files
STAGE=$(mktemp -d) && [ -n "$STAGE" ] && [ -d "$STAGE" ] \
  || { echo "ERROR: could not create a staging directory; nothing changed."; exit 1; }
trap 'rm -rf "$STAGE"' EXIT
# To a file first: a download cut off midway must fail here, not leave a
# shorter list that installs only part of the skill
curl -fsSL "$BASE/MANIFEST" -o "$STAGE/.manifest" \
  || { echo "ERROR: could not download MANIFEST; nothing changed."; exit 1; }
FILES=$(grep -v -e '^[[:space:]]*#' -e '^[[:space:]]*$' "$STAGE/.manifest"); rm -f "$STAGE/.manifest"
[ -n "$FILES" ] || { echo "ERROR: MANIFEST is empty; nothing changed."; exit 1; }
# Refuse any path outside the skill before creating a directory or file
for FILE in $FILES; do
  case "$FILE" in /*|*..*) echo "ERROR: MANIFEST lists an unsafe path ($FILE); nothing changed."; exit 1 ;; esac
done
for FILE in $FILES; do
  mkdir -p "$STAGE/$(dirname "$FILE")"
  curl -fsSL "$BASE/$FILE" -o "$STAGE/$FILE" || { echo "ERROR: could not download $FILE; nothing changed."; rm -rf "$STAGE"; exit 1; }
done
# As install.sh does: every file SKILL.md or a workflow names, and the revocation helper,
# must have arrived before the old copy is replaced
for REQ in VERSION SKILL.md scripts/discard-credential.sh \
           $(cat "$STAGE/SKILL.md" "$STAGE"/workflows/*.md 2>/dev/null \
             | grep -oE '(workflows|references|scripts)/[A-Za-z0-9_-]+\.(md|sh)' | sort -u); do
  [ -s "$STAGE/$REQ" ] || { echo "ERROR: the release lacks $REQ; nothing changed."; exit 1; }
done
# Record what was installed, as install.sh does, so update.sh can later remove
# files a newer release drops
printf '%s\n' $FILES > "$STAGE/.installed-files"
# Swap the complete staged copy in with renames (as update.sh does): a failure
# leaves the existing installation untouched, never a mix of two releases
mkdir -p "$(dirname "$DEST")"
NEW=$(mktemp -d "$(dirname "$DEST")/.cloud-bootstrap.new.XXXXXX") \
  || { echo "ERROR: could not create a directory next to $DEST; nothing changed."; exit 1; }
OLD_DIR="$(dirname "$DEST")/.cloud-bootstrap.old.$$"
trap 'rm -rf "$STAGE" "$NEW"; if [ -d "$OLD_DIR" ] && [ ! -e "$DEST" ]; then mv "$OLD_DIR" "$DEST"; fi' EXIT
cp -R "$STAGE"/. "$NEW"/ && chmod 755 "$NEW" \
  || { echo "ERROR: could not prepare the new copy; nothing changed."; exit 1; }
if [ -e "$DEST" ]; then mv "$DEST" "$OLD_DIR" || { echo "ERROR: could not move the old copy aside; nothing changed."; exit 1; }; fi
mv "$NEW" "$DEST" || { echo "ERROR: could not move the new copy into place; the old one is restored."; exit 1; }
rm -rf "$OLD_DIR"

git add "$DEST"
git commit -m "Add cloud-bootstrap skill" -- "$DEST"   # only the skill, not anything else already staged

Or just tell Claude Code on the Web:

"Clone the cloud-bootstrap skill from https://github.com/ipeirotis/cloud-bootstrap into .claude/skills/cloud-bootstrap/ in this repo and commit it."

Updating

Check which version you have and whether a newer one is available:

curl -sSL https://raw.githubusercontent.com/ipeirotis/cloud-bootstrap/main/update.sh | bash

This will:

  1. Show your installed version and the latest version
  2. Display the changelog entries you'd be getting
  3. Ask for confirmation on your terminal before updating (where no terminal is available, run ... | bash -s -- --yes)

You can also check your installed version at any time: cat .claude/skills/cloud-bootstrap/VERSION.

Prerequisites

  • Encryption passphrase set as an environment variable in Claude Code on the Web: either GCP_CREDENTIALS_KEY / AWS_CREDENTIALS_KEY / AZURE_CREDENTIALS_KEY, or the universal CLOUD_CREDENTIALS_KEY
  • A cloud account with permission to create service accounts and assign roles
  • openssl available in the environment (standard on CCoW)

Supported Providers

Provider Bootstrap Command What Gets Created Team Limit
GCP gcloud auth print-access-token Service account + JSON key per user ~10 (keys per SA)
AWS aws sts get-session-token IAM group + IAM user per team member Bounded by the account's IAM user quota
Azure az account get-access-token Service principal + client secret per user Bounded: secrets share the app manifest's credential limit, and rotated or departed members' secrets count until removed

Files Created in Your Repo

File Purpose Committed?
.cloud-credentials.<email>.enc Encrypted key, one per team member Yes
.cloud-config.json Provider, project ID, roles (shared) Yes
.claude/hooks/cloud-auth.sh SessionStart hook: installs CLI + authenticates Yes
.claude/settings.json Hook configuration Yes
CLAUDE.md (Cloud Credentials section) Human/agent-readable auth docs Yes
credentials.json Never (plaintext key) .gitignored

Multi-provider repos: When using multiple providers, credential files are named .cloud-credentials.<provider>.<email>.enc and .cloud-config.json uses a providers array format. See SKILL.md for details.

Security Model

  • Each team member's credentials are encrypted with their own passphrase (never shared)
  • Credentials are encrypted with AES-256-CBC (via openssl)
  • Plaintext keys exist only momentarily during setup and authentication, and are deleted immediately
  • The agent cannot escalate its own permissions; it must ask you
  • Bootstrap tokens expire in ~1 hour
  • Encryption passphrases never enter the repo
  • Revoking a team member's access: delete their .cloud-credentials.<email>.enc file and remove their key/user from the cloud provider

Troubleshooting

Symptom Likely Cause Fix
"No credentials key found" Passphrase env var not set Set CLOUD_CREDENTIALS_KEY in Claude Code Web settings
Decryption fails silently Wrong passphrase or corrupted .enc file Re-run setup with the correct passphrase
403 after authentication Service account missing a role Ask your admin to grant the needed role (skill will suggest which one)
CLI not found after hook runs Install failed or PATH issue Re-open session; hook retries install on next start
Credential age warning Key older than 180 days Run credential rotation workflow

License

MIT

About

A skill for Claude Code on the Web that bootstraps cloud provider credentials (GCP, AWS, Azure) and stores them encrypted in your repo.

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Contributors

Languages