Skip to content

Cron Secrets Management — Securely Handling Credentials in Scheduled Jobs

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Cron Secrets Management. We cover key concepts, practical examples, and best practices to help you master this topic.

Learn cron secrets management: securely store database passwords, API keys, and tokens for cron jobs, retrieve secrets from vaults at runtime, avoid hardcoding secrets in scripts, and rotate credentials without downtime.

What You Learn

You will learn how to manage secrets in cron jobs: storing secrets securely, retrieving them at runtime from vaults, avoiding secret exposure in logs and Process listings, and implementing credential rotation.

Why It Matters

A hardcoded password in a cron script is visible to anyone who can read the script. A secret in a cron command is visible in process listings to any user. Proper secrets management prevents credential exposure and enables rotation.

Real-World Use

DodaTech stores all cron job secrets in HashiCorp Vault. Each cron job retrieves its credentials at startup via a Vault token with limited scope. Secrets are never written to disk, never appear in logs, and are rotated every 90 days automatically.

Vault Secret Retrieval

import os
import json
import time
import base64

class VaultClient:
    def __init__(self, vault_addr, token):
        self.addr = vault_addr
        self.token = token
        self.cache = {}

    def read_secret(self, path):
        if path in self.cache:
            return self.cache[path]
        data = {'password': f'supersecret_{path.replace("/", "_")}', 'username': 'cron_user'}
        self.cache[path] = data
        return data

class SecretInjector:
    def __init__(self, vault_client):
        self.vault = vault_client

    def get_db_credentials(self, db_name):
        path = f"cron/{db_name}/database"
        secret = self.vault.read_secret(path)
        os.environ[f"DB_USER_{db_name.upper()}"] = secret['username']
        os.environ[f"DB_PASS_{db_name.upper()}"] = secret['password']
        print(f"  Injected DB credentials for {db_name}")
        return secret

    def get_api_key(self, service_name):
        path = f"cron/{service_name}/api-key"
        secret = self.vault.read_secret(path)
        os.environ[f"API_KEY_{service_name.upper()}"] = secret['password']
        print(f"  Injected API key for {service_name}")
        return secret

    def clear_env(self):
        for key in list(os.environ.keys()):
            if key.startswith('DB_') or key.startswith('API_'):
                os.environ.pop(key)
        print("  Cleared secrets from environment")

vault = VaultClient("https://vault.dodatech.com:8200", "hvs.token-12345")
injector = SecretInjector(vault)
injector.get_db_credentials("production")
injector.get_api_key("payment")
injector.clear_env()

Expected output:

  Injected DB credentials for production
  Injected API key for payment
  Cleared secrets from environment

Encrypted Config File

import os
import json
from cryptography.fernet import Fernet
import base64

class EncryptedConfig:
    def __init__(self, key_path):
        self.key_path = key_path

    def _load_key(self):
        with open(self.key_path, 'rb') as f:
            return f.read()

    def decrypt_file(self, encrypted_path):
        key = self._load_key()
        cipher = Fernet(key)
        with open(encrypted_path, 'rb') as f:
            encrypted_data = f.read()
        decrypted = cipher.decrypt(encrypted_data)
        return json.loads(decrypted)

    def encrypt_file(self, data, output_path):
        key = self._load_key()
        cipher = Fernet(key)
        encrypted = cipher.encrypt(json.dumps(data).encode())
        with open(output_path, 'wb') as f:
            f.write(encrypted)
        print(f"  Encrypted config written to {output_path}")

    def get_credential(self, encrypted_path, key_name):
        config = self.decrypt_file(encrypted_path)
        return config.get(key_name)

key = Fernet.generate_key()
with open('/tmp/test.key', 'wb') as f:
    f.write(key)

config = EncryptedConfig('/tmp/test.key')
config.encrypt_file(
    {"db_password": "secret123", "api_key": "sk-abc456"},
    '/tmp/cron-config.enc'
)
password = config.get_credential('/tmp/cron-config.enc', 'db_password')
print(f"  Decrypted password: {password}")

Expected output:

  Encrypted config written to /tmp/cron-config.enc
  Decrypted password: secret123

Common Mistakes

1. Hardcoding Secrets in Scripts

A password written directly in a Shell Script is visible to anyone who can read the file, appears in version control (even if removed later, it is in the git history), and is visible in process listings. Never hardcode secrets.

2. Secrets in Cron Command Arguments

*/5 * * * * /script.sh --password 'mypass' — the password is visible in ps aux to any user on the system. Pass secrets as environment variables or read them from a secured file at runtime.

3. Secrets in Log Files

If a cron job logs its command or environment, secrets end up in log files that may have broader read permissions. Strip secrets from logs. Use structured logging that knows which fields to redact.

4. No Secret Rotation

A database password that never changes is a permanent vulnerability. Rotate secrets every 90 days. Use cron to automate rotation: the rotation job generates a new secret, updates the target service, and updates the vault.

5. Same Secret for Multiple Services

If the same API key is used for backup, reporting, and monitoring, compromising any one cron job exposes all services. Use separate secrets per cron job with minimum required permissions.

Practice Questions

1. Where should cron job secrets be stored?

In a secrets manager (Vault, AWS Secrets Manager, GCP Secret Manager) with access control. For simpler setups, use an encrypted file with restricted permissions (0600) and a decryption key stored separately.

2. How do you pass secrets to a cron job without exposing them?

Retrieve secrets from a vault at job start, store in environment variables in-memory only, use for the duration of the job, then clear. Never write secrets to disk, log files, or command arguments.

3. How do you rotate secrets used by cron jobs?

Use a cron job that: generates a new secret, updates the target service with the new secret, updates the vault, and verifies the new secret works. Run rotation during maintenance Windows and test after rotation.

4. What is the risk of storing secrets in environment variables?

Environment variables are visible in /proc/self/environ to the same user, and in child processes. While better than command-line arguments, they are not fully secure. Clear secrets from the environment after use.

Challenge

Build a cron secrets management system: (1) vault integration: retrieve secrets from HashiCorp Vault at job start using a Vault token with limited scope and TTL, (2) encrypted config: store secrets in Fernet-encrypted JSON files with key rotation, (3) secret injection: inject secrets as environment variables, clear after job completion, (4) log redaction: strip known secret patterns from log output before writing, (5) secret rotation: monthly rotation cron that generates new secrets, updates services, and updates vault, (6) access audit: log all secret retrievals with job name, user, and timestamp, (7) emergency secret rotation: on-demand rotation triggered by security incident.

FAQ

Is it safe to store secrets in environment variables?

Environment variables are safer than command-line arguments but not fully secure. They are visible to /proc/self/environ, child processes, and debugging tools. Use them for runtime injection but clear them after use.

How do I prevent secrets from appearing in logs?

Use a log filter that redacts known secret patterns (passwords, keys, tokens). For structured logging, mark secret fields as redacted. Test by searching logs for known secret patterns.

What is the best vault for cron job secrets?

HashiCorp Vault is the most feature-rich (dynamic secrets, rotation, access control). AWS Secrets Manager and GCP Secret Manager are simpler if you are on those clouds. Choose based on your infrastructure.

How often should cron job secrets be rotated?

Every 90 days is standard. PCI DSS requires 90-day rotation. For high-security environments, rotate every 30 days. Use a cron job to automate rotation and avoid manual processes.

What happens if a secret rotation fails?

The old secret should continue working until rotation is verified. Implement a two-phase rotation: create new secret and verify it works before deactivating the old secret. Roll back if verification fails.

Mini Project: Cron Secrets Management

Build a secrets management system: (1) vault reader: retrieve secrets from Vault using token with TTL, (2) encrypted file reader: decrypt Fernet-encrypted config files with key loaded from restricted file, (3) secret injector: set environment variables from secrets, clear after job, (4) log redactor: filter stdout/stderr for patterns matching known secrets before writing to log file, (5) secret rotator: monthly cron that generates new random secrets, updates target service (database, API), updates vault, verifies new secret, (6) emergency rotation: trigger via API call, rotates all cron secrets immediately, (7) audit: log all secret access with job name, timestamp, and result.

What's Next

Now that you understand cron secrets management, explore configuration management for cron, then learn about version control for cron.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro