Keeps the encryption secret in more than one place at once.
This is what makes a remote store an addition rather than a foundation. Configure the local file first and something remote second, and the secret is written to both while every read is served by the local one:
config :phoenix_kit,
integrations_key_store:
{PhoenixKit.Integrations.KeyStore.Chain,
stores: [
PhoenixKit.Integrations.KeyStore.File,
{PhoenixKit.Integrations.KeyStore.S3, bucket: "my-ops-bucket"}
]}A PhoenixKit install that wants nothing remote configures nothing and loses nothing: the file store on its own remains the default and the whole feature is opt-in. Requiring an AWS account before someone can use integrations at all would be the wrong shape, and this is the shape that avoids it.
Reading
The first store that has the secret answers. A later store answering when an
earlier one did not is the recovery case — the local file was lost and the
remote copy saved it — so it is reported at :warning rather than passing
silently: the operator should know the primary is empty before the remote one
is also gone.
Writing
Every store is written, and the read-back verification in
PhoenixKit.Integrations.KeyStore.write_verified/1 then checks the chain,
which by definition checks the first store. A failure in any store is
reported: a backup that quietly stopped being written is not a backup, and
finding out during a recovery is finding out too late.
What this deliberately does not do
It does not fall back to a later store on write failure, and it does not
hide a partial success behind an :ok. Both would produce the single
situation this whole area exists to prevent — believing the secret is safe
somewhere it is not.
Summary
Functions
The configured members, normalised to {module, opts}.