Cron Secrets Management — Securely Handling Credentials in Scheduled Jobs
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
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