I’m developing an application that’s going to be (for the forseeable future) installed and managed in a pretty boring, standard way — not using bespoke containerization, clustering, or anything like that.
I’ve currently got this code to manage SECRET_KEY_BASE
, and it seems to work, but it also seems like a really messy hack:
# /config/runtime.exs # … if config_env() == :prod do # … secret_key_base = System.get_env("SECRET_KEY_BASE") || Foo.Application.Util.app_secret_key_auto() # … end
# /lib/foo/util.ex defmodule Foo.Application.Util do # … def app_secret_key_auto do p = Path.expand("secret_key_base.txt", :filename.basedir(:user_config, "foo-app")) # 1. Generate key if it doesn't exist :ok = mkdir_p(Path.expand("..", p)) :ok = case File.open(p, [:write, :exclusive]) do # FIXME surely there must be some built-in tooling for this??? {:error, :eexist} -> :ok # happy path {:ok, h} -> case File.chmod(p, 0o600) do :ok -> # https://github.com/phoenixframework/phoenix/blob/v1.7.17/lib/mix/tasks/phx.gen.secret.ex#L17 data_ascii = (&:crypto.strong_rand_bytes(&1) |> Base.encode64(padding: false) |> binary_part(0, &1)).(64) result = IO.write(h, data_ascii) :ok = File.close(h) result {:error, e} -> :ok = File.close(h) {:error, e} end {:error, e} -> {:error, e} end # 2. load key {:ok, data_ascii} = File.open(p, [:read], &Enum.fetch!(IO.stream(&1, :line), 0)) data_ascii end end
Is there any existing utility function or simple pattern that I should be using instead of this pile of spaghetti, or is Phoenix really just not meant to be used outside of cloud containers?
The documentation didn’t say much about it.