Skip to content

Local File Targets

Local file targets store secrets in files on the local filesystem, making them ideal for development environments, testing, and applications that read configuration from files.

Overview

The file target supports multiple formats commonly used for configuration:

  • .env (dotenv) - Environment variable format
  • JSON - JavaScript Object Notation
  • YAML - YAML Ain't Markup Language
  • TOML - Tom's Obvious Minimal Language

Use Cases

  • Local development - Store secrets for development environments
  • Container configuration - Mount secret files in Docker containers
  • Legacy applications - Support apps that read from config files
  • Backup - Create local copies of cloud-managed secrets
  • Testing - Generate test fixtures with realistic secret data

Configuration

Basic Example

secrets:
  - name: database_password
    kind: random_password
    config:
      length: 32
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv
          merge: true

Configuration Options

Option Type Required Default Description
path string Yes .env File path to store secrets (relative or absolute)
format string Yes dotenv File format: dotenv, json, yaml, toml
merge boolean No true Whether to merge with existing content or overwrite

Format Specifications

Dotenv Format

Standard environment variable format used by many frameworks.

Configuration:

targets:
  - provider: local
    kind: file
    config:
      path: .env
      format: dotenv
      merge: true

Output (.env):

DATABASE_PASSWORD=supersecret123
API_KEY=abcdef123456
JWT_SECRET=random-jwt-token-here

Features: - Simple key=value pairs - Comments supported (lines starting with #) - Automatic quoting for values with spaces or special characters - Preserves existing variables when merge: true

Example with multiple secrets:

secrets:
  - name: DB_HOST
    kind: static
    config:
      value: localhost
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv

  - name: DB_PASSWORD
    kind: random_password
    config:
      length: 24
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv
          merge: true  # Merge with DB_HOST

JSON Format

Structured format for programmatic access.

Configuration:

targets:
  - provider: local
    kind: file
    config:
      path: secrets.json
      format: json
      merge: true

Output (secrets.json):

{
  "database_password": "supersecret123",
  "api_key": "abcdef123456",
  "jwt_secret": "random-jwt-token-here"
}

Features: - Structured key-value storage - Easy to parse in any language - Pretty-printed with 2-space indentation - Supports merging with existing JSON objects

Example with nested structure:

secrets:
  - name: app_config
    kind: templates.application_config

templates:
  application_config:
    fields:
      database:
        generator:
          kind: static
          config:
            default: '{"host": "localhost", "port": 5432}'
      api_key:
        generator:
          kind: random_string
          config:
            length: 32
    targets:
      - provider: local
        kind: file
        config:
          path: config.json
          format: json

YAML Format

Human-readable format popular in configuration files.

Configuration:

targets:
  - provider: local
    kind: file
    config:
      path: secrets.yaml
      format: yaml
      merge: true

Output (secrets.yaml):

database_password: supersecret123
api_key: abcdef123456
jwt_secret: random-jwt-token-here

Features: - Clean, readable format - Preserves key order - No flow style (uses block style) - Merges with existing YAML structures

Example configuration:

secrets:
  - name: database_url
    kind: static
    config:
      value: postgresql://user:pass@localhost/db
    targets:
      - provider: local
        kind: file
        config:
          path: config.yaml
          format: yaml

  - name: redis_url
    kind: static
    config:
      value: redis://localhost:6379
    targets:
      - provider: local
        kind: file
        config:
          path: config.yaml
          format: yaml
          merge: true

TOML Format

Configuration format used by Rust, Python, and other ecosystems.

Configuration:

targets:
  - provider: local
    kind: file
    config:
      path: secrets.toml
      format: toml
      merge: true

Output (secrets.toml):

database_password = "supersecret123"
api_key = "abcdef123456"
jwt_secret = "random-jwt-token-here"

Features: - Clear, unambiguous format - Type-safe - Good for nested configurations - Popular in Rust and Python projects

Dependencies: TOML support requires additional packages:

pip install secretzero[toml]
# or
pip install tomli tomli-w

Complete Examples

Development Environment Setup

Create a complete .env file for local development:

version: '1.0'

secrets:
  # Database configuration
  - name: DB_HOST
    kind: static
    config:
      value: localhost
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv

  - name: DB_PORT
    kind: static
    config:
      value: "5432"
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv
          merge: true

  - name: DB_NAME
    kind: static
    config:
      value: myapp_dev
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv
          merge: true

  - name: DB_PASSWORD
    kind: random_password
    config:
      length: 24
      special: false
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv
          merge: true

  # Application secrets
  - name: SECRET_KEY
    kind: random_string
    config:
      length: 64
      charset: base64
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv
          merge: true

  - name: JWT_SECRET
    kind: random_string
    config:
      length: 32
      charset: hex
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv
          merge: true

  # External API keys
  - name: STRIPE_API_KEY
    kind: random_string
    config:
      length: 32
      charset: alphanumeric
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv
          merge: true

Result (.env):

DB_HOST=localhost
DB_PORT=5432
DB_NAME=myapp_dev
DB_PASSWORD=randompassword123456789012
SECRET_KEY=base64encodedsecretkey...
JWT_SECRET=abcdef1234567890abcdef1234567890
STRIPE_API_KEY=sk_test_abc123def456ghi789jkl

Multi-Format Configuration

Store secrets in multiple formats simultaneously:

version: '1.0'

secrets:
  - name: api_credentials
    kind: templates.api_config

templates:
  api_config:
    description: API configuration
    fields:
      api_key:
        generator:
          kind: random_string
          config:
            length: 32
            charset: alphanumeric
      api_secret:
        generator:
          kind: random_string
          config:
            length: 64
            charset: base64
      endpoint:
        generator:
          kind: static
          config:
            default: https://api.example.com
    targets:
      # Dotenv for Docker Compose
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv

      # JSON for Node.js apps
      - provider: local
        kind: file
        config:
          path: config/secrets.json
          format: json

      # YAML for Python apps
      - provider: local
        kind: file
        config:
          path: config/secrets.yaml
          format: yaml

Docker Container Secrets

Generate secrets for Docker containers:

version: '1.0'

secrets:
  - name: POSTGRES_PASSWORD
    kind: random_password
    config:
      length: 32
      special: false
    targets:
      - provider: local
        kind: file
        config:
          path: docker/.env
          format: dotenv

  - name: REDIS_PASSWORD
    kind: random_password
    config:
      length: 24
      special: false
    targets:
      - provider: local
        kind: file
        config:
          path: docker/.env
          format: dotenv
          merge: true

  - name: APP_SECRET_KEY
    kind: random_string
    config:
      length: 64
      charset: base64
    targets:
      - provider: local
        kind: file
        config:
          path: docker/.env
          format: dotenv
          merge: true

Use with Docker Compose:

# docker-compose.yml
version: '3.8'

services:
  postgres:
    image: postgres:15
    env_file:
      - docker/.env
    environment:
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}

  redis:
    image: redis:7
    command: redis-server --requirepass ${REDIS_PASSWORD}
    env_file:
      - docker/.env

  app:
    build: .
    env_file:
      - docker/.env
    environment:
      - SECRET_KEY=${APP_SECRET_KEY}

Best Practices

1. Use .gitignore

Always exclude secret files from version control:

# Secret files
.env
.env.local
.env.*.local
secrets.json
secrets.yaml
secrets.toml
config/secrets.*

# Keep templates
!.env.example

2. Provide Example Files

Create example files with dummy values:

# .env.example
DB_HOST=localhost
DB_PORT=5432
DB_PASSWORD=changeme
API_KEY=your-api-key-here

3. Use Merge Mode Carefully

When merge: true: - Existing keys are preserved - New secrets are added - Updated secrets overwrite old values

When merge: false: - File is completely overwritten - Only current secrets are included - Previous content is lost

# Safe for multiple secrets in same file
targets:
  - provider: local
    kind: file
    config:
      path: .env
      format: dotenv
      merge: true  # Add to existing file

# Use for single-secret files
targets:
  - provider: local
    kind: file
    config:
      path: secrets/api_key.txt
      format: dotenv
      merge: false  # Overwrite completely

4. Organize by Environment

Structure files by environment:

variables:
  environment: dev

secrets:
  - name: database_password
    kind: random_password
    config:
      length: 32
    targets:
      - provider: local
        kind: file
        config:
          path: .env.{{var.environment}}
          format: dotenv

Results in: .env.dev, .env.staging, .env.prod

5. Set Appropriate Permissions

Protect secret files with proper permissions:

# Restrict access to owner only
chmod 600 .env
chmod 600 secrets.json

# Or use SecretZero to set permissions
secretzero sync -f Secretfile.yml --file-mode 0600

6. Use Separate Files for Different Purposes

Organize secrets logically:

secrets:
  # Database secrets → database.env
  - name: DB_PASSWORD
    targets:
      - provider: local
        kind: file
        config:
          path: secrets/database.env
          format: dotenv

  # API keys → api.env
  - name: API_KEY
    targets:
      - provider: local
        kind: file
        config:
          path: secrets/api.env
          format: dotenv

  # Application config → app.json
  - name: app_config
    targets:
      - provider: local
        kind: file
        config:
          path: config/app.json
          format: json

Troubleshooting

File Not Created

Problem: Secret file doesn't exist after running sync.

Solutions: 1. Check parent directory exists (SecretZero creates missing directories) 2. Verify path is correct (relative to working directory) 3. Check file permissions on parent directory 4. Review logs for error messages

# Test with absolute path
secretzero sync -f Secretfile.yml --log-level debug

Merge Not Working

Problem: New secrets overwrite existing ones.

Solutions: 1. Ensure merge: true is set 2. Check file format matches existing file 3. Verify file is readable 4. Use different files if formats conflict

Format Not Supported

Problem: Error about unsupported format.

Solutions: 1. For TOML: Install dependencies

pip install tomli tomli-w
2. Check format spelling: dotenv, json, yaml, toml (lowercase) 3. Verify file extension matches format

Special Characters in Dotenv

Problem: Values with spaces or special characters break parsing.

Solution: SecretZero automatically quotes values with special characters:

# Automatically quoted
PASSWORD="p@ss w0rd!"
API_KEY="key-with-dashes"

# No quotes needed
SIMPLE_KEY=abc123

File Encoding Issues

Problem: Non-ASCII characters cause errors.

Solution: All files are written in UTF-8. Ensure your editor uses UTF-8:

secrets:
  - name: WELCOME_MESSAGE
    kind: static
    config:
      value: "Welcome! 你好! مرحبا!"
    targets:
      - provider: local
        kind: file
        config:
          path: .env
          format: dotenv

Integration Examples

Python Applications

# Load secrets from .env
from dotenv import load_dotenv
import os

load_dotenv()

database_password = os.getenv('DATABASE_PASSWORD')
api_key = os.getenv('API_KEY')

Node.js Applications

// Load secrets from .env
require('dotenv').config();

const databasePassword = process.env.DATABASE_PASSWORD;
const apiKey = process.env.API_KEY;

Go Applications

// Load secrets from .env
import "github.com/joho/godotenv"

err := godotenv.Load()
if err != nil {
    log.Fatal("Error loading .env file")
}

databasePassword := os.Getenv("DATABASE_PASSWORD")
apiKey := os.Getenv("API_KEY")

Ruby Applications

# Load secrets from .env
require 'dotenv/load'

database_password = ENV['DATABASE_PASSWORD']
api_key = ENV['API_KEY']

Security Considerations

File Permissions

Local files are only as secure as their permissions:

# Secure file permissions
chmod 600 .env          # Owner read/write only
chmod 700 secrets/      # Owner access to directory

# Check permissions
ls -la .env
# Should show: -rw------- (600)

Encryption at Rest

For sensitive data, consider encrypting files:

# Encrypt with GPG
gpg --symmetric --cipher-algo AES256 secrets.json

# Decrypt when needed
gpg --decrypt secrets.json.gpg > secrets.json

Temporary Files

Clean up temporary secret files:

# Generate temporary secrets
secrets:
  - name: temp_token
    kind: random_string
    config:
      length: 32
    targets:
      - provider: local
        kind: file
        config:
          path: /tmp/temp_secret.txt
          format: dotenv

Then clean up:

# After use
rm -f /tmp/temp_secret.txt

Backup Considerations

When backing up systems: - Exclude secret files from backups - Or use encrypted backups - Rotate secrets after backup restoration

# Exclude from rsync backup
rsync -av --exclude='.env' --exclude='secrets/' /app/ /backup/

Next Steps