Handling Secrets

Overview

secret() resolves values from environment / local / default like config(), but it masks configured values in manage.py configvars output.

Runtime behavior

  • If only DB_PASSWORD is set, the literal value is used.

  • If only DB_PASSWORD_FILE is set, the file content is read.

  • If both are set, ImproperlyConfigured is raised.

  • If neither is set, the function falls back to local/default.

Security behavior

secret() no longer guesses that a literal value is a file path. File reads only happen when file_var=... is passed explicitly.

This avoids accidental reads of unrelated files when an environment value happens to look like an existing path.

File validation for file_var

By default:

  • the file must exist

  • the file must not exceed configvars.MAX_SECRET_FILE_SIZE

  • the file must be single-line

For multiline secrets (for example PEM blocks), enable it explicitly:

TLS_PRIVATE_KEY = secret(
    "TLS_PRIVATE_KEY",
    file_var="TLS_PRIVATE_KEY_FILE",
    allow_multiline=True,
)

CLI masking

Configured secrets are masked in manage.py configvars output:

DB_PASSWORD = '*****'

Unset or empty values are still shown as None / '' to avoid implying a value exists when it does not.