CAPÍTULO 9 · El mismo proyecto llega a Azure
Las opciones de producción adquieren sentido juntas
Al inicio colocamos en base.py la política común. Ahora tenemos un servicio expuesto por HTTPS y una explicación de su proxy, por lo que podemos completar el significado de las opciones específicas de producción. La separación de archivos evita que esas exigencias se confundan con las facilidades del desarrollo local.
Conservamos y estudiamos los valores del proyecto para redirección HTTPS, cookies seguras y HSTS, además de hosts y secretos. Revisamos uno por uno qué hacen y bajo qué condiciones. Por ejemplo, ampliar una política a subdominios obliga a conocer ese alcance; escribir una directiva no reemplaza preparar correctamente la infraestructura que la sostiene.
La configuración queda conectada con el recorrido real de la petición. Pero incluso una aplicación bien configurada puede fallar al acceder a una dependencia. Antes de declarar terminada la publicación necesitamos señales que permitan distinguir un proceso que existe de un servicio que está preparado para atender trabajo útil.
Leer esta parte dentro del relato completo →DEL RELATO A LA PRÁCTICA
Vamos a desarrollar esta decisión con su mapa, explicación, código y ejercicio.
MIRA · CONECTA · COMPRENDE
El perímetro HTTPS
Las flechas resumen el recorrido conceptual. Los controles y dependencias se detallan debajo.
Selecciona una pieza para destacar su responsabilidad.
Leer la explicación del mapa
- Proxy TLS. Protege transporte externo
- Django. Reconoce protocolo confiable
- Cookies Secure. Restringe envío a HTTPS
- HSTS. Comprueba alcance y duración
01 / EL PROBLEMA
¿Para qué sirve?
El proxy puede terminar TLS mientras Django recibe HTTP internamente. Si el entorno no reconoce esa arquitectura, puede redirigir en bucle o emitir cookies con una política incorrecta.
02 / COMPRENDER
El concepto, explicado
production.py conserva los valores de seguridad del proyecto de referencia: redirección HTTPS, confianza del protocolo indicado por proxy, cookies Secure y HSTS de un año con subdominios y preload. Cada ajuste se explica abajo con su finalidad y comprobación.
La política exige un entorno productivo con HTTPS y un proxy que elimina o sobrescribe X-Forwarded-Proto del cliente. El proceso no debe aceptar accesos directos que eludan esa frontera. No actives esta confianza sobre un header que cualquier visitante pueda controlar.
El alcance de HSTS incluye los subdominios. Antes de servir esta política comprueba todo ese alcance bajo HTTPS. PRELOAD no realiza la inscripción externa por sí solo, y HSTS sin precarga efectiva no protege una primera visita que aún no conoce la política.
base.py ya declara las defensas comunes. production.py añade transporte y valores del entorno. development.py conserva su recorrido local HTTP. Los permisos de API, validación y escape se aplican además en sus componentes correspondientes.
Defensas de producción
| Ajuste | Objetivo | Cómo comprobarlo |
|---|---|---|
| DEBUG=False / SECRET_KEY | Evitar exposición interna y proteger firmas | Errores sin traceback y clave exclusiva del entorno |
| ALLOWED_HOSTS | Limitar Host aceptados | Host permitido y Host ajeno |
| CSRF_TRUSTED_ORIGINS | Permitir solo los orígenes necesarios | POST cruzado autorizado y rechazado |
| SECURE_SSL_REDIRECT | Conducir el tráfico a HTTPS | HTTP redirige, HTTPS no entra en bucle |
| SECURE_PROXY_SSL_HEADER | Reconocer HTTPS tras proxy confiable | Revisar saneamiento del header y acceso directo |
| SESSION_COOKIE_SECURE / CSRF_COOKIE_SECURE | Enviar esas cookies por HTTPS | Inspeccionar flags si se crean |
| SECURE_HSTS_SECONDS | Recordar obligación HTTPS | Strict-Transport-Security en HTTPS |
| SECURE_HSTS_INCLUDE_SUBDOMAINS | Extender HSTS al alcance subordinado | Todos los subdominios usan HTTPS |
| SECURE_HSTS_PRELOAD | Anunciar intención de precarga | Revisar requisitos e incorporación externa |
CONFIGURACIÓN EXPLICADA OPCIÓN POR OPCIÓN
Qué hace cada ajuste
1. DEBUG
DEBUG = FalsePara qué y por qué se usa. Evita publicar las páginas detalladas de depuración con contexto interno cuando falla una petición.
Alcance y condiciones. No arregla el error subyacente ni impide registrar secretos indebidamente.
Cómo verificarlo. Provoca un fallo controlado en pruebas y comprueba que la respuesta no muestra el traceback.
2. SECRET_KEY
SECRET_KEY = os.environ["SECRET_KEY"]Para qué y por qué se usa. Extrae la clave de firma desde el entorno productivo y evita versionarla en el código.
Alcance y condiciones. No cifra la base de datos ni sirve como client secret de MSAL. Usa una clave aleatoria exclusiva y controla su rotación.
Cómo verificarlo. Comprueba que falta de la variable impide arrancar, sin imprimir el valor.
3. ALLOWED_HOSTS
ALLOWED_HOSTS = [host.strip() for host in os.environ["ALLOWED_HOSTS"].split(",") if host.strip()]Para qué y por qué se usa. Define los hosts que la aplicación acepta y limita manipulación del header Host.
Alcance y condiciones. No controla quién puede ejecutar un caso de uso. En esta academia se rechaza * y se requieren hosts sin esquema ni ruta.
Cómo verificarlo. El host previsto funciona y uno ajeno obtiene rechazo 400 al validarlo Django.
4. CSRF_TRUSTED_ORIGINS
CSRF_TRUSTED_ORIGINS = [origin.strip() for origin in os.environ.get("CSRF_TRUSTED_ORIGINS", "").split(",") if origin.strip()]Para qué y por qué se usa. Declara orígenes adicionales de confianza para la comprobación CSRF cuando el flujo los necesita.
Alcance y condiciones. No desactiva el token CSRF, no configura CORS ni concede permisos de API. No amplíes la lista sin un caso legítimo.
Cómo verificarlo. Comprueba esquema https:// y un POST protegido con token desde un origen ajeno rechazado.
5. SECURE_SSL_REDIRECT
SECURE_SSL_REDIRECT = TruePara qué y por qué se usa. Redirige peticiones que Django reconoce como HTTP hacia HTTPS. Evita continuar navegaciones inseguras al sitio productivo.
Alcance y condiciones. La infraestructura debe disponer certificado y TLS. Una redirección no protege por sí sola el contenido de la primera solicitud HTTP.
Cómo verificarlo. HTTP devuelve redirección hacia HTTPS y HTTPS llega al sitio sin bucles.
6. SECURE_PROXY_SSL_HEADER
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')Para qué y por qué se usa. Permite que Django reconozca HTTPS externo cuando el proxy termina TLS y comunica el protocolo mediante X-Forwarded-Proto.
Alcance y condiciones. Exige que el proxy elimine/sobrescriba valores enviados por el cliente y que no exista acceso directo que eluda esa frontera. Confiar en un header suplantable crea una falla de seguridad.
Cómo verificarlo. Comprueba el recorrido real del proxy, el saneamiento del header y que Django reconoce request.is_secure() en el flujo HTTPS.
7. SECURE_HSTS_SECONDS
SECURE_HSTS_SECONDS = 31536000Para qué y por qué se usa. Anuncia un año de obligación de HTTPS a navegadores que reciben y conservan la política. Mitiga posteriores intentos de degradar la conexión a HTTP.
Alcance y condiciones. Sin una precarga efectiva no protege la primera visita que todavía no conoce la política. El navegador conserva la duración aunque cambies después el servidor.
Cómo verificarlo. Comprueba Strict-Transport-Security con max-age=31536000 en una respuesta HTTPS.
8. SECURE_HSTS_INCLUDE_SUBDOMAINS
SECURE_HSTS_INCLUDE_SUBDOMAINS = TruePara qué y por qué se usa. Extiende HSTS a los subdominios del host que publica la política. Cubre ese alcance cuando todos soportan HTTPS.
Alcance y condiciones. Todos los subdominios incluidos deben funcionar bajo HTTPS; uno legado puede quedar inaccesible.
Cómo verificarlo. Inspecciona includeSubDomains y verifica inventario, certificados y HTTPS en todo el alcance.
9. SECURE_HSTS_PRELOAD
SECURE_HSTS_PRELOAD = TruePara qué y por qué se usa. Añade la directiva preload para la política destinada a precarga. Expresa una intención que se completa con requisitos y procedimiento externo.
Alcance y condiciones. Este valor no inscribe automáticamente el dominio en las listas de navegadores. La incorporación y retirada tienen efectos de largo plazo.
Cómo verificarlo. Inspecciona preload y revisa por separado elegibilidad e incorporación real del dominio.
10. SESSION_COOKIE_SECURE
SESSION_COOKIE_SECURE = TruePara qué y por qué se usa. Marca la cookie de sesión para que el navegador la envíe solo por HTTPS. Reduce exposición en transporte sin cifrar.
Alcance y condiciones. No impide todo robo de sesión ni crea una sesión si la aplicación no la usa. En local HTTP puede impedir el flujo legítimo.
Cómo verificarlo. Cuando la app emite sessionid, verifica Secure y su envío bajo HTTPS.
11. CSRF_COOKIE_SECURE
CSRF_COOKIE_SECURE = TruePara qué y por qué se usa. Marca la cookie del token CSRF para que se envíe por HTTPS en producción.
Alcance y condiciones. No reemplaza validación del token y del origen. Requiere que el recorrido real use HTTPS.
Cómo verificarlo. Cuando se emite csrftoken, comprueba Secure y el POST protegido bajo HTTPS.
03 / CONSTRUIR
Implementación paso a paso
- Prepara HTTPS y el certificado del dominio productivo.
- Comprueba la frontera del proxy y todos los subdominios del alcance.
- Define SECRET_KEY, ALLOWED_HOSTS y los orígenes CSRF necesarios en el entorno.
- Conserva las asignaciones productivas del ejemplo sin trasladarlas a HTTP local.
- Ejecuta check --deploy con production.py.
- Comprueba cada control de la lista mediante peticiones y cabeceras reales.
- Registra la verificación del flujo productivo, incluidos cookies, acceso y retorno de identidad si aplica.
04 / APLICAR
Ejemplo en SensorHub
"""Configuración HTTPS de producción; valores privados desde el entorno."""
from .base import *
from django.core.exceptions import ImproperlyConfigured
DEBUG = False
SECRET_KEY = os.environ['SECRET_KEY']
ALLOWED_HOSTS = [host.strip() for host in os.environ['ALLOWED_HOSTS'].split(',') if host.strip()]
if not ALLOWED_HOSTS or any(host == '*' or '://' in host or '/' in host for host in ALLOWED_HOSTS):
raise ImproperlyConfigured('ALLOWED_HOSTS requiere hosts explícitos sin esquema ni rutas')
CSRF_TRUSTED_ORIGINS = [origin.strip() for origin in os.environ.get('CSRF_TRUSTED_ORIGINS', '').split(',') if origin.strip()]
# Transporte: el sitio productivo se sirve bajo HTTPS.
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# El proxy de producción debe eliminar/sobrescribir el header del cliente
# y no permitir acceso directo que eluda esa frontera de confianza.
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Política HSTS del proyecto de referencia: un año y todo el alcance.
# Requiere HTTPS correcto en todos los subdominios incluidos.
# PRELOAD anuncia la directiva; no realiza la inscripción externa.
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
STORAGES = {
'default': {'BACKEND': 'django.core.files.storage.FileSystemStorage'},
'staticfiles': {'BACKEND': 'whitenoise.storage.CompressedManifestStaticFilesStorage'},
}
MIDDLEWARE = [MIDDLEWARE[0], 'whitenoise.middleware.WhiteNoiseMiddleware', *MIDDLEWARE[1:]]
Cómo leer el ejemplo
- Los valores HSTS son 31536000, True y True: año, subdominios y directiva preload.
- El proxy HTTPS queda definido por HTTP_X_FORWARDED_PROTO=https; el entorno debe garantizar esa cabecera.
- SESSION_COOKIE_SECURE y CSRF_COOKIE_SECURE son True en producción.
- Las variables de secretos, hosts y orígenes siguen fuera del código.
- WhiteNoise conserva su posición después de SecurityMiddleware.
Error habitual
Confiar en X-Forwarded-Proto sin comprobar que el proxy controle el valor recibido, o publicar HSTS para subdominios que no soportan HTTPS. Comprueba la infraestructura que hace válida la política.
05 / PRACTICAR
Tu turno
El sitio anuncia HSTS con includeSubDomains, pero un subdominio antiguo solo sirve HTTP. Explica el riesgo y qué debes preparar para cumplir esta política.
Ver solución orientativa
Los navegadores que conocen la política pueden forzar HTTPS en ese subdominio y dejarlo inaccesible si no lo admite. Debes inventariar el alcance y preparar HTTPS y certificados para todos los subdominios incluidos. El valor de preload tampoco prueba incorporación a una lista externa.
06 / VERIFICAR
Cómo sabes que funciona
- DEBUG=False y secretos no publicados.
- HTTP redirige a HTTPS y la petición HTTPS real no entra en bucle.
- La respuesta HTTPS anuncia el HSTS previsto y las cabeceras comunes.
- Cuando se crean cookies de sesión/CSRF, sus flags son correctos.
- Un host no autorizado recibe rechazo.
Para profundizar
Documentación oficial para comprobar configuración, permisos y condiciones vigentes. Revisión del tema: 11 de octubre de 2026.
CONTINUAR LA EXPERIENCIA
El siguiente paso del recorrido:
Despliegue, salud y observabilidad →Continuar en modo relato