# SopsConfigProvider
Decrypt secrets from sops file and set the config to your application on
runtime.
## Installation
The package can be installed
by adding `sops_config_provider` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:sops_config_provider, "~> 0.1.0"}
]
end
```
## Usage
**[ATTENTION] Please make sure that you have sops installed, and proper permission
to encrypt and decrypt the file. See [SOPS docs](https://github.com/mozilla/sops)
for sops intallation and setup**
After the installation, you need to add the provider into `def project` section in
`mix.exs`.
```elixir
releases: [
change_with_your_app_name: [
config_providers: [
{
SopsConfigProvider,
%{
app_name: :change_with_your_app_name,
secret_file_path: "priv/secrets.yml" # I'd recommend to put
# the secrets inside the priv directory, as it automatically get
# copied on release
}
}
]
]
]
```
The config provider will decrypt the secrets and set the config like you do in
runtime.exs
For example, if you have secrets config in yaml as below
```yaml
# priv/secrets.yml
sentry:
dsn: "https://sentry.io"
```
It'll set the value below and app boot like on `runtime.exs`
```elixir
config :sentry, dsn: "http://sentry.io"
```
## Options
Pass options as a map (second element of the tuple) in `config_providers`.
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `app_name` | `atom` | yes | — | Your app name. Used to resolve `secret_file_path` via `Application.app_dir/2`. |
| `secret_file_path` | `string` | yes | — | Path to the SOPS-encrypted file relative to the app dir. Supports `.json`, `.yaml`, `.yml`. |
| `sops_binary_path` | `string` | no | `"sops"` | Path to the `sops` binary. Override if sops is not on `PATH`. |
| `execution_dir` | `string` | no | `"./"` | Working directory used when running `sops -d`. Relevant when sops resolves key config (e.g., `.sops.yaml`) relative to cwd. |
| `env_variables` | `[{string, string}]` | no | `[]` | Environment variables injected into the sops process. Useful for passing AWS/GCP credentials at runtime. |
| `mappings` | `map` | no | `%{}` | Remap flat secret keys into nested module configs. See [Mappings](#mappings) below. |
| `env_override` | `boolean` | no | `false` | Allow OS env vars to override decrypted SOPS values. See [Env Override](#env-override) below. |
| `config_env` | `atom` | no | `:prod` | Config environment. |
### Mappings
`mappings` lets you nest a secret key under a specific module within an app's config.
Structure:
```elixir
%{
app_atom => %{
secret_key => {TargetModule, :nested_key}
}
}
```
Example — map `:db_url` in `:my_app` into `{MyApp.Repo, :url}`:
```elixir
{
SopsConfigProvider,
%{
app_name: :my_app,
secret_file_path: "priv/secrets.yml",
mappings: %{
my_app: %{
db_url: {MyApp.Repo, :url}
}
}
}
}
```
Given this secret file:
```yaml
my_app:
db_url: "ecto://user:pass@localhost/mydb"
other_key: "value"
```
Produces:
```elixir
config :my_app, MyApp.Repo, url: "ecto://user:pass@localhost/mydb"
config :my_app, other_key: "value"
```
### Env Override
Set `env_override: true` to allow OS environment variables to override values from the SOPS file. Useful for emergency overrides or per-deploy flexibility without re-encrypting the secrets file.
**Naming convention:** `APP_KEY` — the app atom and config key joined with `_`, uppercased.
| YAML key | App | Derived env var |
|---|---|---|
| `api_key` | `stripity_stripe` | `STRIPITY_STRIPE_API_KEY` |
| `dsn` | `sentry` | `SENTRY_DSN` |
| `password` | `orca` | `ORCA_PASSWORD` |
| `webhook` | `slack` | `SLACK_WEBHOOK` |
Only flat atom keys are overridable. Nested module keys (set via `mappings`) are not derived and must be changed via the SOPS file.
An env var is ignored if it is not set or is an empty string — the SOPS value is used as-is.
```elixir
{
SopsConfigProvider,
%{
app_name: :my_app,
secret_file_path: "priv/secrets.yml",
env_override: true,
mappings: %{
my_app: %{
database_url: {MyApp.Repo, :url}
}
}
}
}
```
With this config, setting `SENTRY_DSN=https://new-dsn` as an OS env var overrides the `sentry > dsn` value from the SOPS file at runtime. No re-encryption needed.
### env_variables example
Pass AWS credentials when the runtime environment doesn't have them on the system:
```elixir
{
SopsConfigProvider,
%{
app_name: :my_app,
secret_file_path: "priv/secrets.yml",
env_variables: [
{"AWS_ACCESS_KEY_ID", System.get_env("AWS_ACCESS_KEY_ID")},
{"AWS_SECRET_ACCESS_KEY", System.get_env("AWS_SECRET_ACCESS_KEY")}
]
}
}