Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plug.SSL - exclude certain paths from redirecting #815

Closed
arjan opened this issue Jan 29, 2019 · 4 comments
Closed

Plug.SSL - exclude certain paths from redirecting #815

arjan opened this issue Jan 29, 2019 · 4 comments

Comments

@arjan
Copy link

arjan commented Jan 29, 2019

Similar to the exclude: option for hosts, it would be handy to have an option (exclude_paths) to prevent certain paths to redirect to HTTPS.

The use case here is that I'm configuring GKE with HTTPS and use Plug.SSL to redirect HTTP traffic to HTTPS. The problem is now that my health check also does a 301 redirect instead of serving a 200, which leads to Kubernetes (or the Google Ingress HTTP specifically) thinking that my application is not healthy.

I now ended up forking Plug.SSL, it's a 4-line change literally, but I was wondering if this would be something worth contributing.

@josevalim
Copy link
Member

josevalim commented Jan 29, 2019

So this is a very tricky slippery slope because in theory all plugs could have a "path" option. So my suggestion here is to apply the plug dynamically in your endpoint and continue treating this as a concern orthogonal to plugs. It would be something like this:

plug :ssl

@ssl_opts Plug.SSL.init(...your_opts)
def ssl(%{path_info: ["health"]} = conn, _opts), do: conn
def ssl(conn, _opts), do: Plug.SSL.call(conn, @ssl_opts)

Another idea is to have the healthcheck endpoint separate from your app, either by running on another port, or by having a custom route in your cowboy dispatch.

PS: theoretically the same logic could apply to hosts, they do not need to be handled by the plug, but in this case it was done in favor of security handling.

@arjan
Copy link
Author

arjan commented Jan 29, 2019

Thanks, great answer! Did not think of wrapping Plug.SSL, that is indeed very elegant.

@dannypaz
Copy link

@josevalim circling back on this. I just ran into this issue myself.

I'm not sure how many users will run into this, but if you're using a managed LB like AWS ALB or GCP CLB... you would run into this issue and need to create a custom plug yourself (AWS/GCP both use hostnames over ips).

Just my initial reaction (as a new Elixir user), I was surprised that exclude_paths was not an option, but IPs were.

@arjan
Copy link
Author

arjan commented Sep 28, 2020

FWIW this is my implementation:

defmodule MyApp.Plug.SSL do
  @moduledoc """
  SSL redirect excluding the health endpoints

  https://github.com/elixir-plug/plug/issues/815
  """

  defdelegate init(opts), to: Plug.SSL

  def call(%{request_path: "/healthz"} = conn, _opts), do: conn
  def call(%{request_path: "/api/sys/" <> _} = conn, _opts), do: conn
  def call(%{request_path: "/.well-known/" <> _} = conn, _opts), do: conn

  def call(conn, opts) do
    Plug.SSL.call(conn, opts)
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants