Current section

Files

Jump to
elixir_structure_manager priv templates adapters secrets_manager secret_adapter.ex
Raw

priv/templates/adapters/secrets_manager/secret_adapter.ex

defmodule {app}.Infrastructure.Adapters.Secrets.SecretManagerAdapter do
alias {app}.Config.{ConfigHolder, AppConfig}
alias {app}.Utils.DataTypeUtils
require Logger
@compile if Mix.env() == :test, do: :export_all
@behaviour {app}.Config.ConfigHolder.PropertiesLoaderBehaviour
@moduledoc """
Provides functions for handle secrets from AWS
"""
@impl true
def load(%AppConfig{env: env, secret_name: secret_name}) do
if env == :prod do
Logger.info("Loading secret #{secret_name} from AWS Secrets Manager")
secret = get_secret(secret_name)
# TODO: Load another cacheable secrets here
%{secret: secret}
else
%{}
end
end
def get_secret(secret_name, cached \\ true)
def get_secret(secret_name, true = _cached) do
case ConfigHolder.get(secret_name) do
{:ok, secret} ->
secret
_ ->
load_and_cache(secret_name)
end
end
def get_secret(secret_name, false = _cached) do
get_secret_value(secret_name) |> parse_secret()
end
defp load_and_cache(secret_name) do
secret = get_secret_value(secret_name) |> parse_secret()
ConfigHolder.set(secret_name, secret)
secret
end
defp get_secret_value(secret_name) do
cfg = ExAws.Config.build_base(:secretsmanager)
region = ExAws.Config.retrieve_runtime_value(cfg.region, cfg)
ExAws.SecretsManager.get_secret_value(secret_name)
|> ExAws.request(region: region)
|> case do
{:ok, %{"SecretString" => secret_string}} -> secret_string
{code, rs} -> {code, rs}
end
end
defp parse_secret(secret_string) do
secret_string
|> Poison.decode!()
|> DataTypeUtils.normalize()
end
end