DiscourseConnect genera redirecciones HTTP incluso con force_https activado

Estoy ejecutando Discourse detrás de Traefik en una configuración personalizada; darle a Discourse su propia VM no es una opción aquí.

Mi Discourse no tiene habilitadas las plantillas SSL/Let’s Encrypt, ya que Traefik no permite que las solicitudes HTTP sin cifrar lleguen al contenedor; está configurado para redirigir las solicitudes HTTP a HTTPS.

Tengo problemas para configurar DiscourseConnect, porque, dado que la solicitud Traefik -> nginx[Discourse] se envía a través de HTTP sin cifrar (porque nginx no tiene SSL configurado), la regla en /etc/nginx/conf.d/discourse.conf que intenta “preservar el protocolo, debe estar en el contexto http” hace que Discourse (la aplicación Rails) reciba una solicitud HTTP sin cifrar, devolviendo así una redirección HTTP sin cifrar a /session/sso, incluso si tengo force_https habilitado.

Creo que ese es el error: independientemente de mi configuración, con force_https habilitado, Discourse siempre debería generar URLs HTTPS, lo cual no está haciendo.

Creo que el código infractor es application_controller#redirect_to_login, pero no he profundizado tanto en el código fuente de Discourse para estar seguro.

¿Se puede solucionar esto en el propio código?

Como solución alternativa, estoy intentando agregar una regla que modifique el discourse.conf de nginx para eliminar esa regla.

Deberíamos tener algún soporte para encabezados reenviados que usarías para indicar a NGINX cuál es el origen.

¿Estableciste \n\nproxy_set_header X-Forwarded-Proto https;

Lo más fácil para mí fue configurar una etiqueta adicional en app.yml de Discourse para indicarle a mi Traefik que agregara una cabecera X-Forwarded-Proto: https, pero luego nginx anularía ese parámetro con su propia versión.

Y la configuración de nginx de Discourse juega un papel aquí:

Aquí Discourse intenta adivinar el protocolo de la solicitud original (que, en mi configuración, siempre es texto plano ya que eso es lo que envía Traefik). Y luego lo usa para establecer el X-Forwarded-Proto varias veces.

Al final, edité mi containers/app.yml para codificar esas cabeceras como https:

run:
  - exec: echo "Beginning of custom commands"
  ## If you want to set the 'From' email address for your first registration, uncomment and change:
  ## After getting the first signup email, re-comment the line. It only needs to run once.
  # - exec: rails r "SiteSetting.notification_email='no-reply@forum.cabana.network'"
  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: /# attempt to preserve the proto, must be in http context\nmap \$http_x_forwarded_proto \$thescheme {\n  default \$scheme;\n  "~https$" https;\n}/\n
     to: |
       # force https scheme so Discourse generates HTTPs links and redirects (ie, `/login`)
  - replace:
     filename: "/etc/nginx/conf.d/discourse.conf"
     from: "$thescheme"
     global: "true"
     to: "https"
  - exec: echo "End of custom commands"

Una vez más, creo que si hubiera una configuración force_https, Discourse-la-aplicación-rails debería respetarla, independientemente de lo que el proxy inverso u otras partes manejen o no.

Así es como lo hacemos en nuestra plataforma de alojamiento; tenemos una capa de balanceador de carga que establece X-Forwarded-Proto para que nginx+Discourse lo consuma aguas abajo.

No necesitamos ninguna complicación adicional para que funcione; no estoy seguro de qué está saliendo mal para ti aquí.

Esto es, de hecho, lo que sucede:

  def self.generate_sso(return_path = "/", secure_session:)
    sso = new(secure_session: secure_session)
    sso.nonce = SecureRandom.hex
    sso.register_nonce(return_path)
    sso.return_sso_url = Discourse.base_url + "/session/sso_login"
    sso
  end

y base_url proviene de:

  def self.base_protocol
    SiteSetting.force_https? ? "https" : "http"
  end

  def self.base_url_no_prefix
    "#{base_protocol}://#{current_hostname_with_port}"
  end

  def self.base_url
    base_url_no_prefix + base_path
  end
1 me gusta