Migrate from .env Files
Move your credentials out of flat files and into a purpose-built secret vault — with encryption, audit trails, and scoped access control.
Why .env files are dangerous for production agents
⚠ Git accidents
.env files get committed accidentally despite .gitignore — it happens to everyone, including security teams.
⚠ No access control
Any code running on the host can read all environment variables — your database password and your LLM key share the same flat namespace.
⚠ No audit trail
You have no idea which agents accessed which credentials, or when. Forensics after a breach is impossible.
⚠ Rotation pain
Rotating a key means updating .env on every server, restarting containers, and hoping nothing missed the update.
⚠ Plaintext at rest
.env files are plaintext. If your host is compromised, all credentials are immediately exposed.
⚠ Copy-paste culture
Devs copy production keys to local .env files "just for testing" — now they're on 12 laptops.
Starting point — your existing .env
# .env (what you have today)
OPENAI_API_KEY=sk-proj-abc123...
STRIPE_SECRET_KEY=sk_live_xyz789...
SLACK_BOT_TOKEN=xoxb-123456-...
DATABASE_URL=postgresql://user:pass@host:5432/db
ANTHROPIC_API_KEY=sk-ant-...
SENDGRID_API_KEY=SG.abc...Migration steps
- 1
Create an Agent Secret Store account
Sign up at agentsecretstore.com/signup and copy your agent key from the dashboard.
- 2
Install the SDK and set your key
Shellpip install agentsecretstore export ASS_AGENT_KEY="ass_live_your_key_here" - 3
Bulk import your .env file
Use the import script below to read your .env and create all secrets in the vault. Run with
--dry-runfirst to preview:import_env.py#!/usr/bin/env python3 """ import_env.py — Bulk import a .env file into Agent Secret Store Usage: python import_env.py --env-file .env --namespace production --tier sensitive """ import argparse import asyncio import os import re from pathlib import Path from agentsecretstore import AgentVault from agentsecretstore.exceptions import AgentVaultError def parse_env_file(path: Path) -> dict[str, str]: """Parse a .env file into a dict of key=value pairs.""" secrets: dict[str, str] = {} pattern = re.compile(r'^([A-Za-z_][A-Za-z0-9_]*)=(.*)$') for line in path.read_text().splitlines(): line = line.strip() if not line or line.startswith('#'): continue m = pattern.match(line) if m: key, value = m.groups() # Strip surrounding quotes if present value = value.strip('"').strip("'") secrets[key] = value return secrets async def import_secrets( env_file: Path, namespace: str, tier: str, dry_run: bool, ) -> None: secrets = parse_env_file(env_file) print(f"Found {len(secrets)} secrets in {env_file}") if dry_run: for key, value in secrets.items(): path = f"{namespace}/{key.lower().replace('_', '-')}" print(f" [DRY RUN] Would import: {path} = {value[:4]}...") return async with AgentVault() as vault: for key, value in secrets.items(): # Convert ENV_VAR_NAME to namespace/env-var-name secret_name = key.lower().replace('_', '-') path = f"{namespace}/{secret_name}" try: await vault.set_secret( path=path, value=value, tier=tier, description=f"Imported from .env: {key}", tags={"source": "env-import", "original_key": key}, ) print(f" ✓ Imported: {path}") except AgentVaultError as e: print(f" ✗ Failed to import {path}: {e}") if __name__ == "__main__": parser = argparse.ArgumentParser(description="Import .env into Agent Secret Store") parser.add_argument("--env-file", default=".env", help="Path to .env file") parser.add_argument("--namespace", required=True, help="Target namespace (e.g. 'production')") parser.add_argument("--tier", default="sensitive", choices=["standard", "sensitive", "critical"]) parser.add_argument("--dry-run", action="store_true", help="Preview without writing") args = parser.parse_args() asyncio.run(import_secrets( env_file=Path(args.env_file), namespace=args.namespace, tier=args.tier, dry_run=args.dry_run, ))Shell# Preview what will be imported (no writes) python import_env.py --env-file .env --namespace production --dry-run # Import for real ASS_AGENT_KEY=ass_live_your_key_here \ python import_env.py --env-file .env --namespace production --tier sensitive # Output: # Found 6 secrets in .env # ✓ Imported: production/openai-api-key # ✓ Imported: production/stripe-secret-key # ✓ Imported: production/slack-bot-token # ✓ Imported: production/database-url # ✓ Imported: production/anthropic-api-key # ✓ Imported: production/sendgrid-api-key - 4
Update your agent code
Python
credentials.py# BEFORE — reading from .env / environment import os openai_key = os.environ["OPENAI_API_KEY"] stripe_key = os.environ["STRIPE_SECRET_KEY"] # AFTER — reading from vault import asyncio from agentsecretstore import AgentVault async def load_credentials() -> dict[str, str]: async with AgentVault() as vault: openai = await vault.get_secret("production/openai-api-key") stripe = await vault.get_secret("production/stripe-secret-key") return { "openai_key": openai.value, "stripe_key": stripe.value, } # Or use a helper for simpler access async def get(path: str) -> str: async with AgentVault() as vault: return (await vault.get_secret(path)).valueJavaScript / TypeScript
credentials.ts// BEFORE — reading from process.env const openaiKey = process.env.OPENAI_API_KEY!; const stripeKey = process.env.STRIPE_SECRET_KEY!; // AFTER — reading from vault import { AgentVault } from '@agentsecretstore/sdk'; const vault = new AgentVault(); async function loadCredentials() { const [openai, stripe] = await Promise.all([ vault.getSecret('production/openai-api-key'), vault.getSecret('production/stripe-secret-key'), ]); return { openaiKey: openai.value, stripeKey: stripe.value, }; } - 5
Update CI/CD
Instead of storing 20 secrets in GitHub Actions (or your CI/CD provider), store only
ASS_AGENT_KEY— all other secrets are fetched at runtime..github/workflows/deploy.yml# GitHub Actions — before (secrets in repo settings) env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} STRIPE_SECRET_KEY: ${{ secrets.STRIPE_SECRET_KEY }} # GitHub Actions — after (only vault key needed) env: ASS_AGENT_KEY: ${{ secrets.ASS_AGENT_KEY }} # All other secrets fetched from vault at runtime - 6
Delete your .env files
Don't skip this step
Once your code is updated and tested against the vault, delete all .env files and remove them from .gitignore. If they're already committed to git history, use
git filter-repoor BFG Repo Cleaner to purge them from history, then rotate all the affected secrets.
Secret Rotation →
Set up automatic rotation schedules.
Python SDK Reference →
Complete SDK documentation.