A collection of scripts to manage credentials in Cloudflare Secrets Store, providing a secure, centralized location for storing sensitive information that can be reused across your Cloudflare account.
This project provides a simple, secure way to upload and manage credentials from .env files into Cloudflare Secrets Store. All secrets are encrypted and stored across all Cloudflare data centers, and can be easily accessed by Cloudflare Workers and other Cloudflare services.
Single Store Approach: We use one Secrets Store with clear, searchable naming conventions that match your credential template structure. This keeps it simple for developers who need to find keys quickly.
Naming Convention:
- Preserves original variable names from your template (e.g.,
TWILIO_ACCOUNT_SID,GOOGLE_CLIENT_ID) - All names are uppercase (matching .env convention)
- No spaces (Cloudflare requirement)
- Service categories are added as comments for discoverability in the dashboard
- Cloudflare Account: You need a Cloudflare account with appropriate permissions
- Wrangler CLI:
npx wranglershould be installed and you should be logged in - Permissions: You need one of the following roles:
- Super Administrator
- Secrets Store Admin (for creating/managing secrets)
- Secrets Store Deployer (for using secrets in Workers)
To verify you're logged in:
npx wrangler whoami- Clone or download this repository
- Make scripts executable (already done if you cloned):
chmod +x *.sh
First, verify or create a Secrets Store:
./setup-store.shThis will:
- Check if a store already exists
- Create a new store named "main-credentials-store" if none exists
- Display the store ID for reference
Upload credentials from a .env file:
./upload-secrets.sh ~/path/to/your/credentials.envPreview before uploading (dry run):
./upload-secrets.sh ~/path/to/your/credentials.env --dry-runView all secrets in your store (names and metadata only, no values):
./list-secrets.shSearch secrets by key name or comments:
./search-secrets.sh "SMS Bot"
./search-secrets.sh "SMS,Bot" # multi-term search (OR)Quickly retrieve your store ID:
./get-store-id.shInitializes or verifies that a Cloudflare Secrets Store exists.
Usage:
./setup-store.shWhat it does:
- Checks for existing stores
- Creates "main-credentials-store" if none exists
- Displays store information
Uploads credentials from a .env file to Cloudflare Secrets Store.
Usage:
./upload-secrets.sh <path-to-env-file> [options]Options:
--dry-run: Preview what would be uploaded without actually uploading--store-id <id>: Specify the store ID (auto-detected if not provided)--scopes <scopes>: Comma-separated list of scopes (default:workers)--help, -h: Show help message
Examples:
# Basic upload
./upload-secrets.sh ~/vibe-projects/auths/credentials.env
# Dry run to preview
./upload-secrets.sh ~/vibe-projects/auths/credentials.env --dry-run
# Specify store ID
./upload-secrets.sh ~/vibe-projects/auths/credentials.env --store-id 5513cdcc269747bfaa2aef83958f61bfFeatures:
- Automatically detects service categories from key names
- Skips empty values and comments
- Never exposes secret values in output
- Handles existing secrets gracefully (skips duplicates)
- Shows progress and summary statistics
- Supports all standard .env file formats
Service Category Mapping: The script automatically categorizes secrets based on key prefixes:
TWILIO_*,HW_*,TEST_*→ "Twilio"TELNYX_*→ "Telnyx"GOOGLE_*→ "Google"AWS_*,SES_*→ "AWS"CF_*,CLOUDFLARE_*→ "Cloudflare"OPENAI_*,ANTHROPIC_*,GEMINI_*, etc. → "AI Services"- And many more...
Lists all secrets in the store (names and metadata only, no values).
Usage:
./list-secrets.sh [--store-id <id>]Options:
--store-id <id>: Specify the store ID (auto-detected if not provided)--help, -h: Show help message
Lists secrets in a parseable NAME|COMMENT format with a total count.
Usage:
./list-all-secrets.sh [--store-id <id>]Search for secrets by key name or metadata (comments).
Usage:
./search-secrets.sh <search-term> [options]Options:
--store-id <id>: Specify the store ID (auto-detected if not provided)--case-sensitive, -c: Case-sensitive search (default: case-insensitive)--exact, -e: Exact match only (default: partial match)--help, -h: Show help message
Examples:
# Find all secrets with 'twilio' in name or comments
./search-secrets.sh twilio
# Search for phrase 'API key'
./search-secrets.sh 'API key'
# Exact match for 'GOOGLE'
./search-secrets.sh GOOGLE --exact
# Case-sensitive search for 'test'
./search-secrets.sh test --case-sensitiveFeatures:
- Searches both key names and metadata/comments
- Case-insensitive by default (can be made case-sensitive)
- Partial match by default (can use exact match)
- Returns a clean list of matching secret names
- Handles empty stores gracefully
Lists all secrets and identifies duplicate names.
Usage:
./find-duplicates.sh [--store-id <id>]Deletes secrets whose comments match a pattern. Dry-run by default.
Usage:
# dry run
./delete-secrets-by-comment.sh --pattern "Python Environment | LOCAL DEV"
# execute deletes
./delete-secrets-by-comment.sh --pattern "Python Environment | LOCAL DEV" --executeQuick utility to retrieve and display the Secrets Store ID.
Usage:
./get-store-id.shWhat it does:
- Lists all stores
- Displays the first store's name and ID
- Copies the ID to clipboard (macOS) if possible
Once secrets are uploaded, you can use them in your Cloudflare Workers:
Add a Secrets Store binding to your wrangler.toml:
secrets_store_secrets = [
{
binding = "TWILIO_AUTH_TOKEN",
store_id = "5513cdcc269747bfaa2aef83958f61bf",
secret_name = "TWILIO_AUTH_TOKEN"
},
{
binding = "GOOGLE_CLIENT_ID",
store_id = "5513cdcc269747bfaa2aef83958f61bf",
secret_name = "GOOGLE_CLIENT_ID"
}
]Or via the Dashboard:
- Go to Workers & Pages → Your Worker → Settings → Bindings
- Click Add → Select Secrets Store
- Choose your secret from the dropdown
export default {
async fetch(request, env) {
// Access the secret asynchronously
const twilioAuthToken = await env.TWILIO_AUTH_TOKEN.get();
const googleClientId = await env.GOOGLE_CLIENT_ID.get();
// Use the secrets in your code
const response = await fetch("https://api.twilio.com/...", {
headers: {
"Authorization": `Basic ${twilioAuthToken}`
}
});
return response;
}
}-
Never Commit Secrets: Keep your
.envfiles out of version control- Add
.envand*.envto your.gitignore - Use
.env.examplefiles with placeholder values
- Add
-
Shell History: The
upload-secrets.shscript uses the--valueflag which may appear in shell history. Consider:- Using
set +o historybefore running (remember toset -o historyafter) - Clearing history after sensitive operations:
history -c - Using a dedicated script execution environment
- Using
-
Access Control:
- Only grant Secrets Store Admin role to trusted team members
- Use Secrets Store Deployer role for developers who only need to use secrets
-
Regular Audits:
- Periodically review secrets using
./list-secrets.sh - Remove unused or outdated secrets
- Rotate secrets regularly
- Periodically review secrets using
-
Dry Run First: Always use
--dry-runto preview changes before uploading
If you see this error, run:
./setup-store.shYou need one of these roles:
- Super Administrator
- Secrets Store Admin
Check your permissions in the Cloudflare Dashboard under My Profile → Memberships.
This is normal if you're re-running the upload script. The script will skip existing secrets. To update a secret, you'll need to use the Cloudflare Dashboard or API directly.
If wrangler commands fail with authentication errors:
npx wrangler loginIf auto-detection fails, manually specify the store ID:
./get-store-id.sh # Get the ID
./upload-secrets.sh your-file.env --store-id <your-store-id>CloudFlare Secrets Manager/
├── README.md # This file
├── setup-store.sh # Initial store setup
├── upload-secrets.sh # Main upload script
├── list-secrets.sh # List all secrets
├── list-all-secrets.sh # Parseable list with count
├── search-secrets.sh # Search secrets by name or metadata
├── find-duplicates.sh # Identify duplicate secret names
├── delete-secrets-by-comment.sh # Delete by comment pattern (dry-run default)
└── get-store-id.sh # Get store ID utility
The upload script automatically categorizes secrets. Here are the main categories:
- Twilio: Twilio account credentials
- Telnyx: Telnyx messaging service
- Google: Google OAuth, Service Accounts, Maps API
- AWS: AWS SES and other AWS services
- Cloudflare: Cloudflare API tokens
- AI Services: OpenAI, Anthropic, Gemini, Perplexity, etc.
- PostgreSQL: Database credentials
- SMTP: Email service credentials
- Discord: Discord bot and webhook credentials
- And many more...
- Secret values cannot be retrieved after upload (Cloudflare security feature)
- Secret names cannot contain spaces
- Updating secrets requires using the Dashboard or API directly
- The
--valueflag may appear in shell history (see Security Best Practices)
Potential improvements (not currently implemented):
- Support for updating existing secrets
- Support for deleting secrets
- Multiple store support
- Environment-specific stores (dev/staging/prod)
- Integration with CI/CD pipelines
- Secret rotation automation
- Cloudflare Secrets Store Documentation
- Workers Integration Guide
- Wrangler Commands Reference
- Cloudflare Secrets Store API
For issues with:
- These scripts: Check the troubleshooting section above
- Cloudflare Secrets Store: See Cloudflare Support
- Wrangler CLI: See Workers SDK Issues
Note: This is an open beta feature. Please report any issues to the Cloudflare Workers SDK repository.