| name | fnox-security-best-practices |
| description | Use when implementing secure secrets management with Fnox. Covers encryption, key management, access control, and security hardening. |
| allowed-tools | ["Read","Write","Edit","Bash","Grep","Glob"] |
Fnox - Security Best Practices
Security guidelines and best practices for managing secrets with Fnox.
Encryption Fundamentals
Always Encrypt Sensitive Data
[secrets]
DATABASE_PASSWORD = "super-secret-password"
API_KEY = "sk-live-12345"
[providers.age]
type = "age"
public_keys = ["age1ql3z..."]
[secrets]
DATABASE_PASSWORD = { provider = "age", value = "age[...]" }
API_KEY = { provider = "age", value = "age[...]" }
Use Strong Encryption
age-keygen -o ~/.config/fnox/keys/identity.txt
[providers.kms]
type = "aws-kms"
key_id = "arn:aws:kms:us-east-1:..."
Key Management
Protect Private Keys
chmod 600 ~/.config/fnox/keys/identity.txt
echo "*.txt" >> ~/.config/fnox/keys/.gitignore
Separate Public and Private Keys
[providers.age]
type = "age"
public_keys = ["age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p"]
[providers.age]
identity = "~/.config/fnox/keys/identity.txt"
Rotate Keys Regularly
age-keygen -o ~/.config/fnox/keys/identity-2025.txt
fnox get --all | fnox set --provider age-new
Access Control
Use Least Privilege
[profiles.production]
[profiles.production.providers.prod-secrets]
type = "aws-sm"
region = "us-east-1"
[profiles.production.secrets]
DATABASE_URL = { provider = "prod-secrets", value = "prod/db" }
[profiles.development]
[profiles.development.secrets]
DATABASE_URL = "postgresql://localhost/dev"
Team Access Control
[providers.age]
type = "age"
public_keys = [
"age1ql3z...",
"age1qw4r...",
]
Role-Based Secrets
[providers.backend]
type = "aws-sm"
region = "us-east-1"
[providers.frontend]
type = "aws-sm"
region = "us-east-1"
[secrets]
BACKEND_DB_PASSWORD = { provider = "backend", value = "backend/db-pass" }
FRONTEND_API_ENDPOINT = { provider = "frontend", value = "frontend/api-url" }
Git Security
Never Commit Sensitive Data
# .gitignore
fnox.local.toml
*.age-identity.txt
*.key
*.pem
.env
Audit Git History
git log -p | grep -i "password\|secret\|key"
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch fnox.local.toml' \
--prune-empty --tag-name-filter cat -- --all
Use Pre-Commit Hooks
if git diff --cached --name-only | grep -q "fnox.local.toml"; then
echo "Error: Attempting to commit fnox.local.toml"
exit 1
fi
if git diff --cached | grep -q "password.*=.*\"[^a]"; then
echo "Warning: Possible plain text password detected"
exit 1
fi
Environment Separation
Separate Development and Production
[secrets]
DATABASE_URL = "postgresql://localhost/dev"
DEBUG = "true"
[providers.prod]
type = "aws-sm"
region = "us-east-1"
[secrets]
DATABASE_URL = { provider = "prod", value = "prod/db-url" }
DEBUG = "false"
Use Profiles for Environments
fnox exec -- node app.js
FNOX_PROFILE=staging fnox exec -- node app.js
FNOX_PROFILE=production fnox exec -- node app.js
Cloud Provider Security
AWS Best Practices
[providers.aws-sm]
type = "aws-sm"
region = "us-east-1"
[providers.aws-sm]
type = "aws-sm"
region = "us-east-1"
Azure Best Practices
[providers.azure]
type = "azure-kv"
vault_url = "https://my-vault.vault.azure.net"
GCP Best Practices
[providers.gcp]
type = "gcp-sm"
project_id = "my-project"
Audit and Monitoring
Log Secret Access
Monitor for Anomalies
fnox list
fnox doctor
fnox provider test aws-sm
Regular Security Audits
fnox list
fnox doctor
grep -r "password.*=.*\"[^a]" fnox.toml
Secrets Lifecycle
Rotate Secrets Regularly
NEW_PASSWORD=$(openssl rand -base64 32)
echo "$NEW_PASSWORD" | fnox set DATABASE_PASSWORD
Remove Obsolete Secrets
fnox unset OLD_API_KEY
aws secretsmanager delete-secret --secret-id old/api-key
Document Secret Purpose
[secrets]
STRIPE_API_KEY = {
provider = "age",
value = "age[...]",
description = "Stripe secret key for payment processing. Rotate quarterly."
}
DATABASE_PASSWORD = {
provider = "aws-sm",
value = "prod/db-password",
description = "PostgreSQL master password. Last rotated: 2025-01-01"
}
CI/CD Security
Use Dedicated CI Keys
[providers.age]
type = "age"
public_keys = [
"age1ql3z...",
"age1ci3d...",
]
Restrict CI Secret Access
env:
FNOX_PROFILE: production
AGE_IDENTITY: ${{ secrets.AGE_IDENTITY }}
steps:
- name: Load secrets
run: |
echo "$AGE_IDENTITY" > /tmp/identity.txt
chmod 600 /tmp/identity.txt
fnox exec -- ./deploy.sh
rm /tmp/identity.txt
Minimal CI Permissions
[profiles.ci]
[profiles.ci.secrets]
DEPLOY_TOKEN = { provider = "age", value = "age[...]" }
Best Practices Summary
DO
✅ Always encrypt sensitive secrets
✅ Use strong encryption (age, KMS)
✅ Store private keys securely
✅ Separate dev and prod secrets
✅ Use .gitignore for local overrides
✅ Rotate keys and secrets regularly
✅ Use cloud provider managed identities
✅ Audit secret access
✅ Document secret purpose
✅ Use profiles for environments
DON'T
❌ Never commit private keys
❌ Never use plain text for sensitive data
❌ Don't share private keys between team members
❌ Don't hardcode credentials
❌ Don't mix dev and prod secrets
❌ Don't skip encryption in production
❌ Don't ignore security warnings
❌ Don't use weak passwords as secrets
Common Threats and Mitigations
Threat: Accidental Commit
cat > .git/hooks/pre-commit <<'EOF'
if git diff --cached fnox.local.toml > /dev/null; then
echo "Error: fnox.local.toml should not be committed"
exit 1
fi
EOF
chmod +x .git/hooks/pre-commit
Threat: Key Compromise
age-keygen -o ~/.config/fnox/keys/identity-new.txt
fnox get --all | fnox set --provider age-new
Threat: Unauthorized Access
[providers.aws-sm]
type = "aws-sm"
region = "us-east-1"
Related Skills
- configuration: Managing fnox.toml securely
- providers: Choosing secure providers