Are there any generic KMS libraries out there?

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

I don’t know if there is one for KMS - but you may use adapter pattern (like Tesla for HTTP client) to have general interface and specific implementation modules.

However I’m not sure we can have a good abstraction of KMS; I’ve used three KMS but they are slightly different - especially auth and details on options. I’ve built own domain/context module for my abstraction/policy etc. wrapping existing library instead of making generic wrapper for all KMS provider for that reason.

Do you have any similar libraries for KMS in other languages?

However I’m not sure we can have a good abstraction of KMS; I’ve used three KMS but they are slightly different - especially auth and details on options. I’ve built own domain/context module for my abstraction/policy etc. wrapping existing library instead of making generic wrapper for all KMS provider for that reason.

I’m also unsure whether there’s a good abstraction for KMS. As I’ve mentioned, I’ve been able to switch from Google Cloud to AWS without any change to the core KMS interface. Auth details do vary but I think those are more implementation details of the specific cloud provider and I think aren’t concerns for the core interface.

Do you have any similar libraries for KMS in other languages?

Not that I’m aware of.