CreaRack-SL

CREDENTIAL_ENCRYPTION_KEY_OLD (variable de configuración)

Descripción

Variable de entorno que aloja la clave de cifrado anterior durante un ciclo de rotación de credenciales. Solo se lee en la cadena de descifrado; nunca se usa para cifrar nuevos valores.

Estado: Vacía ("") cuando no hay rotación en curso.

Ubicación

  • Definición: config/settings/base.py (línea ~39)
  • Lectura: core/security/credential_manager.py, método _decryption_chain()
CREDENTIAL_ENCRYPTION_KEY_OLD = os.getenv("CREDENTIAL_ENCRYPTION_KEY_OLD", "")

Propagación en entornos

Production (compose.prod.yml)

services:
  web:
    environment:
      - CREDENTIAL_ENCRYPTION_KEY_OLD=${CREDENTIAL_ENCRYPTION_KEY_OLD:-}
  worker:
    environment:
      - CREDENTIAL_ENCRYPTION_KEY_OLD=${CREDENTIAL_ENCRYPTION_KEY_OLD:-}

Development (compose.yml)

services:
  web:
    environment:
      - CREDENTIAL_ENCRYPTION_KEY_OLD=${CREDENTIAL_ENCRYPTION_KEY_OLD:-}

Ciclo de vida en rotación

  1. Antes de rotación: Vacía ("")
  2. Inicia rotación: Se establece en Dokploy/orquestador a la clave antigua
  3. Se ejecuta reencrypt_credentials: Migra todo ciphertext a la nueva clave
  4. Se limpia: Se borra de entorno; la app no la lee más
  5. Después de rotación: Nuevamente vacía

Uso en descifrado

En core/security/credential_manager.py, la cadena de intento es:

def _decryption_chain(cls, include_dev_rescue=True):
    chain = []
    
    def _add(material):
        if material and material not in chain:
            chain.append(material)
    
    _add(cls._active_key_material())  # CREDENTIAL_ENCRYPTION_KEY
    _add((getattr(settings, "CREDENTIAL_ENCRYPTION_KEY_OLD", "") or "").strip() or None)  # OLD
    _add(getattr(settings, "SECRET_KEY", None))  # legacy
    if include_dev_rescue:
        _add(cls.DEV_KEY)  # rescue
    
    return chain

Si la variable está vacía o whitespace, se omite de la cadena.

Seguridad

  • Secreto de entorno: Nunca se debe serializar, loguear o exponer
  • Solo lectura en descifrado: El encriptado siempre usa CREDENTIAL_ENCRYPTION_KEY (activa)
  • Limpieza obligatoria: Debe borrarse después de reencrypt_credentials para no mantener claves antiguas innecesariamente
  • Auditar antes de limpiar: Verificar que la migración fue completa y exitosa

Test

Validado en tests/test_credential_key_rotation.py::test_rotation_via_old_key:

  • Verifica que ciphertext antiguo se descifra vía OLD cuando es activa la nueva clave
  • Valida que nuevos ciphertexts se cifran con la clave activa
  • Confirma que OLD se omite de la cadena tras limpiar la variable

Véase también

  • [[feature—security—credential-key-rotation]]
  • [[entity—core—config—credential-encryption-key]]
  • [[entity—core—service—credential-manager]]
  • [[concept—security—credential-encryption]]
  • [[concept—security—key-rotation]]