Add LIVEBOOK_PROXY_HEADERS (#2604)

This commit is contained in:
José Valim 2024-05-14 13:22:17 +02:00 committed by GitHub
parent 708c151cfc
commit 6f1e09e09b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 49 additions and 2 deletions

View file

@ -266,6 +266,10 @@ The following environment variables can be used to configure Livebook on boot:
* `LIVEBOOK_PASSWORD` - sets a password that must be used to access Livebook. * `LIVEBOOK_PASSWORD` - sets a password that must be used to access Livebook.
Must be at least 12 characters. Defaults to token authentication. Must be at least 12 characters. Defaults to token authentication.
* `LIVEBOOK_PROXY_HEADERS` - a comma-separated list of headers that are set by
proxies. For example, `x-forwarded-for,x-forwarded-proto`. Configuring those
may be required when running Livebook behind reverse proxies.
* `LIVEBOOK_PORT` - sets the port Livebook runs on. If you want to run multiple * `LIVEBOOK_PORT` - sets the port Livebook runs on. If you want to run multiple
instances on the same domain with the same credentials but on different ports, instances on the same domain with the same credentials but on different ports,
you also need to set `LIVEBOOK_SECRET_KEY_BASE`. Defaults to 8080. If set to 0, you also need to set `LIVEBOOK_SECRET_KEY_BASE`. Defaults to 8080. If set to 0,

View file

@ -35,6 +35,7 @@ config :livebook,
force_ssl_host: nil, force_ssl_host: nil,
learn_notebooks: [], learn_notebooks: [],
plugs: [], plugs: [],
rewrite_on: [],
shutdown_callback: nil, shutdown_callback: nil,
teams_url: "https://teams.livebook.dev", teams_url: "https://teams.livebook.dev",
update_instructions_url: nil, update_instructions_url: nil,

View file

@ -199,6 +199,10 @@ defmodule Livebook do
config :livebook, :cacertfile, cacertfile config :livebook, :cacertfile, cacertfile
end end
if rewrite_on = Livebook.Config.rewrite_on!("LIVEBOOK_PROXY_HEADERS") do
config :livebook, :rewrite_on, rewrite_on
end
config :livebook, config :livebook,
:cookie, :cookie,
Livebook.Config.cookie!("LIVEBOOK_COOKIE") || Livebook.Config.cookie!("LIVEBOOK_COOKIE") ||

View file

@ -349,6 +349,13 @@ defmodule Livebook.Config do
Application.fetch_env!(:livebook, :force_ssl_host) Application.fetch_env!(:livebook, :force_ssl_host)
end end
@doc """
Returns rewrite_on headers.
"""
def rewrite_on do
Application.fetch_env!(:livebook, :rewrite_on)
end
@doc """ @doc """
Returns the application cacertfile if any. Returns the application cacertfile if any.
""" """
@ -543,6 +550,25 @@ defmodule Livebook.Config do
end end
end end
@doc """
Parses info for `Plug.RewriteOn`.
"""
def rewrite_on!(env) do
if headers = System.get_env(env) do
headers
|> String.split(",")
|> Enum.map(&(&1 |> String.trim() |> rewrite_on!(env)))
else
[]
end
end
defp rewrite_on!("x-forwarded-for", _env), do: :x_forwarded_for
defp rewrite_on!("x-forwarded-host", _env), do: :x_forwarded_host
defp rewrite_on!("x-forwarded-port", _env), do: :x_forwarded_port
defp rewrite_on!("x-forwarded-proto", _env), do: :x_forwarded_proto
defp rewrite_on!(header, env), do: abort!("unknown header #{inspect(header)} given to #{env}")
@doc """ @doc """
Parses and validates the password from env. Parses and validates the password from env.
""" """

View file

@ -95,7 +95,10 @@ defmodule LivebookWeb.Endpoint do
end end
end end
@plug_ssl Plug.SSL.init(host: {Livebook.Config, :force_ssl_host, []}) @plug_ssl Plug.SSL.init(
host: {Livebook.Config, :force_ssl_host, []},
rewrite_on: {Livebook.Config, :rewrite_on, []}
)
def force_ssl(conn, _opts) do def force_ssl(conn, _opts) do
if Livebook.Config.force_ssl_host() do if Livebook.Config.force_ssl_host() do
Plug.SSL.call(conn, @plug_ssl) Plug.SSL.call(conn, @plug_ssl)

View file

@ -106,6 +106,7 @@ defmodule Livebook.MixProject do
{:telemetry_poller, "~> 1.0"}, {:telemetry_poller, "~> 1.0"},
{:jason, "~> 1.0"}, {:jason, "~> 1.0"},
{:bandit, "~> 1.0"}, {:bandit, "~> 1.0"},
{:plug, github: "elixir-plug/plug", override: true},
{:plug_crypto, "~> 2.0"}, {:plug_crypto, "~> 2.0"},
{:earmark_parser, "~> 1.4"}, {:earmark_parser, "~> 1.4"},
{:ecto, "~> 3.10"}, {:ecto, "~> 3.10"},

View file

@ -39,7 +39,7 @@
"phoenix_live_view": {:hex, :phoenix_live_view, "0.20.14", "70fa101aa0539e81bed4238777498f6215e9dda3461bdaa067cad6908110c364", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "82f6d006c5264f979ed5eb75593d808bbe39020f20df2e78426f4f2d570e2402"}, "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.14", "70fa101aa0539e81bed4238777498f6215e9dda3461bdaa067cad6908110c364", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "82f6d006c5264f979ed5eb75593d808bbe39020f20df2e78426f4f2d570e2402"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"}, "phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
"plug": {:hex, :plug, "1.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"}, "plug": {:git, "https://github.com/elixir-plug/plug.git", "0574733fb933e4a2ea78532e38e687d9cffb4858", []},
"plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"}, "plug_cowboy": {:hex, :plug_cowboy, "2.7.1", "87677ffe3b765bc96a89be7960f81703223fe2e21efa42c125fcd0127dd9d6b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "02dbd5f9ab571b864ae39418db7811618506256f6d13b4a45037e5fe78dc5de3"},
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
"protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"}, "protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"},

View file

@ -4,6 +4,14 @@ defmodule Livebook.ConfigTest do
doctest Livebook.Config doctest Livebook.Config
alias Livebook.Config alias Livebook.Config
describe "rewrite_on!/1" do
test "parses headers" do
with_env([TEST_REWRITE_ON: "x-forwarded-for, x-forwarded-proto"], fn ->
assert Config.rewrite_on!("TEST_REWRITE_ON") == [:x_forwarded_for, :x_forwarded_proto]
end)
end
end
describe "node!/1" do describe "node!/1" do
test "parses longnames" do test "parses longnames" do
with_env([TEST_LIVEBOOK_NODE: "test@::1", TEST_LIVEBOOK_DISTRIBUTION: "name"], fn -> with_env([TEST_LIVEBOOK_NODE: "test@::1", TEST_LIVEBOOK_DISTRIBUTION: "name"], fn ->