diff --git a/.env b/.env index 264215f0b..6a0b8d907 100644 --- a/.env +++ b/.env @@ -22,6 +22,19 @@ 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 top level domain of your edgehog instance. # In case you want to make Edgehog visible in your LAN, consider setting the variable # to .nip.io diff --git a/backend/config/runtime.exs b/backend/config/runtime.exs index efeb95621..550020a36 100644 --- a/backend/config/runtime.exs +++ b/backend/config/runtime.exs @@ -31,10 +31,13 @@ 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: Config.database_ssl_config() + } # 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 @@ -102,13 +105,13 @@ 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 config :edgehog, EdgehogWeb.Endpoint, http: [ diff --git a/backend/lib/edgehog/config.ex b/backend/lib/edgehog/config.ex index c5dbcb8d6..a24132e69 100644 --- a/backend/lib/edgehog/config.ex +++ b/backend/lib/edgehog/config.ex @@ -43,6 +43,30 @@ defmodule Edgehog.Config do os_env: "ADMIN_JWT_PUBLIC_KEY_PATH", type: JWTPublicKeyPEMType + @envdoc "Whether edgehog should use a tls connection with the database or not." + app_env :database_enable_ssl, :edgehog, :database_enable_ssl, + os_env: "DATABASE_ENABLE_SSL", + type: :boolean, + default: false + + @envdoc "The certificate file to use to verify the ssl connection with the database." + app_env :database_ssl_cacertfile, :edgehog, :database_ssl_cacertfile, + os_env: "DATABASE_SSL_CACERTFILE", + type: :binary, + default: "" + + @envdoc "Whether to use the os certificates to communicate with the database over ssl." + app_env :database_use_os_certs, :edgehog, :database_use_os_certs, + os_env: "DATABASE_USE_OS_CERTS", + type: :boolean, + default: false + + @envdoc "Whether to verify the ssl connection with the database or not." + app_env :database_ssl_verify, :edgehog, :database_ssl_verify, + os_env: "DATABASE_SSL_VERIFY", + type: :boolean, + default: false + @envdoc """ Disables tenant authentication. CHANGING IT TO TRUE IS GENERALLY A REALLY BAD IDEA IN A PRODUCTION ENVIRONMENT, IF YOU DON'T KNOW WHAT YOU ARE DOING. """ @@ -94,6 +118,71 @@ defmodule Edgehog.Config do @spec admin_authentication_disabled?() :: boolean() def admin_authentication_disabled?, do: disable_admin_authentication!() + @doc """ + Returns true if edgehog should use an ssl connection with the database. + """ + @spec database_enable_ssl?() :: boolean() + def database_enable_ssl?, do: database_enable_ssl!() + + @doc """ + Reutrns whether to verify the ssl connection witht he database or not. + """ + @spec database_ssl_verify?() :: boolean() + def database_ssl_verify?, do: database_ssl_verify!() + + @doc """ + Returns true if edgehog should use the operative system certificates. + """ + @spec database_use_os_certs?() :: boolean() + def database_use_os_certs?, do: database_use_os_certs!() + + @doc """ + Returns the ssl configuration for the ssl connection with the database. + """ + @spec database_ssl_cert_config() :: {:cacerts, [term()]} | {:cacertfile, binary()} + def database_ssl_cert_config do + use_os_certs = database_use_os_certs?() + + certfile = System.get_env("DATABASE_SSL_CACERTFILE") + + 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 + end + + @doc """ + Returns the Ecto configuration for the ssl connection to the database. + """ + @spec database_ssl_config_opts() :: list(term()) + def database_ssl_config_opts do + if database_ssl_verify?(), + do: [{:verify, :verify_peer}, database_ssl_cert_config()], + else: [verify: :verify_none] + end + + @doc """ + Returns the database configuration for the database connection. + """ + @spec database_ssl_config() :: false | list(term()) + def database_ssl_config do + if database_enable_ssl?(), + do: database_ssl_config_opts(), + else: false + end + @doc """ Returns true if tenant authentication is disabled. """