mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-30 20:29:15 +00:00
341511a2e0
* feat: deliver hub registry credentials to remote Compose targets
When a hub forwards stack operations to a remote node over confidential
transport, discover private image hosts on the target, attach an attested
credential envelope, and materialize DOCKER_CONFIG at the Compose seam.
Capability-gated with pass-through when delivery is unavailable.
* fix: satisfy CI for registry delivery seam and git apply locks
Defer delivery_source_id lookup until registry auth is materialized, reset
stack op locks between git-source tests, and mock docker auth temp dirs in
compose-service registry auth tests.
* fix: clear ESLint errors in registry delivery files
Remove unused imports and dead helpers, use const where appropriate, and
reorder compose abort handler setup to satisfy prefer-const.
* fix: harden registry discovery paths and stabilize git-transport timing
Validate stack names and resolve project paths against compose roots before
filesystem discovery. Widen the git-transport termination race margin in CI.
* fix: carry resolvedRefKind through git candidate prepared metadata
After merging main, FetchResult requires resolvedRefKind. Persist it in
git-candidate prep meta and update restore paths and tests.
* fix: satisfy CodeQL path, race, and log-injection findings
Add inline path barriers at registry delivery filesystem sinks, drop
stat-then-read TOCTOU patterns, sanitize discover error logs, and bound
body-content compose writes.
* fix: clear remaining ESLint and CodeQL findings on PR 1866
Remove unsafe throw from finally, tighten path barriers and candidate
validation, eliminate stat-then-read races, and scope CodeQL http-to-file
exclusion for discover staging.
* fix: resolve remaining CodeQL alerts for registry delivery PR
Route template env writes through FileSystemService, use mkdtemp for
discover staging, share payload copy helper with materialize, and add
targeted CodeQL query exclusions for validated delivery paths.
* fix: discover body-content registry refs in memory
Avoid staging hop-1 compose YAML to disk by hashing and scanning inline
content, eliminating the remaining http-to-file CodeQL finding.
* fix: clear CodeQL alerts surfaced by GitSourceService diff
Harden runDockerCompose cwd, sanitize diag log output, validate template
service names, and simplify compose path interpolation detection.
* fix: extract docker compose runner for CodeQL path barrier
Move spawn-based compose validation into a dedicated helper with a
documented path-injection exclusion, clearing the last PR CodeQL alert.
* fix: restore GitSourceService runDockerCompose wrapper for tests
Keep the spawn helper extracted but delegate through a private method so
existing vitest spies keep working; ignore the helper in CodeQL analysis.
* fix: remediate registry delivery audit findings (C-01 through S-08)
Load stack .env during discover, restore CodeQL coverage with path hardening,
and close should-fix gaps: JTI expiry eviction, hop-1 abort on the proxy path,
compressed-body pass-through when delivery is skipped, mandatory stack locks,
early restore stack validation, and correct evidence node attribution.
* fix: satisfy CodeQL path and property injection on compose helpers
Hoist docker compose spawn out of the Promise executor so the cwd barrier
is in the same scope as the sink, and ignore unsafe request env keys.
* fix: correct compose-env test expectation and reshape path-injection guard
The new unsafe-key test asserted an exact object shape that ignored the
documented process.env override layer, failing wherever process.env is
non-empty. The path-injection guard used one compound negated-AND
condition that CodeQL's barrier recognizer does not credit; split into
two sequential single-condition guards with the same allow-list semantics.
* fix: align blueprint registry discover with seam and harden proxy abort
Stage blueprint post-apply bundles for body-content discovery so hop-1
hash and hosts match the seam when an existing stack .env is present.
Restore prior compose.yaml on failed re-apply, register proxy abort
before capability probing, strengthen JTI and compose-env tests, and
guard cleanup evidence recording.
* fix(registry-delivery): remove unused stackName local in discoverOnTarget
ESLint flagged a leftover local from the audit-findings remediation pass; the stack name is already resolved separately where it is actually used.
* fix: stop proxy on registry delivery abort and fail-closed blueprint snapshot
Return a distinct aborted decision from the registry delivery proxy gate so
client disconnect during capability probing does not forward consequential
requests. Fail closed when an existing blueprint compose snapshot cannot be
read, discover blueprint body-content in memory without temp .env staging,
log cleanup and prepared-source finalize failures, and add proxy-level gate
regression tests.
* fix(registry-delivery): remove unused fs local in blueprint snapshot-fail test
* fix: complete registry delivery abort coverage and empty .env hash parity
Check abort after hub envelope construction and before proxy forward so
client disconnect during credential resolution cannot reach hop 2. Include
zero-byte stack .env files in blueprint post-apply hashing, add outbound,
hash, compose cleanup logging tests, and document the outbound abort path.
* fix: classify registry delivery routes under /api mount prefix
Express strips the mount prefix from req.path when registryDeliveryMiddleware
is installed at app.use('/api', ...). Normalize to /api${req.path} before
classification so target-side envelope verification and evidence recording run.
Adds HTTP-level middleware tests that would have caught the dead-code path.
219 lines
15 KiB
Plaintext
219 lines
15 KiB
Plaintext
---
|
|
title: Private Registries
|
|
sidebarTitle: Registries
|
|
description: Store credentials for private Docker registries so Sencho can authenticate automatically during deploy, pull, and image-update checks.
|
|
---
|
|
|
|
<Note>
|
|
Private Registries is an admin-only feature. Credentials for Docker Hub, GitHub Container Registry (GHCR), and custom or self-hosted registries are available on every tier; AWS ECR requires a Sencho **Admiral** license. Each Sencho instance stores its own registry credentials; the Registries section is hidden when you are viewing another node through the node switcher.
|
|
</Note>
|
|
|
|
Sencho stores credentials for your private Docker registries and injects them automatically whenever it runs `docker compose pull` or `docker compose up`. Stacks can reference private images without anyone having to run `docker login` on the host.
|
|
|
|
<Frame>
|
|
<img src="/images/private-registries/registries-overview.png" alt="Registries section in Settings showing one configured GHCR registry card with the global scope masthead stat" />
|
|
</Frame>
|
|
|
|
## Supported registry types
|
|
|
|
| Type | Description | Credentials |
|
|
|------|-------------|-------------|
|
|
| **Docker Hub** | Private Docker Hub organizations and repositories | Username + access token |
|
|
| **GitHub Container Registry (GHCR)** | `ghcr.io` images for users and organizations | GitHub username + personal access token (PAT) |
|
|
| **AWS Elastic Container Registry (ECR)** | Amazon ECR private registries (Admiral) | AWS Access Key ID + Secret Access Key (+ region) |
|
|
| **Custom / Self-hosted** | Any Docker V2 compatible registry | Username + password or token |
|
|
|
|
AWS ECR requires a Sencho **Admiral** license; Docker Hub, GHCR, and custom registries are available on every tier.
|
|
|
|
|
|
|
|
## Browse tags from Resources
|
|
|
|
When you inspect an image on the Resources page, the detail sheet includes a **Registry tags** section for admins. Sencho lists tag names from the configured registry that matches the image host (credentials come from that registry row only). Tag browsing always runs on the hub instance; local image digests still come from the active node. Digest comparison for updates and scans happens separately on that node. For how tags and digests relate, see [Tags vs digests](/features/vulnerability-scanning#tags-vs-digests).
|
|
|
|
If credentials are wrong, Sencho reports a registry error without signing you out of the dashboard.
|
|
|
|
## Where to find it
|
|
|
|
Open **Settings → Infrastructure → Registries** on the Sencho instance you are signed into directly. The section is hidden when you are viewing another node through the node switcher.
|
|
|
|
## Adding a registry
|
|
|
|
1. Click **Add registry**. The form expands inline above the registry list.
|
|
2. Pick a **Registry Type**. The form rearranges to match: for ECR an **AWS Region** field appears and the credential fields are relabelled to **AWS Access Key ID** and **AWS Secret Access Key**; for GHCR the **Registry URL** is pre-filled with `ghcr.io`.
|
|
3. Enter a descriptive **Name**.
|
|
4. Enter the **Registry URL**. For Docker Hub the field is read-only and the canonical `https://index.docker.io/v1/` value is used automatically.
|
|
5. Enter the credentials (username + secret, or AWS keys for ECR).
|
|
6. For ECR, fill in the **AWS Region** (e.g., `us-east-1`).
|
|
7. Click **Test connection** to probe the registry before saving. For Docker, GHCR, and self-hosted registries this hits the `/v2/` endpoint; for ECR it calls AWS STS `GetAuthorizationToken`.
|
|
8. Click **Add** to store the credentials.
|
|
|
|
<Frame>
|
|
<img src="/images/private-registries/registries-empty.png" alt="Empty Registries section with the Add registry button and the 'No private registries configured' callout" />
|
|
</Frame>
|
|
|
|
<Frame>
|
|
<img src="/images/private-registries/registries-add-form.png" alt="Add registry form expanded with Registry Type set to Docker Hub, the Registry URL field locked to the canonical value, and credential fields below" />
|
|
</Frame>
|
|
|
|
## Managing registries
|
|
|
|
Each saved registry renders as a card:
|
|
|
|
<Frame>
|
|
<img src="/images/private-registries/registries-card-detail.png" alt="Registry card showing a GHCR entry with type badge, URL, username, Secret stored pill, created date, and Test connection, Edit, and Delete icon buttons" />
|
|
</Frame>
|
|
|
|
The card surfaces:
|
|
|
|
- **Name** and **type badge** (`Docker Hub`, `GitHub (GHCR)`, `AWS ECR`, or `Custom`).
|
|
- **Registry URL** in a monospaced font.
|
|
- **Username**.
|
|
- **Secret stored** (or **No secret**) with a status icon.
|
|
- **Region**, when the registry is an ECR type.
|
|
- **Created** date.
|
|
|
|
Three icon actions sit on the right of the card:
|
|
|
|
- **Test connection** (checkmark icon) re-runs the live probe against the saved credentials.
|
|
- **Edit** (pencil icon) re-opens the form with the existing values. The **Secret / Token** field shows `(leave blank to keep current)` as its placeholder; type a new value only if you want to rotate the credential.
|
|
- **Delete** (trash icon) opens a destructive confirmation dialog.
|
|
|
|
<Frame>
|
|
<img src="/images/private-registries/registries-delete-confirm.png" alt="Delete registry confirmation dialog warning that stacks using images from this registry will fail to pull until credentials are re-added" />
|
|
</Frame>
|
|
|
|
Deleting a registry removes the credential record immediately. Any stack that references images from that registry will start failing its pull step on the next deploy until you add the registry back.
|
|
|
|
### Testing connectivity
|
|
|
|
You can verify credentials at two points:
|
|
|
|
- **Before saving**, from the **Test connection** button inside the add or edit form. The probe runs against the values currently in the form and never persists them, so you can confirm a token or password works before committing it.
|
|
- **After saving**, from the **Test connection** icon on any registry card. Sencho decrypts the stored secret and re-runs the same probe.
|
|
|
|
For Docker Hub, GHCR, and self-hosted registries, the probe authenticates against `/v2/` with Basic auth and follows a token-endpoint redirect on a 401 `WWW-Authenticate` challenge. For ECR, the probe asks AWS for an authorization token and returns success once the call succeeds.
|
|
|
|
## How credentials are applied
|
|
|
|
### Deploy and pull operations
|
|
|
|
For every deploy or update Sencho:
|
|
|
|
1. Resolves credentials for every configured registry.
|
|
2. For ECR, reuses a cached authorization token when one is still valid; otherwise fetches a fresh one from AWS. Cached tokens are refreshed a few minutes before the AWS-reported expiry, so deploys do not fail on a borderline token.
|
|
3. Writes a temporary Docker config file containing all the resolved auth entries.
|
|
4. Sets the `DOCKER_CONFIG` environment variable so `docker compose` reads from the temporary config instead of the host's `~/.docker/config.json`.
|
|
5. Runs the compose operation (pull and/or up).
|
|
6. Deletes the temporary config immediately after the operation finishes.
|
|
|
|
Credentials are never persisted to disk on the host beyond the duration of a single operation.
|
|
|
|
If a stored secret cannot be decrypted at deploy time (for example because the encryption key file was replaced), Sencho skips that one registry, writes a warning to the deploy log stream prefixed with `[Sencho] Warning:`, and continues. Public-image deploys still succeed when one private registry is misconfigured, and the failure is visible so the operator can re-save the credentials.
|
|
|
|
### Image update checks
|
|
|
|
The background image-update checker uses the same stored credentials. When it polls a registry to compare local and remote digests for a private image, it authenticates with the registry-specific credentials configured here.
|
|
|
|
## ECR setup
|
|
|
|
AWS ECR uses short-lived authentication tokens (valid for 12 hours) derived from IAM credentials. Sencho handles the token lifecycle automatically:
|
|
|
|
1. Store the **AWS Access Key ID** and **Secret Access Key** as the credential pair.
|
|
2. Set the **AWS Region** where the registry lives.
|
|
3. On every deploy or pull, Sencho reuses a cached authorization token while it is valid, or calls the AWS `GetAuthorizationToken` API to obtain a fresh one.
|
|
|
|
<Frame>
|
|
<img src="/images/private-registries/registries-ecr-form.png" alt="Add registry form with type set to AWS Elastic Container Registry (ECR), showing the relabelled AWS Access Key ID and AWS Secret Access Key inputs and the AWS Region field" />
|
|
</Frame>
|
|
|
|
<Warning>
|
|
Use an IAM user or role limited to the ECR read permissions below. Do not paste root account credentials.
|
|
</Warning>
|
|
|
|
### IAM policy example
|
|
|
|
```json
|
|
{
|
|
"Version": "2012-10-17",
|
|
"Statement": [
|
|
{
|
|
"Effect": "Allow",
|
|
"Action": [
|
|
"ecr:GetAuthorizationToken",
|
|
"ecr:BatchGetImage",
|
|
"ecr:GetDownloadUrlForLayer",
|
|
"ecr:BatchCheckLayerAvailability"
|
|
],
|
|
"Resource": "*"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Registry URL reference
|
|
|
|
| Registry | URL to use |
|
|
|----------|-----------|
|
|
| Docker Hub | `https://index.docker.io/v1/` (set automatically) |
|
|
| GHCR | `ghcr.io` |
|
|
| AWS ECR | `{account_id}.dkr.ecr.{region}.amazonaws.com` |
|
|
| Self-hosted | Your registry hostname, e.g. `registry.example.com` |
|
|
|
|
## Security
|
|
|
|
- **Encrypted storage.** Registry secrets are encrypted at rest with the same encryption layer used for remote-node tokens and SSO secrets.
|
|
- **No persistent Docker login.** Credentials are written to a temporary file for the duration of each compose operation and deleted afterward.
|
|
- **Secrets never exposed.** The API never returns decrypted secrets. The UI shows only whether a secret is stored.
|
|
- **Admin role required.** Registry management is restricted to admin operators. Viewers and operators with non-admin roles cannot see the section.
|
|
- **API tokens cannot manage registries.** Registry credentials can only be created, edited, or deleted from an admin browser session. Automation tokens are scoped away from this surface so a leaked CI key cannot rewrite pull credentials.
|
|
- **Audit trail.** Registry create, update, and delete operations are recorded in the [Audit Log](/features/audit-log).
|
|
|
|
## Registries in a multi-node fleet
|
|
|
|
Registry credentials are stored on the Sencho instance where you enter them, and each instance resolves its own credentials at deploy time. Sencho does not automatically share credentials between instances: a remote node authenticates its pulls with the registries configured on that node, not with the ones on the instance you happen to be signed into.
|
|
|
|
Because the Registries section is hidden when you view another node through the node switcher, manage a remote node's registries by signing into that node's own Sencho instance directly. Configure each private registry on every instance that deploys images from it, so a stack keeps pulling no matter which node it runs on.
|
|
|
|
## Remote fleet delivery
|
|
|
|
When you manage remote nodes from a central Sencho instance, you can store private registry credentials once on the hub and have Sencho deliver them to a compatible remote target for a single Compose operation (deploy, update, rollback, template deploy, or Git apply with auto-deploy).
|
|
|
|
Delivery runs only when the remote target advertises the `remote-registry-credentials` capability and the hop is confidential (HTTPS proxy URL, or a Pilot tunnel terminated with TLS or a trusted reverse proxy). Otherwise the operation forwards unchanged: public images and registry rows already configured on the target keep working without hub credentials traveling to that node.
|
|
|
|
Credentials exist only in the forwarded delivery envelope and a temporary `DOCKER_CONFIG` for the duration of the Compose child process. They are not written to the target's registry table, responses, logs, or audit trail. Target-local registry rows always win when both sides have a credential for the same host.
|
|
|
|
If discovery or delivery fails before Compose starts, Sencho returns a clear error and does not spawn the operation. Retry the deploy after fixing hub registry configuration or upgrading the remote Sencho version.
|
|
|
|
## Troubleshooting
|
|
|
|
<AccordionGroup>
|
|
<Accordion title="Pull fails with a 401 even though the credentials saved successfully">
|
|
The most common cause is a URL format mismatch. Use the values from the **Registry URL reference** table above. For Docker Hub the value is set automatically; for GHCR use `ghcr.io` exactly. If the URL is correct, open the registry, re-enter the secret, and click **Test connection** inside the form. Some providers rotate tokens silently, and the card view cannot tell you a stored token was revoked without an active probe.
|
|
</Accordion>
|
|
|
|
<Accordion title="An ECR registry works for a while and then stops pulling">
|
|
AWS ECR authorization tokens are valid for 12 hours. Sencho caches the token in memory and refreshes it automatically a few minutes before the AWS-reported expiry, so no operator action is needed in steady state. If pulls still fail, confirm the IAM user still has `ecr:GetAuthorizationToken` and that the AWS Access Key ID has not been rotated. Click **Test connection** on the card to force a fresh token fetch.
|
|
</Accordion>
|
|
|
|
<Accordion title='The deploy log shows `[Sencho] Warning: Registry "X" credentials unavailable`'>
|
|
Sencho could not decrypt the stored secret for that registry. The deploy continues without that registry's credentials, which is fine if the stack pulls only public images. To fix it, open the registry, re-enter the secret, and save. If the same warning appears for every registry at once, the encryption key file in your data directory has been replaced or lost and every stored secret needs to be re-entered.
|
|
</Accordion>
|
|
|
|
<Accordion title="Test connection says it failed but deploys still pull images successfully">
|
|
Some registries, notably certain self-hosted mirrors and proxy caches, restrict access to the `/v2/` discovery endpoint while still allowing pulls. Sencho uses `/v2/` as the probe target, so a failure there does not always indicate broken credentials. If your deploys succeed, the test result can be ignored. The probe is a best-effort check, not a save-time gate.
|
|
</Accordion>
|
|
|
|
<Accordion title="The Registries section is not visible">
|
|
The section is shown on the instance you are signed into directly, to operators with the admin role. On a remote node viewed through the node switcher, the section is hidden by design; sign into that node's own Sencho instance to manage its registries. If a non-admin operator should be able to manage registries, change their role under **Settings → Access → Users** first. Adding an **AWS ECR** registry requires Admiral; Docker Hub, GHCR, and custom registries are available on every tier.
|
|
</Accordion>
|
|
|
|
<Accordion title="A node displays a 'Private Registries is not available on this node' lock card">
|
|
The selected node is on a Sencho version too old to surface this feature. Upgrade the node to a current Sencho release, then sign into that node's own Sencho instance to configure its registry credentials. Only the management UI depends on the node's version; once upgraded, that node's deploys use the registries configured on it.
|
|
</Accordion>
|
|
|
|
<Accordion title="An API token cannot create or update registries">
|
|
Registry management is restricted to admin browser sessions; API tokens are not scoped for this surface. Use a signed-in browser for the create, edit, and delete flow and reserve API tokens for the operations they are designed for.
|
|
</Accordion>
|
|
</AccordionGroup>
|