Skip to content

feat: wire AUTOMATION_KV_SECRET through the automation chart - #1327

Closed
jpshackelford wants to merge 1 commit into
mainfrom
feat/automation-kv-secret
Closed

jpshackelford wants to merge 1 commit into
mainfrom
feat/automation-kv-secret

Conversation

@jpshackelford

@jpshackelford jpshackelford commented Oct 1, 2026 •

Copy link
Copy Markdown
Member

Why

The automation KV store (kv_router.py) needs AUTOMATION_KV_SECRET to sign per-run JWT KV tokens and encrypt stored values at rest. Every other automation secret is threaded through this chart (AUTOMATION_SERVICE_KEY, AUTOMATION_WEBHOOK_SECRET, AUTOMATION_GIT_SYNC_SECRET) but AUTOMATION_KV_SECRET was never wired. As a result:

  • GET /api/automation/v1/kv returns HTTP 503 "KV store not configured (missing AUTOMATION_KV_SECRET)" on every install produced by this chart (OHE Replicated and SaaS). Verified on the OHE Beta instance just now, running automation 1.15.1 which already contains the user-auth KV code from feat: add user-authenticated KV access automation#445.
  • Any automation that imports the kv helpers (AUTOMATION_KV_TOKEN env in a run) silently has no backing store.
  • The user-authenticated KV path added in feat: add user-authenticated KV access automation#445 is unusable on self-hosted and SaaS until this lands.

The only existing production code that sets AUTOMATION_KV_SECRET is the single-container OpenHands/OpenHands docker/entrypoint.sh (derived from EFFECTIVE_SESSION_KEY), which doesn't apply here because the automation service runs as its own pod from this chart.

Design note on hiding

AUTOMATION_KV_SECRET is internal signing material only — automation scripts never see or supply it, and admins have no reason to tune or rotate it from the UI. The new ConfigOption uses hidden: true + {{repl RandomString 32}}, so it's generated once per install, stable across upgrades (unless deliberately rotated through the API), and never shown in the Replicated admin console. Same posture as automation_service_key / automation_webhook_secret / automation_git_sync_secret.

What changed

Full mirror of the AUTOMATION_WEBHOOK_SECRET wiring, scoped to the layers that actually matter for KV:

charts/openhands-secrets/

  • New template templates/automation-kv-secret.yaml — K8s Secret named automation-kv-secret, key kv-secret, gated on .Values.automation.enabled.
  • values.yaml: new config.automation_kv_secret: "" stub.
  • Chart.yaml: 0.1.24 → 0.1.25.

charts/openhands/charts/automation/

  • values.yaml: new kvSecretFromSecret: { name: automation-kv-secret, key: kv-secret }.
  • templates/_env.yaml: new AUTOMATION_KV_SECRET env entry, valueFrom.secretKeyRef (same shape as AUTOMATION_WEBHOOK_SECRET, not optional: true — if the secret is missing the pod won't start, which is what we want because openhands-secrets always creates it alongside the automation deployment).

charts/openhands/

  • Chart.yaml: 0.74.0 → 0.74.1 (subchart values changed).
  • templates/troubleshoot/support-bundle.yaml: added AUTOMATION_KV_SECRET to SECRET_PRESENCE so "is KV configured on this install?" is a one-line answer in a bundle.

replicated/

  • config.yaml: new automation_kv_secret ConfigOption, type: password, hidden: true, value: '{{repl RandomString 32}}'.
  • secrets.yaml: mapped into openhands-secrets.config.automation_kv_secret.
  • openhands.yaml: added to the secretsChecksum sha256 so rotating the secret rolls the pod. Our new field lands at position 32, safely inside the hashed range — see the sidebar below.

Not changed (deliberately):

  • Parent chart's main _env.yaml — unlike AUTOMATION_WEBHOOK_SECRET (which the main openhands pod needs so it can sign events sent to the automation service), the main pod never signs KV requests. Only the automation pod needs this env.

Validation

  • helm lint charts/openhands-secrets — passes (one pre-existing icon INFO).
  • helm lint charts/openhands --set automation.enabled=true … — passes.
  • helm template charts/openhands-secrets --set automation.enabled=true --set config.automation_kv_secret=test-value — renders the new Secret with the decoded value test-value.
  • helm template charts/openhands --set automation.enabled=true … — the automation and automation-events deployments both include the new AUTOMATION_KV_SECRET env entry, right after AUTOMATION_WEBHOOK_SECRET.
  • python3 scripts/check_secret_checksum.py — OK: all 46 password config fields are covered by secretsChecksum. (was 45).
  • python3 -m pytest scripts/test_openhands_secrets_template.py scripts/test_troubleshoot_secrets_template.py -q — 9 passed.

How this fixes Beta

Beta currently serves automation 1.15.1 (post-OpenHands/automation#445) but 503s on GET /api/automation/v1/kv because the KV secret is unset. After this chart ships and the KOTS config renders the new ConfigOption, the automation-kv-secret K8s Secret will be auto-populated with a 32-char random value, the automation pod will boot with AUTOMATION_KV_SECRET set, and KV endpoints will start returning 401/400/200 instead of 503 (both the JWT path and the new user-auth path in #445).

Helm Chart Checklist

  • I have tested the chart upgrade path from the previous version — helm template produces a new K8s Secret and new env entry; no changes to existing resources.
  • I have verified backwards compatibility with existing values.yaml configurations — the new kvSecretFromSecret value defaults to a non-nil map so the template always renders the env block, and config.automation_kv_secret defaults to "" so pre-existing installs continue to render the Secret (empty value, same as the sibling secrets when unset in a non-Replicated install).
  • I have updated the chart's README.md if there are any breaking changes or new required values — no breaking changes, no new required values.

Sidebar: pre-existing secretsChecksum arity bug (fixed in #1328)

Inserting automation_kv_secret at position 32 of the secretsChecksum arg list shifts everything after it down by one slot. The printf format only has 45 %s placeholders, so the trailing args already fell off the hash — this PR pushes external_postgres_password off the edge too. No impact on AUTOMATION_KV_SECRET itself (position 32 is inside the hashed range), but worth tracking.

Full accounting and fix in #1328. Either PR can land first.


This PR was created by an AI agent (OpenHands) on behalf of the user.

The automation KV store (openhands/automation/kv_router.py) requires
AUTOMATION_KV_SECRET to sign per-run JWT KV tokens and encrypt stored
values at rest. The chart previously threaded AUTOMATION_SERVICE_KEY,
AUTOMATION_WEBHOOK_SECRET, and AUTOMATION_GIT_SYNC_SECRET but had no
provision for AUTOMATION_KV_SECRET, so every KV endpoint returns 503
"KV store not configured" on Replicated/OHE and SaaS installs. User-
authenticated KV access (OpenHands/automation#445) is also blocked by
this on the beta instance.

Mirror the AUTOMATION_WEBHOOK_SECRET pattern end to end: new K8s Secret
in openhands-secrets, kvSecretFromSecret + env entry in the automation
subchart, hidden auto-generated Replicated ConfigOption piped through
secrets.yaml and secretsChecksum, support-bundle presence check.

AUTOMATION_KV_SECRET is internal signing material; the ConfigOption is
hidden: true (same posture as service_key/webhook_secret/git_sync_secret)
and never surfaces in the admin console.

Chart bumps: openhands 0.74.0 -> 0.74.1, openhands-secrets 0.1.24 -> 0.1.25.

Co-authored-by: openhands <openhands@all-hands.dev>
@jpshackelford jpshackelford changed the title Wire AUTOMATION_KV_SECRET through the automation chart feat: wire AUTOMATION_KV_SECRET through the automation chart Oct 1, 2026
@github-actions github-actions Bot added the type: feat A new feature label Oct 1, 2026
@jpshackelford

Copy link
Copy Markdown
Member Author

Closing in favor of #1326 (@hieptl got there ~8h earlier; same problem, same core fix). The useful bits from this PR — Chart.yaml bumps, the SECRET_PRESENCE entry in the support bundle, and the pointer to #1328 — have been carried over as review comments on #1326.

This comment was posted by an AI agent (OpenHands) on behalf of @jpshackelford.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feat A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants