This skill guides integrating 1Password CLI (op) for secret management in development workflows. Use when loading secrets for infrastructure, deployments, or local development.
This skill is limited to using the following tools:
The 1Password CLI (op) provides secure secret injection into development workflows without exposing credentials in code, environment files, or shell history.
op://<vault>/<item>/<field>
Examples:
op://Development/AWS/access_key_id
op://Production/Database/password
op://Shared/Stripe/secret_key
Create .op.env in project root:
# AWS credentials
AWS_ACCESS_KEY_ID=op://Infrastructure/AWS/access_key_id
AWS_SECRET_ACCESS_KEY=op://Infrastructure/AWS/secret_access_key
AWS_REGION=op://Infrastructure/AWS/region
# DigitalOcean
DIGITALOCEAN_TOKEN=op://Infrastructure/DigitalOcean/api_token
# Database
DATABASE_URL=op://Production/PostgreSQL/connection_string
# API Keys
STRIPE_SECRET_KEY=op://Production/Stripe/secret_key
OPENAI_API_KEY=op://Development/OpenAI/api_key
Critical: Add to .gitignore:
# 1Password - NEVER commit
.op.env
*.op.env
# Single command
op run --env-file=.op.env -- terraform plan
# With environment variable prefix
op run --env-file=.op.env -- rails server
# Inline secret reference
op run -- printenv DATABASE_URL
OP ?= op
OP_ENV_FILE ?= .op.env
# Prefix for all commands needing secrets
CMD = $(OP) run --env-file=$(OP_ENV_FILE) --
deploy:
$(CMD) kamal deploy
console:
$(CMD) rails console
migrate:
$(CMD) rails db:migrate
# docker-compose.yml
services:
app:
build: .
environment:
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
# Run with secrets injected
op run --env-file=.op.env -- docker compose up
# config/deploy.yml
env:
secret:
- RAILS_MASTER_KEY
- DATABASE_URL
- REDIS_URL
# .kamal/secrets (loaded by Kamal)
RAILS_MASTER_KEY=$(op read "op://Production/Rails/master_key")
DATABASE_URL=$(op read "op://Production/PostgreSQL/url")
REDIS_URL=$(op read "op://Production/Redis/url")
# .github/workflows/deploy.yml
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: 1password/load-secrets-action@v2
with:
export-env: true
env:
OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}
AWS_ACCESS_KEY_ID: op://CI/AWS/access_key_id
AWS_SECRET_ACCESS_KEY: op://CI/AWS/secret_access_key
- run: terraform apply -auto-approve
# Read single field
op read "op://Vault/Item/field"
# Read with output format
op read "op://Vault/Item/field" --format json
# Read to file (for certificates, keys)
op read "op://Vault/TLS/private_key" > /tmp/key.pem
chmod 600 /tmp/key.pem
# Single secret inline
DATABASE_URL=$(op read "op://Production/DB/url") rails db:migrate
# Multiple secrets via env file
op run --env-file=.op.env -- ./deploy.sh
# With account specification
op run --account my-team --env-file=.op.env -- terraform apply
# List vaults
op vault list
# List items in vault
op item list --vault Infrastructure
# Get item details
op item get "AWS" --vault Infrastructure
# Create item
op item create \
--category login \
--vault Infrastructure \
--title "New Service" \
--field username=admin \
--field password=secret123
# Sign in (creates session)
op signin
# Verify access
op vault list
# Create project env file
cat > .op.env << 'EOF'
# Infrastructure secrets
AWS_ACCESS_KEY_ID=op://Infrastructure/AWS/access_key_id
AWS_SECRET_ACCESS_KEY=op://Infrastructure/AWS/secret_access_key
# Application secrets
DATABASE_URL=op://Production/Database/url
REDIS_URL=op://Production/Redis/url
EOF
# Test secret loading
op run --env-file=.op.env -- env | grep -E '^(AWS|DATABASE|REDIS)'
Recommended vault structure:
| Vault | Purpose | Access |
|---|---|---|
Infrastructure | Cloud provider credentials | DevOps team |
Production | Production app secrets | Deploy systems |
Staging | Staging environment | Dev team |
Development | Local dev secrets | Individual devs |
Shared | Cross-team API keys | All teams |
.op.env files for project-specific secret mapping.op.env variants to .gitignore.op.env filesop read output in logs or echo statements# Check recent access events
op events-api
# Specific vault events
op audit-events list --vault Production
# Re-authenticate
op signin
# Check current session
op whoami
# Verify vault access
op vault list
# Search for item
op item list --vault Infrastructure | grep -i aws
# Check exact field names
op item get "AWS" --vault Infrastructure --format json | jq '.fields[].label'
# Check account permissions
op vault list
# Verify specific vault access
op vault get Infrastructure
Many users have separate personal and work 1Password accounts. The CLI supports switching between them.
op account list
Output:
USER ID URL
----------------------------- --------------------------
A3BCDEFGHIJKLMNOPQRSTUVWX my.1password.com
B4CDEFGHIJKLMNOPQRSTUVWXY acme.1password.com
Use --account with either the sign-in address or account ID:
# Using sign-in address
op vault list --account my.1password.com
op item get "AWS" --account acme.1password.com
# Using account ID
op vault list --account A3BCDEFGHIJKLMNOPQRSTUVWX
Set OP_ACCOUNT to choose default for all commands in that shell:
export OP_ACCOUNT=acme.1password.com
op vault list # Uses acme.1password.com
op item get "API Key" # Uses acme.1password.com
--account flag overrides OP_ACCOUNT for a single command.
# Specify account explicitly
op run --account acme.1password.com --env-file=.op.env.work -- ./deploy.sh
# Or set environment variable first
export OP_ACCOUNT=my.1password.com
op run --env-file=.op.env.personal -- ./start-local-dev.sh
When scripts need secrets from different accounts:
# Script using work account
export OP_ACCOUNT=acme.1password.com
WORK_DB=$(op read "op://Production/Database/url")
# Switch to personal for specific command
PERSONAL_KEY=$(op read "op://Personal/GitHub/token" --account my.1password.com)
# Default to work account
OP_ACCOUNT ?= acme.1password.com
OP ?= op
OP_ENV_FILE ?= .op.env
CMD = OP_ACCOUNT=$(OP_ACCOUNT) $(OP) run --env-file=$(OP_ENV_FILE) --
deploy:
$(CMD) kamal deploy
# Personal account for local dev
dev:
OP_ACCOUNT=my.1password.com $(OP) run --env-file=.op.env.personal -- rails server
# Usage:
# make deploy # Uses work account
# make deploy OP_ACCOUNT=my.1password.com # Override account
# make dev # Uses personal account
DO:
--account or OP_ACCOUNT in scripts (don't rely on "last signed in").op.env files per account contextDON'T:
# .op.env.work (uses work account vaults)
AWS_ACCESS_KEY_ID=op://Work-Infrastructure/AWS/access_key_id
DATABASE_URL=op://Work-Production/Database/url
# .op.env.personal (uses personal account vaults)
GITHUB_TOKEN=op://Personal/GitHub/token
OPENAI_API_KEY=op://Personal/OpenAI/api_key
# Makefile with account + env file pairing
work-deploy:
op run --account acme.1password.com --env-file=.op.env.work -- ./deploy.sh
personal-dev:
op run --account my.1password.com --env-file=.op.env.personal -- ./dev.sh
# .op.env.production
DATABASE_URL=op://Production/Database/url
REDIS_URL=op://Production/Redis/url
# .op.env.staging
DATABASE_URL=op://Staging/Database/url
REDIS_URL=op://Staging/Redis/url
# .op.env.development
DATABASE_URL=op://Development/Database/url
REDIS_URL=op://Development/Redis/url
ENV ?= development
OP_ENV_FILE = .op.env.$(ENV)
deploy:
op run --env-file=$(OP_ENV_FILE) -- kamal deploy
# Usage: make deploy ENV=production