SOPS: Secrets OPerationS
The SOPS provider integrates with SOPS to enable reading and writing of secrets encrypted at rest in local files.
Prerequisites
Section titled “Prerequisites”- The SOPS CLI available within the environment:
- Manually download a release binary
- Use the SOPS Nix package
-
Install with a package manager:
Terminal window # Homebrew$ brew install sops# Arch$ sudo pacman -S sops
Configuration
Section titled “Configuration”URI Format
Section titled “URI Format”sops://path/to/secret[?key=value[&key=value]...]-
path/to/secret— required path to the encrypted file (absolute or relative) -
?key=value— optional query parameter, refer to the Query Parameters section for available parameters. -
&key=value— additional parameters
Query Parameters
Section titled “Query Parameters”Excepting the SecretSpec-specific format parameter, refer to the SOPS documentation for the purpose and usage of each parameter.
SecretSpec
Section titled “SecretSpec”| Provider URL Query Parameter Name | Purpose |
|---|---|
| format | Overrides the extension-based file format detection. Valid values: dotenv env ini json yaml |
| Provider URL Query Parameter Name | Corresponding Environment Variable |
|---|---|
| sops_config | SOPS_CONFIG |
| sops_decryption_order | SOPS_DECRYPTION_ORDER |
| sops_editor | SOPS_EDITOR |
| sops_enable_local_keyservice | SOPS_ENABLE_LOCAL_KEYSERVICE |
| sops_keyservice | SOPS_KEYSERVICE |
| Provider URL Query Parameter Name | Corresponding Environment Variable |
|---|---|
| age_key_cmd | SOPS_AGE_KEY_CMD |
| age_key_file | SOPS_AGE_KEY_FILE |
| age_recipients | SOPS_AGE_RECIPIENTS |
| age_ssh_private_key_cmd | SOPS_AGE_SSH_PRIVATE_KEY_CMD |
| age_ssh_private_key_file | SOPS_AGE_SSH_PRIVATE_KEY_FILE |
| Provider URL Query Parameter Name | Corresponding Environment Variable |
|---|---|
| aws_access_key_id | AWS_ACCESS_KEY_ID |
| aws_profile | AWS_PROFILE |
| aws_region | AWS_REGION |
| kms_arn | SOPS_KMS_ARN |
| Provider URL Query Parameter Name | Corresponding Environment Variable |
|---|---|
| gcp_kms_client_type | SOPS_GCP_KMS_CLIENT_TYPE |
| gcp_kms_endpoint | SOPS_GCP_KMS_ENDPOINT |
| gcp_kms_ids | SOPS_GCP_KMS_IDS |
| gcp_kms_universe_domain | SOPS_GCP_KMS_UNIVERSE_DOMAIN |
| Provider URL Query Parameter Name | Corresponding Environment Variable |
|---|---|
| azure_client_id | AZURE_CLIENT_ID |
| azure_keyvault_urls | SOPS_AZURE_KEYVAULT_URLS |
| azure_tenant_id | AZURE_TENANT_ID |
| Provider URL Query Parameter Name | Corresponding Environment Variable |
|---|---|
| pgp_fp | SOPS_PGP_FP |
| Provider URL Query Parameter Name | Corresponding Environment Variable |
|---|---|
| gpg_exec | SOPS_GPG_EXEC |
Hashicorp Vault/OpenBao
Section titled “Hashicorp Vault/OpenBao”| Provider URL Query Parameter Name | Corresponding Environment Variable |
|---|---|
| hc_vault_addr | VAULT_ADDR |
| hc_vault_allowlist | SOPS_HC_VAULT_ALLOWLIST |
Huawei Cloud
Section titled “Huawei Cloud”| Provider URL Query Parameter Name | Corresponding Environment Variable |
|---|---|
| huawei_kms_ids | SOPS_HUAWEICLOUD_KMS_IDS |
| huawei_sdk_project_id | HUAWEICLOUD_SDK_PROJECT_ID |
Provider credentials
Section titled “Provider credentials”Secret values used to authenticate SOPS belong in a provider alias’s
credentials map, not in the SOPS URI.
| Credential | Environment fallback | Available since |
|---|---|---|
age_key | SOPS_AGE_KEY | 0.17+ |
aws_secret_access_key | AWS_SECRET_ACCESS_KEY | 0.17+ |
azure_client_secret | AZURE_CLIENT_SECRET | 0.17+ |
hc_vault_token | VAULT_TOKEN | 0.17+ |
huawei_sdk_ak | HUAWEICLOUD_SDK_AK | 0.17+ |
huawei_sdk_sk | HUAWEICLOUD_SDK_SK | 0.17+ |
google_oauth_access_token | GOOGLE_OAUTH_ACCESS_TOKEN | 0.17+ |
See the complete provider credential reference for all supported providers and environment fallbacks.
For example, this alias loads an age identity from the system keyring and passes it only to the SOPS child process:
[providers.sops_age]uri = "sops://secrets.enc.yaml?age_recipients=age1example"
[providers.sops_age.credentials]age_key = "keyring"
[profiles.production.defaults]providers = ["sops_age"]When a credential is not declared on the alias, SOPS can still use its normal environment variable.
Storage layout
Section titled “Storage layout”The URI shape determines the on-disk layout. This matters when editing a file
with sops directly and when diagnosing a value set under the wrong profile.
For a single YAML or JSON file, convention-addressed secrets are written at
[project][profile][key]. For example,
secretspec set API_KEY --profile production in project my-app writes:
my-app: production: API_KEY: secret-valueThe equivalent selector passed to sops set is
["my-app"]["production"]["API_KEY"]. Reads also retain compatibility with
older [profile][key] and root [key] layouts, but new convention writes use
the fully namespaced path.
For a templated YAML or JSON URI, {project} and {profile} already select
the file, so the key is flat inside it:
[providers]prod_sops = "sops://secrets/{project}/{profile}.enc.yaml"API_KEY: secret-valueSingle-file dotenv is always a flat API_KEY=value document. Single-file INI
uses the selected profile as its section; templated INI uses [DEFAULT] because
the profile is already represented by the filename. The following table is the
write layout:
| Format | Single file | Templated path |
|---|---|---|
| YAML / JSON | [project][profile][key] | root [key] |
| dotenv | root [key] | root [key] |
| INI | [profile][key] | [DEFAULT][key] |
In SecretSpec 0.19+, set prints the resolved provider URI, profile, file, and
selector before it prompts for or writes the value. This makes an accidentally
omitted --profile visible before the encrypted file changes.
Format handling
Section titled “Format handling”SecretSpec asks SOPS to emit JSON when decrypting, then uses one lookup path
for YAML, JSON, dotenv, and INI files. When ?format= is present, SecretSpec
also passes the corresponding SOPS input type so filenames such as
.env.production.enc?format=dotenv work correctly.
SOPS does not support --input-type ini, so ?format=ini is accepted only
when the filename itself ends in .ini. Without ?format=, the filename must
end in .yaml, .yml, .json, .env, .dotenv, or .ini; an unrecognized
extension is reported as a configuration error.
In a single dotenv file, the same key cannot hold different values for
different profiles. Use a templated path such as
secrets/{project}/.env.{profile}.enc?format=dotenv when profiles need
separate dotenv values.
Secret references
Section titled “Secret references”SOPS supports ref = { item = "..." } against a single-file provider URI.
The item names a root key and does not add the project/profile convention path:
[providers]shared_sops = "sops://shared.enc.yaml"
[profiles.production]EXTERNAL_TOKEN = { description = "Token already managed in shared.enc.yaml", ref = { item = "existing_token" }, providers = ["shared_sops"] }This reads or writes root selector ["existing_token"]. SOPS documents hold
single values at each key, so field and other extra ref coordinates are
rejected. A templated SOPS URI also rejects refs: without convention
project/profile inputs, SecretSpec cannot choose which templated file the
external root key belongs to. See Secret References for
the general model.
Set a secret with age
Section titled “Set a secret with age”$ secretspec set DATABASE_URL --provider 'sops://secrets.enc.json?age_key_file=key.txt&age_recipients=age1jpa8rf5qmrg6pw444fcgpkaxg8x4neueszrexzagdjpunjlgeyzq304w34'Or, if keys.txt exists in a place discoverable by SOPS and .sops.yaml
exists next to the project’s secretspec.toml, configure a creation rule:
creation_rules: - path_regex: secrets\.enc\.json$ age: "age1jpa8rf5qmrg6pw444fcgpkaxg8x4neueszrexzagdjpunjlgeyzq304w34"then:
$ secretspec set DATABASE_URL --provider sops://secrets.enc.json