Files
sencho/docs/features/git-secrets.mdx
T
Anso 5b41c0512f docs: reorganize GitOps documentation into one section (#2167)
* docs: reorganize GitOps documentation into one section

Add a GitOps overview that defines the model once (Direct sources versus
Blueprints, the chain from commit to container, the three authority
steps, the policies, source states, executable identity). Split the
oversized Git Sources and Blueprints pages into focused pages for Git
authentication, provider and CI webhooks, repository secrets, and
Git-managed Blueprints, and trim the remaining pages to their own slice.

Group the GitOps pages in the navigation and split the old "Deploy and
automate" group into "Deploy and recover" and "Automate". Existing page
slugs are unchanged. Correct the provider hook labels to match the app,
and repoint What's New links to the new Git-managed Blueprints page.

* docs: add current GitOps screenshots and correct UI labels

Retake the Git Sources, Blueprints, and GitOps portfolio screenshots on
the integration image, and add screenshots to the new GitOps pages
(answer, path, and evidence block; SSH deploy key form; provider hooks;
Secrets tab; Convert to Git, placement review, and rollout controls).

Correct labels to match the app: Deploy key (SSH), the provider hook
event scopes, and the encrypted source policy buttons. The change plan
dialog shows the stack name, not the commit.

* docs: map the GitOps policy names once in the overview

Evidence, the policy controls, and the Git source form name the same
settings differently. State the mapping in one place.
2026-10-22 19:20:47 -04:00

80 lines
6.4 KiB
Plaintext

---
title: Repository secrets with SOPS and age
sidebarTitle: Repository secrets
description: Keep sensitive env files in Git as SOPS-encrypted documents. Sencho decrypts them only for the moment a validation, apply, deploy, or rollback needs them.
---
Some teams commit sensitive env files to the repository as [SOPS](https://github.com/getsops/sops)-encrypted documents. That covers a sibling `.env` synced with the source and any env files or file-backed secrets the compose file names.
Sencho keeps ciphertext in the repository and on disk. Decryption happens only in a short-lived overlay while it validates a candidate, applies, deploys, or rolls back.
## Set it up
<Steps>
<Step title="Create an identity on the owning node">
Open **Git Source** on the linked stack and select the **Secrets** tab. Click **Generate identity**, or **Import identity** to use an age key you already hold. The key pair is created on the node that owns this Git source. Private key material never leaves the node and is never returned by the API.
</Step>
<Step title="Add the recipient to your SOPS files">
Sencho shows the public recipient (`age1…`). Add it to the SOPS configuration in your repository and encrypt the env files.
</Step>
<Step title="Choose the encrypted source policy">
**Encrypted source policy** defaults to **Allow plaintext secrets**. Switch to **Require SOPS encryption** when every managed secret-bearing input in the repository must be SOPS-encrypted with age.
</Step>
<Step title="Check readiness">
The readiness chip reports whether this node holds the recipients for the generation applied on it. Before the first apply, it reports the staged candidate.
</Step>
</Steps>
<Frame caption="The Secrets tab with a generated identity. The recipient is listed with copy, rotate, and delete controls, and Import identity takes an existing age key.">
<img src="/images/git-secrets/secrets-tab.png" alt="Secrets tab of the Git Source sheet showing a Ready readiness chip, the Allow plaintext secrets and Require SOPS encryption buttons, a recipient starting age1 with copy, rotate, and delete buttons, a Generate identity button, and a field with an Import identity button" />
</Frame>
## What is supported
| Format | Support |
|---|---|
| age (X25519) recipients in YAML SOPS documents (`sops.age`) | Supported |
| age recipients in dotenv or INI stores (`sops_age__list_*` keys) | Supported |
| PGP, cloud KMS, and other SOPS backends | Refused with an unsupported-backend message |
| Encrypted compose files | Not supported |
## How decrypted files reach the stack
While a candidate is validated or a deploy runs, Compose reads decrypted values from the overlay.
- Relative mounts keep the host path they would have if Compose ran in the stack directory, at any parent depth. The same holds for the host directory a named volume's local driver binds.
- A decrypted secret file that the compose file mounts directly is read from the overlay for that run, including a file whose name contains a literal `$`.
- A rollback checks the restored files the same way before it replaces any container.
Sencho refuses, before the stack starts, a mount that covers both a decrypted secret and persistent data, a named volume backed by the decrypt area, and a relative path it cannot place on the stack with confidence. The fix for the first is to move the secret file out of that mount. On rollback it also refuses a mount outside the compose path that the host maps 1:1, and an encrypted env file that no identity on this node can open. The name `.sencho-bind-remap.yml` is reserved for the storage layer Sencho writes into the overlay, so a compose file that already holds that name is refused rather than replaced.
A manual **Deploy** or image **Update** follows the files applied on this node, so those actions stay refused while the applied generation is encrypted, even when the last successful deploy recorded no age recipients. Apply also refuses a staged candidate that does not record the recipients for its encrypted files; pull the source again so the candidate records them, then apply.
## Compose output is confidential
Compose quotes the values it interpolated back in its own errors. Whenever Compose runs over decrypted files, Sencho therefore reports only that the command failed and withholds the diagnostic. Those values cannot reach the result, the activity log, or a stored outcome. To find the cause, read the running stack's container logs.
The missing-variable guard follows the same rule. It still refuses the deploy, but on a source with encrypted inputs it cannot name the variables, because naming them would report a value. Give every `${VAR:?message}` reference a value in the project's `.env` or `env_file` files, then deploy again. When a project env file is part of the candidate, or a context directory is set and the stack root `.env` is present, validation and a Git deploy read that copy.
## Back up your keys
Back up both the Sencho data directory's encryption key (`encryption.key`) and every age identity you generate here. Losing either makes the ciphertext in Git unrecoverable on that node.
## Troubleshooting
<AccordionGroup>
<Accordion title="Missing or rotated SOPS age key">
A Git apply, Git deploy, or rollback that needs decryption fails before Compose runs when this node holds no matching age identity. Open the **Secrets** tab, check the readiness chip, and generate or import the key whose recipient appears in your SOPS files.
After rotating a key, re-encrypt the repository files with the new recipient before deleting the old identity. Rollback stays blocked for a generation whose encrypted files name only recipients this node lacks, until you restore one of those identities or advance to a generation encrypted for a key you still hold. Manual Deploy and image Update stay blocked on SOPS-managed stacks; use Git apply instead.
</Accordion>
<Accordion title="A deploy fails and Sencho will not say why">
That is deliberate for sources with encrypted inputs. The Compose diagnostic can contain decrypted values, so Sencho withholds it. Check the container logs, and confirm every `${VAR:?message}` reference has a value in the project's `.env` or `env_file` files.
</Accordion>
<Accordion title="Apply refuses a staged candidate">
The candidate does not record the age recipients for its encrypted files. Pull the source again so the candidate records them, then apply.
</Accordion>
</AccordionGroup>