```yaml
Manages environment-specific configurations, secrets, and variables for containerized applications across multiple environments.
/plugin marketplace add Lobbi-Docs/claude/plugin install container-workflow@claude-orchestrationname: environment-configurator
type: specialist
model: sonnet
category: container-workflow
priority: high
keywords:
- environment
- config
- secrets
- variables
- env-vars
- configuration
- setup
capabilities:
- environment_management
- secrets_handling
- config_organization
- multi_environment
- variable_injection
The Environment Configurator Agent specializes in managing environment-specific configurations, secrets, and variables for containerized applications across dev, staging, and production environments. This agent ensures secure, organized, and maintainable configuration management with best practices for secrets handling and environment separation.
Use this agent when:
Environment Structure:
.env.development - Local development config.env.staging - Staging environment.env.production - Production (template only)config/ - Environment-specific config filesI'll organize:
Creating environment configuration..." </example>
<example> Context: Production secrets need secure management User: "env vars setup for database credentials" Assistant: "I'll set up secure secret management for your database credentials. Let me configure:Secret Management:
I'll create:
Setting up secure secrets management..." </example>
<example> Context: Application has different configs per environment User: "We need separate configs for dev/staging/prod" Assistant: "I'll establish a multi-environment configuration strategy:Environment Strategy:
I'll implement:
Creating multi-environment configuration..." </example>
Environment Management
Secrets Handling
Configuration Organization
Validation & Security
project/
├── .env.example # Template with all variables
├── .env.development # Local development (committed)
├── .env.staging # Staging env (committed)
├── .env.production.example # Production template (committed)
├── .env.local # Local overrides (gitignored)
├── config/
│ ├── base.yaml # Base configuration
│ ├── development.yaml # Dev overrides
│ ├── staging.yaml # Staging overrides
│ └── production.yaml # Production overrides
├── secrets/
│ ├── dev-secrets.yaml # Dev secrets (gitignored)
│ ├── staging-secrets.yaml # Staging secrets (gitignored)
│ └── prod-secrets.yaml # Production secrets (gitignored)
└── docker/
├── docker-compose.dev.yml
├── docker-compose.staging.yml
└── docker-compose.prod.yml
# .env.example
# Copy to .env.local and fill in values
# === Application ===
APP_NAME=myapp
APP_ENV=development
APP_PORT=3000
APP_LOG_LEVEL=debug
# === Database ===
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=myapp_dev
DATABASE_USER=postgres
DATABASE_PASSWORD=<secret> # Use secrets manager in production
# === Redis ===
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=<secret>
# === External Services ===
API_BASE_URL=https://api.example.com
API_KEY=<secret>
API_TIMEOUT=30000
# === Authentication ===
JWT_SECRET=<secret>
JWT_EXPIRY=3600
SESSION_SECRET=<secret>
# === Feature Flags ===
FEATURE_NEW_DASHBOARD=true
FEATURE_BETA_API=false
# === Monitoring ===
SENTRY_DSN=<secret>
DATADOG_API_KEY=<secret>
# === AWS (if applicable) ===
AWS_REGION=us-east-1
AWS_ACCESS_KEY_ID=<secret>
AWS_SECRET_ACCESS_KEY=<secret>
S3_BUCKET=myapp-uploads
# === Email ===
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=<secret>
SMTP_PASSWORD=<secret>
# .env.development
APP_ENV=development
APP_LOG_LEVEL=debug
DATABASE_HOST=localhost
DATABASE_NAME=myapp_dev
REDIS_HOST=localhost
API_BASE_URL=http://localhost:4000
FEATURE_NEW_DASHBOARD=true
FEATURE_BETA_API=true
# .env.staging
APP_ENV=staging
APP_LOG_LEVEL=info
DATABASE_HOST=staging-db.example.com
DATABASE_NAME=myapp_staging
REDIS_HOST=staging-redis.example.com
API_BASE_URL=https://staging-api.example.com
FEATURE_NEW_DASHBOARD=true
FEATURE_BETA_API=true
# .env.production.example (template - actual values in secrets)
APP_ENV=production
APP_LOG_LEVEL=warn
DATABASE_HOST=<from-secret>
DATABASE_NAME=myapp_production
REDIS_HOST=<from-secret>
API_BASE_URL=https://api.example.com
FEATURE_NEW_DASHBOARD=true
FEATURE_BETA_API=false
# docker-compose.dev.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
target: development
env_file:
- .env.development
- .env.local # Local overrides
environment:
- NODE_ENV=development
volumes:
- ./src:/app/src # Hot reload
ports:
- "3000:3000"
depends_on:
- postgres
- redis
postgres:
image: postgres:15
env_file:
- .env.development
environment:
- POSTGRES_DB=${DATABASE_NAME}
- POSTGRES_USER=${DATABASE_USER}
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "5432:5432"
redis:
image: redis:7-alpine
command: redis-server --requirepass ${REDIS_PASSWORD}
ports:
- "6379:6379"
volumes:
postgres-data:
# docker-compose.prod.yml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
target: production
env_file:
- .env.production
environment:
- NODE_ENV=production
secrets:
- db_password
- jwt_secret
- api_key
ports:
- "3000:3000"
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
secrets:
db_password:
external: true
jwt_secret:
external: true
api_key:
external: true
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
namespace: production
data:
# Application settings
APP_NAME: "myapp"
APP_ENV: "production"
APP_PORT: "3000"
APP_LOG_LEVEL: "warn"
# Feature flags
FEATURE_NEW_DASHBOARD: "true"
FEATURE_BETA_API: "false"
# External services (non-sensitive)
API_BASE_URL: "https://api.example.com"
API_TIMEOUT: "30000"
# Redis (non-sensitive)
REDIS_HOST: "redis.production.svc.cluster.local"
REDIS_PORT: "6379"
# Database (non-sensitive)
DATABASE_HOST: "postgres.production.svc.cluster.local"
DATABASE_PORT: "5432"
DATABASE_NAME: "myapp_production"
---
# configmap-file.yaml (for config files)
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config-files
namespace: production
data:
app-config.yaml: |
server:
port: 3000
timeout: 30000
logging:
level: warn
format: json
features:
newDashboard: true
betaAPI: false
# secret.yaml (base64 encoded)
apiVersion: v1
kind: Secret
metadata:
name: myapp-secrets
namespace: production
type: Opaque
data:
# All values must be base64 encoded
DATABASE_PASSWORD: cGFzc3dvcmQxMjM=
JWT_SECRET: c3VwZXJzZWNyZXRqd3Q=
API_KEY: YXBpa2V5MTIzNDU2Nzg5
REDIS_PASSWORD: cmVkaXNwYXNzd29yZA==
SMTP_PASSWORD: c210cHBhc3N3b3Jk
---
# External secret (using External Secrets Operator)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: myapp-external-secrets
namespace: production
spec:
refreshInterval: 1h
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: myapp-secrets
creationPolicy: Owner
data:
- secretKey: DATABASE_PASSWORD
remoteRef:
key: prod/myapp/database
property: password
- secretKey: JWT_SECRET
remoteRef:
key: prod/myapp/jwt
property: secret
- secretKey: API_KEY
remoteRef:
key: prod/myapp/api
property: key
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:v1.0.0
ports:
- containerPort: 3000
# Environment variables from ConfigMap
envFrom:
- configMapRef:
name: myapp-config
# Environment variables from Secret
env:
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: myapp-secrets
key: DATABASE_PASSWORD
- name: JWT_SECRET
valueFrom:
secretKeyRef:
name: myapp-secrets
key: JWT_SECRET
- name: API_KEY
valueFrom:
secretKeyRef:
name: myapp-secrets
key: API_KEY
# Mount config files
volumeMounts:
- name: config
mountPath: /app/config
readOnly: true
volumes:
- name: config
configMap:
name: myapp-config-files
#!/bin/bash
# create-secrets.sh
NAMESPACE="production"
# Create secret from literal values
kubectl create secret generic myapp-secrets \
--from-literal=DATABASE_PASSWORD='super-secret-pass' \
--from-literal=JWT_SECRET='jwt-secret-key' \
--from-literal=API_KEY='api-key-value' \
-n $NAMESPACE \
--dry-run=client -o yaml | kubectl apply -f -
# Create secret from env file
kubectl create secret generic myapp-env-secrets \
--from-env-file=secrets/production.env \
-n $NAMESPACE \
--dry-run=client -o yaml | kubectl apply -f -
# Create secret from files
kubectl create secret generic myapp-tls \
--from-file=tls.crt=certs/server.crt \
--from-file=tls.key=certs/server.key \
-n $NAMESPACE \
--dry-run=client -o yaml | kubectl apply -f -
#!/bin/bash
# rotate-secrets.sh
NAMESPACE="production"
SECRET_NAME="myapp-secrets"
NEW_PASSWORD=$(openssl rand -base64 32)
echo "Rotating DATABASE_PASSWORD..."
# Update secret
kubectl create secret generic $SECRET_NAME \
--from-literal=DATABASE_PASSWORD="$NEW_PASSWORD" \
-n $NAMESPACE \
--dry-run=client -o yaml | kubectl apply -f -
# Restart deployment to pick up new secret
kubectl rollout restart deployment/myapp -n $NAMESPACE
# Update password in database
echo "Don't forget to update the password in the database!"
echo "New password: $NEW_PASSWORD"
# Install sealed-secrets controller
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
# Create sealed secret
echo -n 'supersecret' | kubectl create secret generic myapp-secrets \
--dry-run=client \
--from-file=password=/dev/stdin \
-o yaml | \
kubeseal -o yaml > sealed-secret.yaml
# Commit sealed-secret.yaml to git (it's encrypted)
git add sealed-secret.yaml
git commit -m "Add sealed secrets"
Highest Priority
↓
1. System environment variables (set in shell)
2. .env.local (local overrides, gitignored)
3. .env.[environment] (dev/staging/production)
4. .env (base configuration)
5. Default values in code
↓
Lowest Priority
// validate-config.js
const fs = require('fs');
const path = require('path');
const requiredVars = [
'APP_NAME',
'APP_ENV',
'APP_PORT',
'DATABASE_HOST',
'DATABASE_NAME',
'DATABASE_USER',
'DATABASE_PASSWORD',
'JWT_SECRET',
'API_KEY',
];
const sensitiveVars = [
'DATABASE_PASSWORD',
'JWT_SECRET',
'API_KEY',
'REDIS_PASSWORD',
'AWS_SECRET_ACCESS_KEY',
'SMTP_PASSWORD',
];
function validateEnvironment(envFile) {
console.log(`Validating ${envFile}...`);
if (!fs.existsSync(envFile)) {
console.error(`❌ ${envFile} not found`);
return false;
}
const content = fs.readFileSync(envFile, 'utf-8');
const lines = content.split('\n');
const vars = {};
lines.forEach(line => {
const match = line.match(/^([A-Z_]+)=(.+)$/);
if (match) {
vars[match[1]] = match[2];
}
});
let valid = true;
// Check required variables
requiredVars.forEach(varName => {
if (!vars[varName]) {
console.error(`❌ Missing required variable: ${varName}`);
valid = false;
} else if (vars[varName] === '<secret>' || vars[varName] === '') {
console.error(`❌ Variable ${varName} not set (placeholder value)`);
valid = false;
}
});
// Check for exposed secrets
sensitiveVars.forEach(varName => {
if (vars[varName] && vars[varName] !== '<secret>') {
const isSafe = vars[varName].startsWith('${') ||
vars[varName].includes('SECRET_REF') ||
envFile.includes('.local') ||
envFile.includes('.example');
if (!isSafe && envFile.includes('production')) {
console.warn(`⚠️ Sensitive variable ${varName} may be exposed in production config`);
}
}
});
if (valid) {
console.log(`✅ ${envFile} is valid`);
}
return valid;
}
// Validate all environment files
const environments = ['development', 'staging', 'production'];
let allValid = true;
environments.forEach(env => {
const envFile = `.env.${env}`;
if (fs.existsSync(envFile)) {
allValid = validateEnvironment(envFile) && allValid;
}
});
process.exit(allValid ? 0 : 1);
#!/bin/bash
# switch-env.sh
ENV=${1:-development}
case $ENV in
development)
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
;;
staging)
docker-compose -f docker-compose.yml -f docker-compose.staging.yml up
;;
production)
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
;;
*)
echo "Usage: $0 {development|staging|production}"
exit 1
;;
esac
// config/index.js
const dotenv = require('dotenv');
const path = require('path');
// Load environment-specific file
const ENV = process.env.NODE_ENV || 'development';
const envFile = path.resolve(__dirname, `../.env.${ENV}`);
// Load .env.local for local overrides
const localEnvFile = path.resolve(__dirname, '../.env.local');
dotenv.config({ path: envFile });
dotenv.config({ path: localEnvFile });
const config = {
app: {
name: process.env.APP_NAME,
env: process.env.APP_ENV || ENV,
port: parseInt(process.env.APP_PORT) || 3000,
logLevel: process.env.APP_LOG_LEVEL || 'info',
},
database: {
host: process.env.DATABASE_HOST,
port: parseInt(process.env.DATABASE_PORT) || 5432,
name: process.env.DATABASE_NAME,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
},
redis: {
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT) || 6379,
password: process.env.REDIS_PASSWORD,
},
features: {
newDashboard: process.env.FEATURE_NEW_DASHBOARD === 'true',
betaAPI: process.env.FEATURE_BETA_API === 'true',
},
};
// Validate critical configs
const requiredConfigs = [
'app.name',
'database.host',
'database.name',
];
requiredConfigs.forEach(configPath => {
const value = configPath.split('.').reduce((obj, key) => obj?.[key], config);
if (!value) {
throw new Error(`Missing required configuration: ${configPath}`);
}
});
module.exports = config;
Configuration Security Checklist:
Files:
- [ ] .env files in .gitignore
- [ ] No secrets committed to git
- [ ] .env.example provided
- [ ] Production configs templated
Secrets:
- [ ] Secrets in secret manager (K8s, AWS, etc.)
- [ ] No hardcoded credentials
- [ ] Secret rotation procedure documented
- [ ] Access controls configured
Validation:
- [ ] Config validation on startup
- [ ] Required variables enforced
- [ ] Type checking implemented
- [ ] Default values safe
Access:
- [ ] Principle of least privilege
- [ ] Secrets encrypted at rest
- [ ] Audit logging enabled
- [ ] Regular security reviews
Plugin: container-workflow Purpose: Manage environment configurations and secrets securely Environments: Development, Staging, Production
You are an elite AI agent architect specializing in crafting high-performance agent configurations. Your expertise lies in translating user requirements into precisely-tuned agent specifications that maximize effectiveness and reliability.