defmodule ExSecrets.Providers.AwsSecretsManager do
use ExSecrets.Providers.Base
@moduledoc """
This module provides a provider for AWS Secrets Manager - https://aws.amazon.com/secrets-manager/
Code for authenticating with AWS has been has been forked from ex_aws See https://github.com/ex-aws/ex_aws
## Configuration
```elixir
config :ex_secrets, :providers, %{
aws_secrets_manager: %{
access_key_id: "taccess_key_id",
secret_access_key: "secret_access_key"
}
}
```
Its is recomended to create an access key and secret access key for the access key with only the required permissions.
Limiting thye scope of the access key will help in reducing the risk of the access key being compromised.
"""
@process_name :ex_secrets_aws_secrets_manager
def reset() do
:ok
end
def init(_) do
{:ok, %{}}
end
def set(_, _) do
{:error, "set is not supported for AWS Secrets Manager"}
end
def get(name) do
name = name |> String.split("_") |> Enum.join("-")
with process when not is_nil(process) <-
GenServer.whereis(@process_name) do
GenServer.call(@process_name, {:get, name})
else
nil ->
case get_secret(name, %{}, get_current_epoch()) do
{:ok, value, _} -> value
_ -> nil
end
end
end
def get_secret(name, %{}, _) do
with {:ok, secret} <- Utils.AwsRequest.call(name),
value <- get_value(secret) do
{:ok, value, %{}}
else
_err ->
nil
end
end
def handle_call({:get, name}, _from, state) do
case get_secret(name, state, get_current_epoch()) do
{:ok, secret, state} -> {:reply, secret, state}
_ -> {:reply, nil, state}
end
end
defp get_current_epoch() do
DateTime.utc_now() |> DateTime.to_unix()
end
def process_name() do
@process_name
end
defp get_value("{" <> _ = value) do
with {:ok, data} <- Jason.decode(value),
[key] <- Map.keys(data) do
data[key]
else
_err ->
value
end
end
defp get_value(value), do: value
end