Skip to content

Commit

Permalink
chore(database): Add ssl support
Browse files Browse the repository at this point in the history
Adds ssl/tls support for the edgehog <-> database communication.
Closes edgehog-device-manager#419.

Signed-off-by: Luca Zaninotto <[email protected]>
  • Loading branch information
lusergit committed Dec 13, 2024
1 parent ad4cb42 commit a1f622e
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 10 deletions.
16 changes: 16 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ IPBASE_API_KEY=
GOOGLE_GEOLOCATION_API_KEY=
GOOGLE_GEOCODING_API_KEY=

# Wether to use SSL/TLS connection to the database, defaults to `false`.
DATABASE_ENABLE_SSL=false

# Whether to use the host machine certificates or not to verify the connection
# with the database.
# DATABASE_USE_OS_CERTS=true

# The CA certificate file to use to verify the TLS connection to the database.
# DATABASE_SSL_CACERTFILE=./example_cacert.pem

# Whether verify the SSL connection with the database or not.
# DATABASE_SSL_VERIFY=true

# The server name indication for the SSL connection with the database.
# DATABASE_SERVER_NAME_INDICATION=https://www.example.com

# The top level domain of your edgehog instance.
# In case you want to make Edgehog visible in your LAN, consider setting the variable
# to <HOST_IP>.nip.io
Expand Down
97 changes: 87 additions & 10 deletions backend/config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,86 @@ end
# any compile-time configuration in here, as it won't be applied.
# The block below contains prod specific runtime configuration.
if config_env() == :prod do
database_username = System.fetch_env!("DATABASE_USERNAME")
database_password = System.fetch_env!("DATABASE_PASSWORD")
database_hostname = System.fetch_env!("DATABASE_HOSTNAME")
database_name = System.fetch_env!("DATABASE_NAME")
database = %{
username: System.fetch_env!("DATABASE_USERNAME"),
password: System.fetch_env!("DATABASE_PASSWORD"),
hostname: System.fetch_env!("DATABASE_HOSTNAME"),
name: System.fetch_env!("DATABASE_NAME"),
ssl_enable: System.fetch_env!("DATABASE_ENABLE_SSL"),
# with ssl_enable = false no additional config is required
ssl_opts: nil
}

database =
if database.ssl_enable == "true" do
use_os_certs =
case System.get_env("DATABASE_USE_OS_CERTS") || "false" do
"true" ->
true

"false" ->
false

other ->
raise """
invalid database SSL configuration:
unknown value `#{other}` for variable DATABASE_USE_OS_CERTS.
"""
end

certfile = System.get_env("DATABASE_SSL_CACERTFILE")

cert_config =
case {certfile, use_os_certs} do
{nil, false} ->
raise """
invalid database SSL configuration:
either set DATABASE_USE_OS_CERTS true to use system's certificates
or provide a CA certificate file with DATABASE_SSL_CACERTFILE.
The latter will take precedence.
"""

{nil, true} ->
{:cacerts, :public_key.cacerts_get()}

{file, _} ->
# Assuming `file` is a file path
{:cacertfile, file}
end

# Found conflicting informations on this. According to the documentation it
# can default to the `Host` argument of `connect/3,4`
# (see "https://www.erlang.org/doc/apps/ssl/ssl.html#t:client_option_cert/0")
# so it is acceptable to levae it as `nil` by default
server_name_indication =
{:server_name_indication, "DATABASE_SERVER_NAME_INDICATION" |> System.get_env() |> to_charlist()}

verify =
case System.get_env("DATABASE_SSL_VERIFY") || "false" do
"true" ->
{:verify, :verify_peer}

"false" ->
{:verify, :verify_none}

_ ->
raise """
invalid database SSL configuration, DATABASE_SSL_VERIFY can be set to `true`
to verify TLS certificates or `false` to skip verification
"""
end

opts = [
cert_config,
verify,
server_name_indication
]

# add config to the database map
Map.put(database, :ssl_opts, opts)
else
database
end

# The secret key base is used to sign/encrypt cookies and other secrets.
# A default value is used in config/dev.exs and config/test.exs but you
Expand Down Expand Up @@ -102,13 +178,14 @@ if config_env() == :prod do
forwarder_hostname = System.get_env("EDGEHOG_FORWARDER_HOSTNAME")

config :edgehog, Edgehog.Repo,
# ssl: true,
# socket_options: [:inet6],
username: database_username,
password: database_password,
hostname: database_hostname,
database: database_name,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
username: database.username,
password: database.password,
hostname: database.hostname,
database: database.name,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
ssl: database.ssl_enable,
ssl_opts: database.ssl_opts

config :edgehog, EdgehogWeb.Endpoint,
http: [
Expand Down

0 comments on commit a1f622e

Please sign in to comment.