Support `sslmode` in `DATABASE_URL` in CE (#5280)
* sslmode * Update config/runtime.exs --------- Co-authored-by: Cenk Kücük <cenk@plausible.io>
This commit is contained in:
parent
07fbfb0c05
commit
97449613e1
|
|
@ -476,13 +476,48 @@ if db_socket_dir? do
|
|||
password: password
|
||||
end
|
||||
else
|
||||
config :plausible, Plausible.Repo,
|
||||
url: db_url,
|
||||
socket_options: db_maybe_ipv6
|
||||
config :plausible, Plausible.Repo, url: db_url
|
||||
|
||||
if db_cacertfile do
|
||||
config :plausible, Plausible.Repo, ssl: [cacertfile: db_cacertfile]
|
||||
unless Enum.empty?(db_maybe_ipv6) do
|
||||
config :plausible, Plausible.Repo, socket_options: db_maybe_ipv6
|
||||
end
|
||||
|
||||
db_query = URI.decode_query(db_uri.query || "")
|
||||
# https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS
|
||||
pg_sslmode = db_query["sslmode"]
|
||||
|
||||
pg_ssl =
|
||||
cond do
|
||||
db_cacertfile ->
|
||||
[cacertfile: db_cacertfile, verify: :verify_peer]
|
||||
|
||||
pg_sslmode == "verify-full" ->
|
||||
if pg_sslrootcert = db_query["sslrootcert"] do
|
||||
[cacertfile: pg_sslrootcert, verify: :verify_peer]
|
||||
else
|
||||
raise ArgumentError,
|
||||
"PostgreSQL SSL mode `sslmode=#{pg_sslmode}` requires a certificate, set it in `sslrootcert`"
|
||||
end
|
||||
|
||||
pg_sslmode == "verify-ca" ->
|
||||
[cacerts: :public_key.cacerts_get(), verify: :verify_peer]
|
||||
|
||||
pg_sslmode == "require" ->
|
||||
[verify: :verify_none]
|
||||
|
||||
pg_sslmode == "disable" ->
|
||||
false
|
||||
|
||||
pg_sslmode ->
|
||||
raise ArgumentError,
|
||||
"PostgreSQL SSL mode `sslmode=#{pg_sslmode}` is not supported, use `disable`, `require`, `verify-ca` or `verify-full` instead"
|
||||
|
||||
true ->
|
||||
# tls is disabled by default, because in self-hosted docker compose postgres is co-located
|
||||
false
|
||||
end
|
||||
|
||||
config :plausible, Plausible.Repo, ssl: pg_ssl
|
||||
end
|
||||
|
||||
sentry_app_version = runtime_metadata[:version] || app_version
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ defmodule Plausible.ConfigTest do
|
|||
|
||||
assert get_in(config, [:plausible, Plausible.Repo]) == [
|
||||
url: "postgres://postgres:postgres@plausible_db:5432/plausible_db",
|
||||
socket_options: []
|
||||
ssl: false
|
||||
]
|
||||
end
|
||||
|
||||
|
|
@ -500,7 +500,7 @@ defmodule Plausible.ConfigTest do
|
|||
assert get_in(config, [:plausible, Plausible.Repo]) == [
|
||||
url:
|
||||
"postgresql://your_username:your_password@cluster-do-user-1234567-0.db.ondigitalocean.com:25060/defaultdb",
|
||||
socket_options: []
|
||||
ssl: false
|
||||
]
|
||||
end
|
||||
|
||||
|
|
@ -516,8 +516,123 @@ defmodule Plausible.ConfigTest do
|
|||
assert get_in(config, [:plausible, Plausible.Repo]) == [
|
||||
url:
|
||||
"postgresql://your_username:your_password@cluster-do-user-1234567-0.db.ondigitalocean.com:25060/defaultdb",
|
||||
socket_options: [],
|
||||
ssl: [cacertfile: "/path/to/cacert.pem"]
|
||||
ssl: [cacertfile: "/path/to/cacert.pem", verify: :verify_peer]
|
||||
]
|
||||
end
|
||||
|
||||
test "sslmode=require disables peer verification" do
|
||||
env = [
|
||||
{"DATABASE_URL",
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslmode=require"}
|
||||
]
|
||||
|
||||
config = runtime_config(env)
|
||||
|
||||
assert get_in(config, [:plausible, Plausible.Repo]) == [
|
||||
url:
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslmode=require",
|
||||
ssl: [verify: :verify_none]
|
||||
]
|
||||
end
|
||||
|
||||
test "sslmode=disable explicitly disables SSL" do
|
||||
env = [
|
||||
{"DATABASE_URL",
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslmode=disable"}
|
||||
]
|
||||
|
||||
config = runtime_config(env)
|
||||
|
||||
assert get_in(config, [:plausible, Plausible.Repo]) == [
|
||||
url:
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslmode=disable",
|
||||
ssl: false
|
||||
]
|
||||
end
|
||||
|
||||
test "sslmode=verify-ca uses system certificates" do
|
||||
env = [
|
||||
{"DATABASE_URL",
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslmode=verify-ca"}
|
||||
]
|
||||
|
||||
config = runtime_config(env)
|
||||
|
||||
assert get_in(config, [:plausible, Plausible.Repo]) == [
|
||||
url:
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslmode=verify-ca",
|
||||
ssl: [
|
||||
cacerts: :public_key.cacerts_get(),
|
||||
verify: :verify_peer
|
||||
]
|
||||
]
|
||||
end
|
||||
|
||||
test "sslmode=verify-full raises error without certificate" do
|
||||
env = [
|
||||
{"DATABASE_URL",
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslmode=verify-full"}
|
||||
]
|
||||
|
||||
assert_raise ArgumentError,
|
||||
~r/PostgreSQL SSL mode `sslmode=verify-full` requires a certificate/,
|
||||
fn -> runtime_config(env) end
|
||||
end
|
||||
|
||||
test "unsupported sslmode raises error" do
|
||||
env = [
|
||||
{"DATABASE_URL",
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslmode=prefer"}
|
||||
]
|
||||
|
||||
assert_raise ArgumentError, ~r/PostgreSQL SSL mode `sslmode=prefer` is not supported/, fn ->
|
||||
runtime_config(env)
|
||||
end
|
||||
end
|
||||
|
||||
test "verify-full with sslrootcert enables peer verification" do
|
||||
env = [
|
||||
{"DATABASE_URL",
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslmode=verify-full&sslrootcert=/path/to/cert.pem"}
|
||||
]
|
||||
|
||||
config = runtime_config(env)
|
||||
|
||||
assert get_in(config, [:plausible, Plausible.Repo]) == [
|
||||
url:
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslmode=verify-full&sslrootcert=/path/to/cert.pem",
|
||||
ssl: [cacertfile: "/path/to/cert.pem", verify: :verify_peer]
|
||||
]
|
||||
end
|
||||
|
||||
test "sslrootcert alone is not enough for peer verification" do
|
||||
env = [
|
||||
{"DATABASE_URL",
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslrootcert=/path/to/cert.pem"}
|
||||
]
|
||||
|
||||
config = runtime_config(env)
|
||||
|
||||
assert get_in(config, [:plausible, Plausible.Repo]) == [
|
||||
url:
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslrootcert=/path/to/cert.pem",
|
||||
ssl: false
|
||||
]
|
||||
end
|
||||
|
||||
test "DATABASE_CACERTFILE takes precedence over sslrootcert" do
|
||||
env = [
|
||||
{"DATABASE_URL",
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslrootcert=/url/cert.pem"},
|
||||
{"DATABASE_CACERTFILE", "/env/cacert.pem"}
|
||||
]
|
||||
|
||||
config = runtime_config(env)
|
||||
|
||||
assert get_in(config, [:plausible, Plausible.Repo]) == [
|
||||
url:
|
||||
"postgresql://username:password@company.postgres.database.azure.com:5432/prod_plausible?sslrootcert=/url/cert.pem",
|
||||
ssl: [cacertfile: "/env/cacert.pem", verify: :verify_peer]
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue