Secure API Key Management with 1Password CLI


We’ve all been there - storing API keys directly in our .zshrc, .bashrc, or .bash_profile files for easy access. While convenient, this approach has serious security implications. Your API keys are stored in plaintext, visible to anyone with access to your shell configuration, and at risk of being accidentally committed to version control.

The Problem with Plaintext Storage

The traditional approach looks like this in your .zshrc:

export GEMINI_API_KEY="your-secret-api-key-here"
export OPENAI_API_KEY="another-secret-key"
export AWS_ACCESS_KEY_ID="yet-another-key"

This creates several security risks:

  • Plaintext exposure: Keys are readable by any process or user with access to your shell files
  • Version control leaks: Easy to accidentally commit these files with sensitive data
  • System-wide access: Any application can read these environment variables
  • No audit trail: No way to track when or how these keys are accessed

Enter 1Password CLI

1Password CLI (op) provides a secure way to store and retrieve sensitive information like API keys. Instead of storing keys in plaintext, we can store them securely in 1Password and retrieve them dynamically when needed.

Setup

First, install the 1Password CLI if you haven’t already:

# macOS with Homebrew
brew install --cask 1password-cli

# Or download from https://1password.com/downloads/command-line/

Next, authenticate with your 1Password account:

op account add
op signin

Storing API Keys in 1Password

Create a new item in 1Password for your API key. You can do this through the 1Password app or CLI:

# Create a new item with your API key
op item create --category="API Credential" \
  --title="Gemini CLI" \
  --field="password=your-actual-api-key-here"

Dynamic Key Retrieval

Now, instead of hardcoding the key in your .zshrc, use the 1Password CLI to retrieve it dynamically:

# In your .zshrc file
export GEMINI_API_KEY=$(op item get 'Gemini CLI' --fields password --reveal)

The --reveal flag ensures that the password field is displayed in plaintext for use as an environment variable.

Complete Shell Configuration

Here’s how your .zshrc might look with multiple API keys managed securely:

# Secure API key management with 1Password CLI
export GEMINI_API_KEY=$(op item get 'Gemini CLI' --fields password --reveal)
export OPENAI_API_KEY=$(op item get 'OpenAI API' --fields password --reveal)
export AWS_ACCESS_KEY_ID=$(op item get 'AWS Credentials' --fields username --reveal)
export AWS_SECRET_ACCESS_KEY=$(op item get 'AWS Credentials' --fields password --reveal)

Benefits

This approach provides several advantages:

  • Encrypted storage: Keys are stored encrypted in 1Password’s secure vault
  • Audit trail: 1Password tracks access to your items
  • Centralized management: Manage all credentials from one secure location
  • Easy rotation: Update keys in 1Password without touching shell configuration
  • Safe version control: Your .zshrc can be safely committed without exposing secrets

Performance Considerations

You might wonder about the performance impact of calling op for each key. In practice, the CLI is quite fast, but if you’re concerned about startup time, you could implement caching:

# Cache keys for the session
if [[ -z "$GEMINI_API_KEY" ]]; then
    export GEMINI_API_KEY=$(op item get 'Gemini CLI' --fields password --reveal)
fi

Alternative: Session Management

For even better security, you can use 1Password’s session management to avoid keeping long-running authenticated sessions:

# Sign in and export session token
export OP_SESSION_my_account=$(op signin my_account --raw)

# Use the session token for subsequent calls
export GEMINI_API_KEY=$(op item get 'Gemini CLI' --fields password --reveal --session="$OP_SESSION_my_account")

Conclusion

By leveraging 1Password CLI, we can maintain the convenience of environment variables while significantly improving our security posture. Your API keys remain encrypted at rest, access is audited, and you eliminate the risk of accidentally exposing secrets in version control.

The small performance overhead is a worthwhile trade-off for the security benefits, and your future self will thank you for taking the extra step to protect your valuable API credentials.