Files
claudetools/.claude/commands/1password.md
Mike Swanson 7128b9e57d Session log: cPanel CVE-2026-41940 IOC scan + remediation on IX/WebSvr
Both servers were already patched (11.110.0.97 and 11.134.0.20) via
daily auto-update. IOC scan found 16 flagged sessions across both
plus 4 uncommented SSH keys on IX.

Critical remediation:
- Forensic evidence preserved before any deletion
- 4 uncommented SSH keys removed from IX (server-side backup retained)
- 16 flagged sessions purged across both servers
- Root passwords rotated via chpasswd
- New WHM API tokens created; 3 stale transfer-* tokens revoked
- Vault entries + 1Password Infrastructure items updated

Forensic deep-dive verdict: patch held. All 7 actual CVE exploit
attempts (botnet IPs hitting /json-api/version) returned HTTP 403.
The "multi-line pass" IOC hits on user sessions were false positives.
Unidentified 76.18.103.222 root session traced to routine SSL
maintenance (zero sensitive endpoints touched).

Skill hardening:
- Added MANDATORY service-token directive to .claude/commands/1password.md
  enforcing OP_SERVICE_ACCOUNT_TOKEN from SOPS for all op CLI calls
- Per Mike: memory files alone don't reliably bind agent behavior;
  baking governance into skill content loaded at moment of use.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 07:22:52 -07:00

9.5 KiB

name, description
name description
1password Integrate 1Password secrets management into Claude Code workflows. Use when the user wants to: store API keys or credentials in 1Password, read secrets from 1Password into scripts or config, set up .env files using 1Password secret references, rotate or update credentials, manage developer secrets across projects, use 1Password service accounts for CI/CD, or integrate 1Password with tools like Claude Desktop, n8n, Docker, Supabase, GitHub Actions, or Replit. Triggers on phrases like "store in 1Password", "read from 1Password", "op://", "secret reference", "manage API keys with 1Password", "1Password CLI", or any request involving the `op` command.

1Password Skill

⚠️ Critical: Never Type Secrets Into Claude Code

Claude Code can see everything typed in its terminal and chat.

When a user needs to store a secret, ALWAYS use the Terminal launch pattern:

  1. Generate a pre-filled script with known values already set
  2. Use launch-in-terminal.sh to open it in Terminal.app
  3. User types secrets in that window — Claude Code cannot see it
  4. 1Password stores the secret, outputs op:// references back to Claude
# Claude generates the script, then launches it outside its own view:
bash scripts/launch-in-terminal.sh /tmp/setup-my-service.sh "Service Name Setup"

Never ask users to paste API keys, passwords, or tokens into:

  • The Claude Code chat
  • A Bash tool call visible in Claude Code
  • Any file Claude Code writes before it's stored in 1Password

⚠️ MANDATORY: Use the SOPS-vaulted service account token, never the desktop session

Every op invocation in agent flows must run with OP_SERVICE_ACCOUNT_TOKEN set. The desktop-app integration prompts to unlock the app, which interrupts the agent flow and is unacceptable. The service token is in the SOPS vault at infrastructure/1password-service-account.sops.yaml (vault entry kind=api-key, name=1Password Service Account (Agentic-RW)).

Load the token at the start of any 1Password work

# Decrypt the service token from SOPS (uses the machine's age key)
export OP_SERVICE_ACCOUNT_TOKEN=$(sops -d /c/Users/guru/vault/infrastructure/1password-service-account.sops.yaml 2>/dev/null \
  | grep -E '^\s*credential:' | sed -E 's/^\s*credential:\s*//' | head -1)

# Verify
op whoami    # expect "User Type: SERVICE_ACCOUNT"

After export, every subsequent op call in the same bash invocation inherits the token. For one-off calls without exporting:

SVC=$(sops -d /c/Users/guru/vault/infrastructure/1password-service-account.sops.yaml 2>/dev/null | grep -E '^\s*credential:' | sed -E 's/^\s*credential:\s*//' | head -1)
OP_SERVICE_ACCOUNT_TOKEN="$SVC" op item get "Item Name" --vault Infrastructure

Vault path resolution

The vault lives wherever .claude/identity.json says (vault_path). On the current Windows workstation it's C:/Users/guru/vault, but other machines (Howard's, future workstations) may differ. Resolve dynamically when needed:

VAULT_DIR=$(python -c "import json; print(json.load(open('/c/Users/guru/ClaudeTools/.claude/identity.json'))['vault_path'])")
SVC=$(sops -d "$VAULT_DIR/infrastructure/1password-service-account.sops.yaml" 2>/dev/null | grep -E '^\s*credential:' | sed -E 's/^\s*credential:\s*//' | head -1)
export OP_SERVICE_ACCOUNT_TOKEN="$SVC"

Service account scope (verified 2026-04-30)

The Agentic-RW service account has access to: Clients, Infrastructure, Internal Sites, Managed Websites, MSP Tools, Projects, Sorting. The Private vault is intentionally NOT shared with the service account — if you need to read from Private, that's a different conversation, not a fallback to desktop session.

When the token fails

  • op vault list returns "account is not signed in" with the token set → token is malformed or revoked. Decrypt directly via sops -d and inspect.
  • vault.sh get-field may fail with "PyYAML not installed" — use direct sops -d + grep instead until that wrapper bug is fixed.
  • Never fall back to the desktop-app session in agent flows. If the service token is unrecoverable, stop and tell Mike.

Setup Check (only for net-new machine onboarding)

For a fresh workstation that doesn't have the service token wired up yet:

bash scripts/check_setup.sh

If not installed: https://developer.1password.com/docs/cli/get-started/

The desktop-app sign-in flow is for interactive human use, not agent flows — those go through the service account above.


Storing Secrets: The Terminal Launch Pattern

When a user needs to store a new secret or credential:

Step 1 — Generate the script (Claude does this, with known values pre-filled):

cat > /tmp/setup-SERVICE.sh << 'EOF'
bash /path/to/store-mcp-credentials.sh \
  --vault Dev \
  --item "Service Name" \
  --set "url=https://known-url.com" \
  --set "env=production" \
  --secret "api_key" \
  --secret "webhook_secret"
EOF

Step 2 — Launch in Terminal.app (secrets stay out of Claude Code):

bash scripts/launch-in-terminal.sh /tmp/setup-SERVICE.sh "Service Name Setup"

Step 3 — Update config (Claude uses the op:// references from the output):

"SERVICE_API_KEY": "op://Dev/Service Name/api_key"

Core Patterns

Read a secret

op read "op://VaultName/ItemTitle/field_name"
export API_KEY=$(op read "op://Dev/Anthropic/api_key")

Store a new secret

# Basic
bash scripts/store_secret.sh --title "My API Key" --field api_key --value "sk-..."

# With vault
bash scripts/store_secret.sh --title "My API Key" --vault Dev --field api_key --value "sk-..."

# From environment variable
bash scripts/store_secret.sh --from-env ANTHROPIC_API_KEY --title "Anthropic"

# Generate a secure credential
bash scripts/store_secret.sh --title "App Secret" --field secret --generate --length 32

Update an existing secret

bash scripts/store_secret.sh --update --title "My API Key" --field api_key --value "new-value"
# Or directly:
op item edit "My API Key" api_key[password]=new-value

Generate a .env from 1Password

# Interactive — lists items, choose one
bash scripts/env_from_op.sh

# From a specific item (dry run preview)
bash scripts/env_from_op.sh --item "Project Credentials" --dry-run

# Write .env.tpl (secret references — safe to commit)
bash scripts/env_from_op.sh --item "Project Credentials" --output .env.tpl

# Write .env with resolved real values (DO NOT commit)
bash scripts/env_from_op.sh --item "Project Credentials" --resolve --output .env

Secret References (op://)

The safest pattern — store op:// references in config files instead of real values.

Privacy note: op:// references reveal vault names, item names, and field names. Safe to commit to private repos. For public repos, check that your vault/item naming doesn't expose sensitive structure (client names, internal service names, etc.).

op://VaultName/ItemTitle/field_name
# .env.tpl (commit this file)
ANTHROPIC_API_KEY=op://Dev/Anthropic/api_key
N8N_API_KEY=op://Dev/n8n/api_key
SUPABASE_SERVICE_KEY=op://Dev/Supabase/service_key

# ✅ Inject at runtime — secrets stay in subprocess, never in shell history
op run --env-file=.env.tpl -- your-command

# ⚠️  Avoid sourcing into current shell — unsafe if values contain $(...) or backticks
# source <(op run --env-file=.env.tpl -- env)   ← skip this pattern

For full syntax and edge cases: references/secret_references.md


Integration Guides

Read references/integrations.md for patterns with:

  • Claude Desktop — MCP server config using op run
  • n8n — Environment injection at startup, credential push via API
  • Docker / Docker Composeop run -- docker compose up
  • GitHub Actions1password/load-secrets-action
  • Python scripts — subprocess + 1Password SDK
  • Supabase — Storing and retrieving project credentials
  • Replit — Local dev → Replit Secrets bridge
  • Rotation workflow — Update in service → update in 1Password → re-inject

Common CLI Commands

Full reference: references/op_commands.md

op item list                           # List all items
op item list --vault Dev               # Filter by vault
op item get "Item Title"               # View item details
op item get "Item Title" --format json # JSON output
op vault list                          # List vaults
op whoami                              # Check auth status
op account list                        # List accounts

CI/CD: Service Accounts

For non-interactive environments (GitHub Actions, Docker, n8n server):

export OP_SERVICE_ACCOUNT_TOKEN="ops_eyJ..."
op read "op://Dev/MyApp/api_key"   # works without signin prompt

Create service accounts: 1Password UI → Settings → Developer → Service Accounts. Grant vault access only to what the service needs.


Security Rules

  1. Never hardcode secrets — always use op:// references or runtime injection
  2. Commit .env.tpl to private repos only — it exposes vault/item structure, not values
  3. Never commit .env (real values) — add it to .gitignore immediately: echo ".env" >> .gitignore
  4. Use vaults to scope access — separate vault per project or team
  5. Rotate on exposure — use store_secret.sh --update then re-inject everywhere
  6. Service accounts for CI/CD — never use personal account tokens in automation