Runtime Secrets Injection
Keep enables secure runtime injection of secrets into your applications without writing them to disk. This approach is ideal for production environments where you need secrets available to your application processes without persisting them in files.
Overview
The keep run
command executes subprocesses with secrets injected as environment variables, providing a diskless solution for secret management. This is particularly valuable for:
- Build processes that need API keys and tokens
- Application servers requiring database credentials
- CI/CD pipelines with deployment secrets
- Container orchestration where secrets shouldn't be baked into images
How It Works
keep run --vault=<vault> --env=<env> -- <command> [arguments]
Keep fetches secrets from your vault, injects them as environment variables, and executes your command. The secrets exist only in memory for the duration of the process.
Laravel Applications
Laravel requires secrets only once - during configuration caching. After that, all processes use the cached config:
#!/bin/bash
# deploy.sh
# Inject secrets and cache configuration (only injection needed!)
keep run --vault=ssm --env=production -- php artisan config:cache
# All subsequent commands use cached config - no injection required
php artisan migrate --force
php artisan route:cache
php artisan view:cache
php artisan queue:restart
Once cached, Laravel completely ignores environment variables, reading everything from bootstrap/cache/config.php
.
Symfony Applications
Symfony compiles environment variables into the container during cache warmup. After compilation, all commands use the cached container:
# Inject secrets during container compilation (only injection needed!)
keep run --vault=ssm --env=production -- php bin/console cache:warmup --env=prod
# All subsequent commands use compiled container - no injection required
php bin/console doctrine:migrations:migrate --no-interaction
php bin/console messenger:consume async
Once compiled, Symfony reads configuration from var/cache/prod/
and never accesses environment variables.
Node.js Applications
# Build with API keys
keep run --vault=ssm --env=production --only='*_API_KEY,*_TOKEN' -- npm run build
# Start server with all secrets
keep run --vault=ssm --env=production -- node server.js
# Use PM2 process manager
keep run --vault=ssm --env=production -- pm2 start app.js
# Template for specific secrets
keep run --vault=ssm --env=production --template=env/prod.env -- npm start
Your Node.js app reads from environment variables as usual:
const config = {
port: process.env.PORT || 3000,
dbUrl: process.env.DATABASE_URL,
apiKey: process.env.API_KEY
};
Python Applications
# Django migrations
keep run --vault=ssm --env=production -- python manage.py migrate
# Django with Gunicorn
keep run --vault=ssm --env=production -- gunicorn myapp.wsgi:application
# Flask development
keep run --vault=ssm --env=local -- flask run
# Flask production
keep run --vault=ssm --env=production -- gunicorn app:app --bind 0.0.0.0:8000
Docker Integration
# Build with secrets (multi-env recommended)
keep run --vault=ssm --env=production -- docker build \
--build-arg NPM_TOKEN=$NPM_TOKEN -t myapp:latest .
# Run container
keep run --vault=ssm --env=production -- docker run \
-e DATABASE_URL=$DATABASE_URL myapp:latest
# Docker Compose
keep run --vault=ssm --env=production -- docker-compose up
With Docker Compose, environment variables are automatically passed through when listed without values.
Template-Based Injection
# Generate template from existing secrets in env/production.env
keep template:add --env=production
# Auto-discover template (looks for env/{env}.env)
keep run --vault=ssm --env=production --template -- npm start
# Use specific template
keep run --vault=ssm --env=production --template=env/prod.env -- npm start
See Managing Templates for detailed template documentation.
Filtering Secrets
Control which secrets are injected using patterns:
# Only database secrets
keep run --vault=ssm --env=production --only='DB_*,DATABASE_*' -- npm run migrate
# Exclude sensitive keys
keep run --vault=ssm --env=production --except='*_PRIVATE_KEY,*_SECRET' -- npm run build
# Multiple patterns
keep run --vault=ssm --env=production --only='API_*,SERVICE_*' --except='*_TEST' -- npm start
CI/CD Integration
# GitHub Actions
- name: Build and Deploy
run: |
keep run --vault=ssm --env=production -- npm run build
keep run --vault=ssm --env=production -- npm run deploy
# GitLab CI
deploy:
script:
- keep run --vault=ssm --env=$CI_ENVIRONMENT_NAME -- ./deploy.sh
Additional Options
# Clean environment (no inheritance)
keep run --vault=ssm --env=production --no-inherit -- node server.js
# Exit codes are propagated for CI/CD
keep run --vault=ssm --env=production -- npm test || exit 1
Security Notes
- Secrets never touch disk - only exist in process memory
- Process isolation ensures secrets don't leak between processes
- All access is logged in your vault's audit trail
- TTY mode automatically enabled for interactive commands
Common Patterns
# Development
keep run --vault=ssm --env=local --template -- npm run dev
# Production deployment
keep run --vault=ssm --env=production --template --no-inherit -- ./deploy.sh
# Testing with filtered secrets
keep run --vault=ssm --env=test --only='TEST_*,DB_*' -- npm test