I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management service but I’m not finding any. Ideally I’d be able to switch from say Google Cloud KMS to AWS KMS seamlessly with minimal configuration.
I’ve thought about open sourcing something that does this but I’m hesitant to create yet another project that may or may not be useful so I figure I’d check here first!
I already have a Google KMS adapter written using the elixir-google-api library and the following interface:
defmodule KMS do
@type key_details :: KMS.KeyDetails.t()
@type public_key :: JOSE.JWK.t()
@type list_keys_response :: {:ok, [key_details]} | {:error, any}
@type public_key_response :: {:ok, public_key} | {:error, any}
@type sign_response :: {:ok, KMS.Signature.t()} | {:error, any}
@client Application.compile_env!(:my_app, [__MODULE__, :client])
@callback list_keys(opts :: keyword) :: list_keys_response
@callback get_public_key(key_id :: String.t(), opts :: keyword) :: public_key_response
@callback sign(String.t(), key_id :: String.t(), opts :: keyword) :: sign_response
@spec list_keys(keyword) :: list_keys_response
def list_keys(opts), do: @client.list_keys(opts)
@spec list_keys!(keyword) :: [key_details]
def list_keys!(opts) do
case list_keys(opts) do
{:ok, keys} -> keys
{:error, error} -> raise KMS.NoKeyDetailsFoundError, message: "#{inspect(error)}"
end
end
@spec get_public_key(String.t(), keyword) :: public_key_response
def get_public_key(key_id, opts), do: @client.get_public_key(key_id, opts)
@spec get_public_key!(String.t(), keyword) :: public_key
def get_public_key!(key_id, opts) do
case get_public_key(key_id, opts) do
{:ok, public_key} -> public_key
{:error, error} -> raise KMS.NoPublicKeyFoundError, message: "#{inspect(error)}"
end
end
@spec sign(String.t(), String.t(), keyword) :: sign_response
def sign(message, key_id, opts), do: @client.sign(message, key_id, opts)
end