Skip to content

fix(openbao): grant external-secrets role write/read on apps/actual-budget path - #2343

Merged
devantler merged 1 commit into
mainfrom
claude/repo-assist-fix-actual-budget-vault-policy
Jun 29, 2026
Merged

devantler merged 1 commit into
mainfrom
claude/repo-assist-fix-actual-budget-vault-policy

Conversation

@devantler

Copy link
Copy Markdown
Contributor

🤖 Generated by the Daily AI Assistant

Problem (live prod stall)

The prod flux-system/infrastructure Kustomization was stuck Unknown (Reconciliation in progress → HealthCheckFailed after 20m), which in turn blocked flux-system/apps with dependency 'flux-system/infrastructure' is not ready.

Root cause traced to the seed-actual-budget-enablebanking PushSecret, stuck InProgress:

set secret failed: could not verify if secret exists in store: cannot read secret data from Vault:
GET http://openbao-active.openbao.svc.cluster.local:8200/v1/secret/data/apps/actual-budget/enablebanking
Code: 403 ... permission denied

Root cause

#2331 added both the PushSecret (writes secret/data/apps/actual-budget/enablebanking) and the actual-budget external-secret-enablebanking ExternalSecret (reads it), both routed through the openbao ClusterSecretStore → external-secrets Kubernetes auth role. But the OpenBao policies that role carries (defined in k8s/bases/infrastructure/vault-config/job.yaml) were never extended to the new apps/actual-budget path — they list every other app (fleetdm, wedding-app, umami, crossview, …) but not actual-budget. Result: 403 on write, PushSecret never syncs, infra health check times out, apps blocked.

Fix

Mirrors the existing crossview pattern exactly:

  • new app-actual-budget-readonly policy — read on secret/data/apps/actual-budget/*
  • add actual-budget data + metadata paths to vault-seed-write (create/update/read) so the PushSecret can seed
  • add app-actual-budget-readonly to the external-secrets role policy list

The Job carries kustomize.toolkit.fluxcd.io/force: enabled (and the infra Kustomization has force: true), so Flux recreates it on the next reconcile, re-applies the policies, the PushSecret syncs, and infrastructure → apps unblocks.

Validation

  • kubectl kustomize k8s/clusters/local/ ✅
  • kubectl kustomize k8s/clusters/prod/ ✅
  • kubectl kustomize k8s/providers/hetzner/infrastructure/ ✅ (renders the new path)
  • kubectl apply --dry-run=client on the Job ✅

…udget path

PR #2331 added the `seed-actual-budget-enablebanking` PushSecret (writes
secret/data/apps/actual-budget/enablebanking) and the actual-budget
`external-secret-enablebanking` ExternalSecret (reads it), both via the
`openbao` ClusterSecretStore → `external-secrets` Kubernetes auth role.
But the OpenBao policies that role carries were never updated for the new
apps/actual-budget path, so the PushSecret got 403 permission denied:

  GET .../v1/secret/data/apps/actual-budget/enablebanking
  Code: 403 ... permission denied

The PushSecret stuck at InProgress, which failed the infrastructure
Kustomization health check (20m timeout) and in turn blocked the apps
Kustomization (dependency not ready) — i.e. a full reconcile stall in prod.

Root cause: the policy set in the vault-config Job lists every other app
path (fleetdm, wedding-app, umami, crossview, ...) but not actual-budget.
Fix mirrors the crossview pattern exactly:
- new `app-actual-budget-readonly` policy (read on secret/data/apps/actual-budget/*)
- add actual-budget data+metadata paths to `vault-seed-write` (create/update/read)
- add `app-actual-budget-readonly` to the `external-secrets` role policy list

The Job carries `kustomize.toolkit.fluxcd.io/force: enabled`, so Flux
recreates it on the next reconcile and re-applies the policies; the
PushSecret then syncs and infrastructure → apps unblocks.

Validated: `kubectl kustomize k8s/clusters/{local,prod}` and the hetzner
infrastructure overlay all build; job dry-run applies clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 29, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2b72c540-53bd-402e-a985-88e2fbf96955

📥 Commits

Reviewing files that changed from the base of the PR and between 54590b8 and 59a3ff1.

📒 Files selected for processing (1)
  • k8s/bases/infrastructure/vault-config/job.yaml

📝 Walkthrough

Walkthrough

The Vault configuration job gains ACL support for the actual-budget app: a new app-actual-budget-readonly policy grants read on secret/data/apps/actual-budget/*, the vault-seed-write policy is extended to cover data and metadata paths for that app, and the external-secrets Kubernetes auth role's policy list is updated to include the new readonly policy.

Vault ACL for actual-budget

Layer / File(s) Summary
New and extended Vault policies for actual-budget
k8s/bases/infrastructure/vault-config/job.yaml
Adds app-actual-budget-readonly policy (read on secret/data/apps/actual-budget/*) and extends vault-seed-write to include create/update/read on both secret/data/apps/actual-budget/* and secret/metadata/apps/actual-budget/*.
Wire readonly policy into external-secrets auth role
k8s/bases/infrastructure/vault-config/job.yaml
Appends app-actual-budget-readonly to the policies= list of auth/kubernetes/role/external-secrets, enabling ExternalSecrets to read actual-budget secrets.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related PRs

  • devantler-tech/platform#2331: Directly related — introduces ExternalSecret and PushSecret resources under apps/actual-budget that depend on the Vault ACL paths and external-secrets role policy being provisioned in this PR.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the core change: extending OpenBao permissions for the actual-budget path.
Description check ✅ Passed The description directly explains the permission issue, the fix, and the affected actual-budget secret paths.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/repo-assist-fix-actual-budget-vault-policy

Comment @coderabbitai help to get the list of available commands.

@devantler
devantler marked this pull request as ready for review June 29, 2026 21:21
@devantler
devantler added this pull request to the merge queue Jun 29, 2026
@devantler
devantler removed this pull request from the merge queue due to a manual request Jun 29, 2026
@devantler
devantler merged commit 22909b2 into main Jun 29, 2026
15 checks passed
@devantler
devantler deleted the claude/repo-assist-fix-actual-budget-vault-policy branch June 29, 2026 21:49
@github-project-automation github-project-automation Bot moved this from 🫴 Ready to ✅ Done in 🌊 Project Board Jun 29, 2026
@botantler-1

botantler-1 Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.88.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@botantler-1 botantler-1 Bot added the released label Jun 29, 2026
devantler added a commit that referenced this pull request Jun 30, 2026
…subst (#2349)

With the infrastructure→apps stall cleared (#2343), the apps Kustomization
finally reconciled past its dependency gate and immediately failed:

  post build failed for 'ConfigMap/actual-budget-enablebanking-seed':
  envsubst error: variable substitution failed: unable to parse variable name

The ConfigMap (added in #2331) embeds a Node.js reconcile script that uses JS
template literals — `${DB_PATH}`, `${name}`, and crucially a multi-line
`${ INTERVAL / 1000 }`. The apps Kustomization runs `substituteFrom`, so Flux's
envsubst tries to expand these; the newline inside `${ ... }` can't be parsed as
a variable name, which fails the WHOLE apps Kustomization (every app blocked).

This was latent: apps never reconciled after #2331 merged because it was blocked
on the infrastructure dependency (the PushSecret 403, #2343), so the error only
surfaced once infrastructure went healthy.

These are not Flux variables, so the ConfigMap needs no post-build substitution.
Opt it out with `kustomize.toolkit.fluxcd.io/substitute: disabled` — the same
pattern the KRO ResourceGraphDefinitions use for their CEL `${...}` expressions.

Validated: kubectl kustomize k8s/clusters/{local,prod} and the actual-budget
base build; rendered ConfigMap carries the annotation; dry-run applies clean.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant