SOPS (Secrets OPerationS) encryption allows you to securely store sensitive values like passwords, API keys, and credentials in your GitOps repository. Encrypted values are automatically decrypted during deployment.
What is SOPS?
SOPS is an editor for encrypted files that supports YAML, JSON, ENV, INI and BINARY formats. Ankra uses SOPS with AGE encryption to protect sensitive values in your Stack configurations.How It Works
- In the Stack Builder: You enter the value in plaintext and list its key under Encrypted Keys (SOPS)
- In Ankra: The control plane stores the value as you entered it, together with the list of keys to seal. Listing a key does not encrypt the value inside Ankra
- On every push to Git: Ankra seals the listed keys with your organisation’s AGE public key, so your repository only ever receives
ENC[AES256_GCM,...]for them - On Deploy: The Ankra agent decrypts inside your cluster - directly with
sopson the native engine, or through ArgoCD’s helm-secrets plugin on the ArgoCD engine (see Deployment Engines)
Because sealing happens at the push, the Stack Builder shows the value you typed, not ciphertext, including after you save and reopen it. That is expected. What protects the value is that it is never written to Git unsealed: a push that cannot seal a listed key is refused instead of committed. To confirm a value is sealed, look at the file in your Git repository.
Getting Started
Setting up SOPS encryption is a single step. Once initialized, encryption is enabled by default and cluster decryption is handled automatically.1
Navigate to Encryption Settings
Go to Organisation Settings → Encryption.
2
Initialize Encryption
Click Initialize Encryption. This generates an AGE key pair:
- Public key: Used to encrypt values (visible to you)
- Private key: Used to decrypt values (stored securely in Ankra’s secret store)
- Encryption is enabled by default - fields you mark as encrypted will be protected immediately.
- Cluster decryption is automatic - on the native engine the agent requests the key from Ankra when it deploys a sealed value, and on the ArgoCD engine Ankra installs the key into the cluster for helm-secrets. There is nothing to configure per-cluster.
age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p
Encrypting Values in Stacks
Using the Stack Builder
When editing a manifest or add-on values in the Stack Builder:- Look for the Encrypted Keys (SOPS) section
- Add key names that should be encrypted (e.g.,
password,apiKey,token) - Enter the plaintext value as normal
- Save. Ankra seals those specific keys every time it writes the file to your Git repository
Common Keys to Encrypt
Example: Encrypting a Database Password
Before encryption (what you see in the editor):Example: Encrypting a Registry Pull Secret (.dockerconfigjson)
A kubernetes.io/dockerconfigjson Secret stores its payload under a key whose
name literally begins with a dot: .dockerconfigjson. Add that key, leading dot
included, to the Encrypted Keys (SOPS) list (or pass --key .dockerconfigjson
to the CLI). The leading dot marks it as a literal key name rather than a nested
dotted path, so it is matched and encrypted as-is.
Encrypting Helm Values
For add-ons (Helm charts), you can encrypt specific values:- Open the add-on in the Stack Builder
- In the values editor, find the Encrypted Keys (SOPS) section
- Add paths to sensitive values
Helm Values Path Examples
Example: Encrypting Grafana admin password
adminPassword to the encrypted keys list.
What an Entry Actually Matches
Dot notation tells Ankra which key you mean; it does not confine the encryption to that one place in the file. Ankra compiles the entries into a SOPSencrypted_regex built from the key names, and SOPS applies that regex to
every key at every depth of the document. A dotted entry contributes its last
segment as one of those names. So an entry auth.password names the key
password, and every key called password in that file is sealed -
auth.password, backups.password, and any other.
That is usually what you want, and it is why a key added under a new section
next month is sealed without changing the declaration. It becomes a problem when
the key name is not unique to your secret.
Encrypting Keys by Pattern
An entry in the Encrypted Keys (SOPS) list is normally a literal key name, matched exactly. Prefix an entry withglob: to seal every key whose name matches a pattern instead - including keys added to the document later:
Pattern Rules
glob:is the opt-in. Entries without the prefix keep their exact-match meaning, so a literal key name that contains a dot (cloud.conf,.dockerconfigjson) is never reinterpreted as a pattern.- Only
*is a wildcard. It matches any run of characters, including none. Every other character is literal. - A pattern describes a key name, not a path. SOPS matches key names at every depth of the document, so
glob:DB_*seals a top-levelDB_PASSWORDand a nestedbackups.DB_PASSWORDalike. - A leading
data.orstringData.section is accepted and stripped, the same as for a literal entry:glob:stringData.DB_*andglob:DB_*select the same keys. - The entry is stored as written.
encrypted_pathskeepsglob:stringData.DB_*verbatim, and Ankra re-expands it into the SOPSencrypted_regexon every push. A key added to the document next month is sealed by the same rule, with no change to the declaration - and because the rule lives in the SOPS metadata, a key you seal by hand with thesopseditor is matched the same way.
DB_ key of a Secret with glob:stringData.DB_*
Rejected Patterns
A pattern that cannot mean what was intended is rejected when you save, with an error naming the entry and the reason (over the API this is an HTTP 422, for exampleInvalid encrypted_paths entry "glob:password": contains no * wildcard; declare an exact key name without the glob: prefix):
A valid pattern that matches zero keys fails later, at encrypt or push time, exactly like a misspelled literal key: rather than write a file that only looks encrypted, Ankra refuses with an error such as
declared encrypted_paths [glob:DB_*] match no key in this document, so sops encrypted nothing. Fix the pattern (or add the keys it should match) and save again.
An Empty or Absent Declaration
What keeps a file sealed on a platform write is its declaration. Ankra seals the file fromencrypted_paths on every push it makes, and a manifest or add-on with no entries is written as plain content.
- No entries, no checks. Every check on a declaration runs on the entries it carries. The store-time guard, the
match no key in this documentrefusal and the over-match warningankra cluster validatereports (categoryencrypted_paths_over_match) are all skipped when there are none; only plaintext-secret detection still runs, on the content itself. Silence from those checks on a resource with an empty declaration is not evidence that its file is sealed. - Over the API,
[]and an absent key mean different things. On an update, omittingencrypted_pathskeeps the stored declaration; sendingencrypted_paths: []replaces it with nothing. If the file is sealed in your repository, the next platform write renders it as plain content and overwrites the sealed copy. Send the key only when you mean to set the declaration. - The CLI drops an empty list.
ankra cluster applysendsencrypted_pathsonly when it has entries, so[]in a cluster YAML applied with the CLI behaves like an absent key and keeps whatever is stored. A sealedfrom_fileis sent as it is on disk; when no declaration is stored for it, the apply is refused withcontent is SOPS-encrypted but encrypted_paths is empty. - In a Git repository Ankra syncs, the file wins. When Ankra reads the cluster directory, the declaration for a sealed file is derived from its
sopsmetadata and replaces whatever the cluster YAML declares; the cluster YAML is rewritten with the derived entries on the next platform write. The cluster YAML Ankra renders listsencrypted_paths: []for every add-on and manifest without a declaration, so that line on its own only says that nothing is declared.
Using the CLI
You can also encrypt and decrypt values using the Ankra CLI for local GitOps workflows.Encrypting Manifest Values
- Find the manifest in the cluster YAML
- Read the referenced manifest file
- Encrypt the specified key using your organisation’s SOPS key
- Update the manifest file with encrypted values
- Add the key to
encrypted_pathsin the cluster YAML
Encrypting Addon Values
Encrypting Keys by Pattern with the CLI
--key also accepts the glob: pattern form described in Encrypting Keys by Pattern:
encrypted_paths as written, so keys added later are sealed automatically the next time the values are encrypted. A pattern that matches no key fails the same way a misspelled exact key does. See ankra cluster encrypt for the full flag reference.
Decrypting for Inspection
To view the decrypted contents of a manifest file:Adding Keys to Existing Encrypted Files
You can add new encrypted keys to files that are already SOPS-encrypted:How Decryption Works
Your organisation’s AGE private key is kept in Ankra’s secret store. How a cluster uses it depends on the deployment engine of the add-on or manifest being deployed.Native engine
The Ankra agent decrypts sealed values itself. When a deploy reaches a sealed file, the agent requests the organisation’s private key from Ankra, runssops --decrypt inside your cluster, and hands the result to Helm or applies the manifest. Nothing is installed in the cluster beforehand and there is no per-cluster setup. This is the default engine for clusters created since May 2026.
ArgoCD engine
On clusters that use ArgoCD, Ankra configures ArgoCD to decrypt during Helm template rendering:- Deploys the AGE private key as a Kubernetes Secret in the ArgoCD namespace
- Configures helm-secrets plugin on the ArgoCD repo-server
- Sets up automatic decryption during Helm template rendering
The helm-secrets plugin is automatically configured with:
HELM_SECRETS_BACKEND=sops- Use SOPS for decryptionSOPS_AGE_KEY_FILE=/ankra-sops-age-key/age.agekey- Path to the private key- Support for
secrets://value file scheme
Troubleshooting
Deployment Fails with Decryption Error
Deployment Fails with Decryption Error
- Verify SOPS is initialized at the organisation level (Organisation Settings → Encryption)
- Ensure the content was encrypted with the current organisation key (compare
sops.age.recipientin the file with the public key on the Encryption settings page) - On the ArgoCD engine only, confirm the cluster has ArgoCD installed and that the repo-server has restarted:
Cluster Not Decrypting Encrypted Values
Cluster Not Decrypting Encrypted Values
On the native engine the agent decrypts on its own and needs nothing installed in the cluster, so check the first entry above instead.An add-on that uses the ArgoCD engine needs ArgoCD to decrypt. If ArgoCD is not installed:
- Create a Stack with the ArgoCD add-on
- Deploy and wait for ArgoCD to become ready
- The SOPS decryption key will be deployed automatically
Values Not Being Encrypted
Values Not Being Encrypted
- Look in your Git repository, not in the Stack Builder. The Stack Builder always shows the value you entered; sealing happens when Ankra writes the file to Git
- Check that the key name matches exactly (case-sensitive)
- Verify SOPS is initialized at the organisation level
- Ensure the key is added to the Encrypted Keys list before saving
A Chart Field Was Encrypted That Should Not Have Been
A Chart Field Was Encrypted That Should Not Have Been
An entry seals every key of that name at every depth, so an entry named after a structural field (
key, name, path, value, type, host, port, operator) also seals the chart’s own fields. Check dotted entries by their last segment: tls.key and metadata.name are the same hazard as a bare key or name. The symptom is a render or sync failure naming a value that was never a secret, such as Input string kubernetes.io/hostname does not match sops data format.Decrypt the file, remove the over-broad entry from Encrypted Keys (SOPS), give the secret a distinctive key name, and re-encrypt. See What an Entry Actually Matches.If that entry is the last encrypted_paths entry anywhere on the cluster, removing it also stops Ankra rendering the cluster’s .sops.yaml, and the next platform write prunes the file along with any creation rules you keep there by hand. Keep a copy first - see Merging the SOPS configuration file.Save Rejected with an Invalid encrypted_paths Entry
Save Rejected with an Invalid encrypted_paths Entry
A
glob: pattern entry the grammar rejects fails the save with Invalid encrypted_paths entry "...": <reason>. The reason names the fix:contains no * wildcard- the pattern has no*; declare the exact key name without theglob:prefixwould match every key in the document- the pattern is only wildcards; keep at least one literal charactermust be followed by a key-name patternornames a section but no key-name pattern- add the pattern after the prefix or section, such asglob:stringData.DB_*
match no key in this document means every entry (literal or pattern) selected nothing - check the spelling against the document’s actual key names. See Encrypting Keys by Pattern for the full rules.A Sealed File Came Back as Plaintext After an API Update
A Sealed File Came Back as Plaintext After an API Update
An update sent over the API with
encrypted_paths: [] clears the stored declaration, and the next platform write renders the file as plain content over the sealed copy. Restore the declaration (declare the keys again, or re-encrypt with ankra cluster encrypt) and rotate any value that reached the repository in plaintext. On updates, omit the key to keep the stored declaration - see An Empty or Absent Declaration.AI Prompts
Press⌘+J to open the AI Assistant and use these prompts:
Set Up SOPS for a Stack
Set Up SOPS for a Stack
Troubleshoot Decryption Failure
Troubleshoot Decryption Failure
Advanced Configuration
The defaults described above work for most setups. The following sections cover optional configuration that you may need if you want to change the default behaviour.Disabling Organisation Encryption
SOPS encryption is enabled by default after initialization. If you need to temporarily stop encrypting new values (existing encrypted content remains encrypted):- Go to Organisation Settings → Encryption
- Toggle SOPS Encryption off
Per-Cluster Decryption Toggle
On the ArgoCD engine, Ankra automatically deploys the SOPS decryption key to every cluster that has ArgoCD. If you need to manage this manually for a specific cluster:- Go to your cluster → Settings → Encryption
- Toggle Enable SOPS Decryption on or off
Key Rotation
Key rotation is not available as a self-service control in the portal or the CLI today. Rotating the organisation key is more than generating a new pair: every file already sealed in your Git repositories has to be re-encrypted with the new public key before the old private key is retired, or those files can no longer be decrypted at deploy time.Related
Stacks
Build and deploy reusable Stack configurations.
GitOps
Sync Stacks with Git repositories.
Cloudflare Tunnel
Encrypt tunnel tokens with SOPS.
Manifests
Create custom Kubernetes resources with encryption.