Automate deployment credential issuance through Forgejo OIDC and OpenBao #19

Closed
opened 2026-09-05 23:50:55 -05:00 by kiyi · 6 comments
Member

Deployment currently requires manually issuing a short-lived Kubernetes token and updating DEPLOY_KUBECONFIG_B64 in the app repository. Automate this so future deployments obtain fresh credentials without recurring manual secret updates.

Scheduling: backlog follow-up after Actual Budget is deployed (Homelab/actual-budget#1). This is not a prerequisite for the current migration; its repository credential assignment is complete.

Proposed implementation:

  • Homelab/platform: configure Forgejo OIDC trust in OpenBao, repository/ref/audience-bound policies, and Kubernetes secrets-engine roles for approved app deployment ServiceAccounts. Verify actual Forgejo claims and reusable-workflow identity before binding trust.
  • Homelab/workflows: authenticate to OpenBao during an authorized deployment, request a temporary Kubernetes credential, generate a private kubeconfig, validate scope/context, deploy, and clean up credential files without exposing tokens in logs or artifacts.
  • App repositories: select their approved deployment role. Evaluate organization-level shared configuration and secrets where appropriate, without distributing one broadly privileged kubeconfig to every repository.

Acceptance criteria:

  • Demonstrate two deployments obtaining fresh credentials without manually replacing repository secrets.
  • Restrict issuance to approved repository and deployment ref/workflow identities; reject unauthorized repositories, refs, and audiences.
  • Preserve per-app deployment permissions and document shared Zarf access/residual permissions; do not grant general cluster-admin.
  • Verify expiration, issuance failures, and authorization failures stop deployment; keep credentials out of logs/artifacts and clean temporary files.
  • Document platform bootstrap, new-app onboarding, organization versus repository configuration, and recovery/revocation.
  • Release the shared workflow change and migrate Actual after its initial deployment is accepted.

Related: Homelab/platform#23 (initial manual deployment credential bootstrap), Homelab/platform#5 (OpenBao), Homelab/workflows#2 (future runner migration). This work should not require moving the runner to Kubernetes first.

Deployment currently requires manually issuing a short-lived Kubernetes token and updating DEPLOY_KUBECONFIG_B64 in the app repository. Automate this so future deployments obtain fresh credentials without recurring manual secret updates. Scheduling: backlog follow-up after Actual Budget is deployed (Homelab/actual-budget#1). This is not a prerequisite for the current migration; its repository credential assignment is complete. Proposed implementation: - Homelab/platform: configure Forgejo OIDC trust in OpenBao, repository/ref/audience-bound policies, and Kubernetes secrets-engine roles for approved app deployment ServiceAccounts. Verify actual Forgejo claims and reusable-workflow identity before binding trust. - Homelab/workflows: authenticate to OpenBao during an authorized deployment, request a temporary Kubernetes credential, generate a private kubeconfig, validate scope/context, deploy, and clean up credential files without exposing tokens in logs or artifacts. - App repositories: select their approved deployment role. Evaluate organization-level shared configuration and secrets where appropriate, without distributing one broadly privileged kubeconfig to every repository. Acceptance criteria: - [x] Demonstrate two deployments obtaining fresh credentials without manually replacing repository secrets. - [ ] Restrict issuance to approved repository and deployment ref/workflow identities; reject unauthorized repositories, refs, and audiences. - [x] Preserve per-app deployment permissions and document shared Zarf access/residual permissions; do not grant general cluster-admin. - [ ] Verify expiration, issuance failures, and authorization failures stop deployment; keep credentials out of logs/artifacts and clean temporary files. - [x] Document platform bootstrap, new-app onboarding, organization versus repository configuration, and recovery/revocation. - [x] Release the shared workflow change and migrate Actual after its initial deployment is accepted. Related: Homelab/platform#23 (initial manual deployment credential bootstrap), Homelab/platform#5 (OpenBao), Homelab/workflows#2 (future runner migration). This work should not require moving the runner to Kubernetes first.
kiyi added this to the Homelab Roadmap project 2026-09-05 23:50:55 -05:00
Author
Member

Progress update — 2026-09-08

Actual is accepted in production, so this is now active automation work for all future application deployments, not a prerequisite still waiting on the first migration.

Implemented and released:

  • Homelab/workflows#26 / v1.4.0: inspect and OpenBao credential modes, per-run issuance, temporary kubeconfig handling, cleanup/revocation, and an explicit per-app permission contract (required and forbidden authorization checks).
  • Homelab/workflows#27 / v1.4.1: actionable, redacted credential inspection errors.
  • Homelab/workflows#28 / v1.4.2: preserve OIDC enablement through reusable-workflow expansion by declaring it at workflow level as well as job level.
  • Bootstrap, onboarding, organization/repository configuration, and recovery/revocation documentation are implemented alongside Homelab/platform#27. The documentation acceptance item is checked.

Latest observed runtime blocker was a missing ACTIONS_ID_TOKEN_REQUEST_URL during inspection. v1.4.2 addresses the identified expansion path; a successful fresh inspection/issuance run has not yet been confirmed. Actual pin adoption is tracked by Homelab/actual-budget#16. Inspection mode does not deploy or alter the working production app.

Remaining acceptance: validate the new run, activate the reviewed OpenBao trust with platform#24, demonstrate two deployments with freshly issued credentials and no manual secret replacement, exercise rejection/expiry/cleanup cases, and verify the issued identity against the permission contract. Keep legacy credentials until the replacement is proven.

Owner requirement: no credential renewal every few hours by hand. Short-lived credentials issued automatically per run meet that requirement; any credential that still needs manual rotation should have a rotation interval of at least three months. Shared organization configuration should support many apps, while issuance remains scoped per application. Complete dev/prod selection and promotion are tracked in Homelab/workflows#5. Maintain explicit stage/progress logging and safe failure summaries throughout.

Progress update — 2026-09-08 Actual is accepted in production, so this is now active automation work for all future application deployments, not a prerequisite still waiting on the first migration. Implemented and released: - Homelab/workflows#26 / v1.4.0: inspect and OpenBao credential modes, per-run issuance, temporary kubeconfig handling, cleanup/revocation, and an explicit per-app permission contract (required and forbidden authorization checks). - Homelab/workflows#27 / v1.4.1: actionable, redacted credential inspection errors. - Homelab/workflows#28 / v1.4.2: preserve OIDC enablement through reusable-workflow expansion by declaring it at workflow level as well as job level. - Bootstrap, onboarding, organization/repository configuration, and recovery/revocation documentation are implemented alongside Homelab/platform#27. The documentation acceptance item is checked. Latest observed runtime blocker was a missing ACTIONS_ID_TOKEN_REQUEST_URL during inspection. v1.4.2 addresses the identified expansion path; a successful fresh inspection/issuance run has not yet been confirmed. Actual pin adoption is tracked by Homelab/actual-budget#16. Inspection mode does not deploy or alter the working production app. Remaining acceptance: validate the new run, activate the reviewed OpenBao trust with platform#24, demonstrate two deployments with freshly issued credentials and no manual secret replacement, exercise rejection/expiry/cleanup cases, and verify the issued identity against the permission contract. Keep legacy credentials until the replacement is proven. Owner requirement: no credential renewal every few hours by hand. Short-lived credentials issued automatically per run meet that requirement; any credential that still needs manual rotation should have a rotation interval of at least three months. Shared organization configuration should support many apps, while issuance remains scoped per application. Complete dev/prod selection and promotion are tracked in Homelab/workflows#5. Maintain explicit stage/progress logging and safe failure summaries throughout.
Author
Member

Runtime evidence: Actual run #87 succeeded on main at a1a10835404c9d65fcb26f92e1dd2366c15b74f2: https://git.gitchegumi.com/Homelab/actual-budget/actions/runs/87/jobs/1/attempt/1

The inspection job retrieved and displayed the allowlisted OIDC claims, resolving the missing ACTIONS_ID_TOKEN_REQUEST_URL blocker. Observed issuer https://git.gitchegumi.com/api/actions, audience homelab-deployment, repository Homelab/actual-budget, ref refs/heads/main, event workflow_call, workflow_ref Homelab/actual-budget/.forgejo/workflows/deploy-bundle.yml@refs/heads/main, and subject repo:Homelab-6/actual-budget-18:ref:refs/heads/main.

Important remaining check: ref_protected is the string "false" in the observed claims. Resolve the branch-protection/claim discrepancy before configuring trust; do not simply weaken the protected-ref requirement. Inspection decodes claims without validating their signature and does not log into OpenBao, issue Kubernetes credentials, or deploy Actual. Next is reviewed trust setup and live issuance/permission validation. The two-deployment acceptance remains open.

Runtime evidence: Actual run #87 succeeded on main at a1a10835404c9d65fcb26f92e1dd2366c15b74f2: https://git.gitchegumi.com/Homelab/actual-budget/actions/runs/87/jobs/1/attempt/1 The inspection job retrieved and displayed the allowlisted OIDC claims, resolving the missing ACTIONS_ID_TOKEN_REQUEST_URL blocker. Observed issuer https://git.gitchegumi.com/api/actions, audience homelab-deployment, repository Homelab/actual-budget, ref refs/heads/main, event workflow_call, workflow_ref Homelab/actual-budget/.forgejo/workflows/deploy-bundle.yml@refs/heads/main, and subject repo:Homelab-6/actual-budget-18:ref:refs/heads/main. Important remaining check: ref_protected is the string "false" in the observed claims. Resolve the branch-protection/claim discrepancy before configuring trust; do not simply weaken the protected-ref requirement. Inspection decodes claims without validating their signature and does not log into OpenBao, issue Kubernetes credentials, or deploy Actual. Next is reviewed trust setup and live issuance/permission validation. The two-deployment acceptance remains open.
Author
Member

Verified live credential issuance on 2026-09-08 with workflows v1.4.3 and Actual main commit 15fcde4f2fbe4fbe181fc622c2f488cf01ed8526:

  • Run #95: validation and cleanup passed in 3.5 seconds.
  • Run #96: a second fresh owner dispatch passed in 3.4 seconds.

Both obtained Forgejo OIDC identity, authenticated through OpenBao, requested a two-hour Kubernetes credential, verified identity/lifetime, passed all 12 required and 7 forbidden permission probes, and logged successful OpenBao session revocation. No deployment command ran. This establishes repeatable automatic issuance without manual token replacement, not two deployments or dev/prod promotion.

The earlier TLS failure came from public DNS reaching a gateway serving the app.gitchegumi.com certificate. The owner reports resolving the runner path with a hosts-file mapping for openbao.admin.app.gitchegumi.com to 10.0.0.240; certificate verification remains enabled. Carry this mapping into internal DNS during the planned Technitium migration.

OpenBao trust is now configured and live issuance is verified. Remaining acceptance includes complete deployment execution and environment promotion, plus outstanding live rejection/expiry cases. Keep this issue open for those checks; promotion is coordinated with workflows#5.

Verified live credential issuance on 2026-09-08 with workflows v1.4.3 and Actual main commit 15fcde4f2fbe4fbe181fc622c2f488cf01ed8526: - [Run #95](https://git.gitchegumi.com/Homelab/actual-budget/actions/runs/95/jobs/1/attempt/1): validation and cleanup passed in 3.5 seconds. - [Run #96](https://git.gitchegumi.com/Homelab/actual-budget/actions/runs/96/jobs/1/attempt/1): a second fresh owner dispatch passed in 3.4 seconds. Both obtained Forgejo OIDC identity, authenticated through OpenBao, requested a two-hour Kubernetes credential, verified identity/lifetime, passed all 12 required and 7 forbidden permission probes, and logged successful OpenBao session revocation. No deployment command ran. This establishes repeatable automatic issuance without manual token replacement, not two deployments or dev/prod promotion. The earlier TLS failure came from public DNS reaching a gateway serving the app.gitchegumi.com certificate. The owner reports resolving the runner path with a hosts-file mapping for openbao.admin.app.gitchegumi.com to 10.0.0.240; certificate verification remains enabled. Carry this mapping into internal DNS during the planned Technitium migration. OpenBao trust is now configured and live issuance is verified. Remaining acceptance includes complete deployment execution and environment promotion, plus outstanding live rejection/expiry cases. Keep this issue open for those checks; promotion is coordinated with workflows#5.
Author
Member

Update — 2026-09-08: workflows#30, platform#30, bundles#7 and actual-budget#18 are merged; workflows v1.5.0 is released. The shared deployment Action now selects dev/prod from the same signed release and obtains credentials through Forgejo OIDC/OpenBao. Actual dev deployment and login/functionality are owner-confirmed successful, using isolated disposable storage.

Production run https://git.gitchegumi.com/Homelab/actual-budget/actions/runs/105/jobs/1/attempt/1 obtained credentials, passed verification/rescan and reached the Helm upgrade. It failed on field ownership left by the manual production URL cutover (kubectl-patch/kubectl-set); cleanup revoked the OpenBao session. The owner confirmed the existing production Deployment/pod remain 1/1 Running. A one-time metadata-only ownership repair was prepared; the production retry is pending confirmation. Do not count the failed run as successful promotion.

The expanded per-app contract retains required/forbidden probes, with 20 required and 7 forbidden checks and reviewed namespace-scoped RBAC. This acceptance item is now checked. Keep the issue In Progress: a second successful deployment, production promotion, and remaining live rejection/expiry acceptance are still outstanding. Static PV/bootstrap and future-app trust onboarding remain platform prerequisites.

Update — 2026-09-08: workflows#30, platform#30, bundles#7 and actual-budget#18 are merged; workflows v1.5.0 is released. The shared deployment Action now selects dev/prod from the same signed release and obtains credentials through Forgejo OIDC/OpenBao. Actual dev deployment and login/functionality are owner-confirmed successful, using isolated disposable storage. Production run https://git.gitchegumi.com/Homelab/actual-budget/actions/runs/105/jobs/1/attempt/1 obtained credentials, passed verification/rescan and reached the Helm upgrade. It failed on field ownership left by the manual production URL cutover (kubectl-patch/kubectl-set); cleanup revoked the OpenBao session. The owner confirmed the existing production Deployment/pod remain 1/1 Running. A one-time metadata-only ownership repair was prepared; the production retry is pending confirmation. Do not count the failed run as successful promotion. The expanded per-app contract retains required/forbidden probes, with 20 required and 7 forbidden checks and reviewed namespace-scoped RBAC. This acceptance item is now checked. Keep the issue In Progress: a second successful deployment, production promotion, and remaining live rejection/expiry acceptance are still outstanding. Static PV/bootstrap and future-app trust onboarding remain platform prerequisites.
Author
Member

Production is now verified: Actual run 107 selected prod/actual-budget, deployed release ci-a20d05f741c712161c17d2fed8f9312adc2b69bf-422, passed deployment/rollout checks and revoked the OpenBao session. Together with the owner-confirmed successful dev deployment, the two-deployment and released-Actual-adoption items are checked.

Follow-up #31 and Homelab/platform#31 make disposable namespace cleanup independent of prod: selected-environment probes, durable bootstrap definitions and automatic dev namespace/binding recreation. All 112 workflow tests and platform local checks pass. Changes are in review, not installed/released. Keep this issue open for bootstrap rollout/live delete-recreate acceptance and outstanding live rejection/expiry cases. Wiki status and reusable runbook updated.

Production is now verified: [Actual run 107](https://git.gitchegumi.com/Homelab/actual-budget/actions/runs/107/jobs/1/attempt/1) selected prod/actual-budget, deployed release ci-a20d05f741c712161c17d2fed8f9312adc2b69bf-422, passed deployment/rollout checks and revoked the OpenBao session. Together with the owner-confirmed successful dev deployment, the two-deployment and released-Actual-adoption items are checked. Follow-up #31 and Homelab/platform#31 make disposable namespace cleanup independent of prod: selected-environment probes, durable bootstrap definitions and automatic dev namespace/binding recreation. All 112 workflow tests and platform local checks pass. Changes are in review, not installed/released. Keep this issue open for bootstrap rollout/live delete-recreate acceptance and outstanding live rejection/expiry cases. Wiki status and reusable runbook updated.
Author
Member

Completed with owner-approved scope on 2026-09-09. Workflows/platform #31 and Actual #19/#20 plus bundles #8 are merged; workflows v1.6.0 is adopted and the owner ran platform bootstrap. Both live namespace and RoleBinding admission denial probes passed.

Evidence: Actual runs 104 and 107 deployed dev/prod from the same signed release without rebuilding. Run 118 exercised production with dev removed: selected prod, passed 12 required and 7 forbidden permission checks, verified signatures/hashes, rescanned, deployed only the production package, passed rollout/HTTPS health and revoked the OpenBao session. Automatic per-run credentials eliminate manual kubeconfig replacement.

Explicitly deferred, NOT passed: remaining live unauthorized repository/ref/audience and credential-expiry cases; comprehensive PR publish/deploy credential-isolation proof; dev namespace delete/recreate acceptance. The owner elected to verify dev recreation naturally on its next use. Existing unchecked compound criteria retain that distinction. These are not blockers for the accepted delivery automation scope. Future apps still require reviewed per-app platform trust/permission onboarding. Closing and moving to Done at the owner’s request.

Completed with owner-approved scope on 2026-09-09. Workflows/platform #31 and Actual #19/#20 plus bundles #8 are merged; workflows v1.6.0 is adopted and the owner ran platform bootstrap. Both live namespace and RoleBinding admission denial probes passed. Evidence: Actual runs [104](https://git.gitchegumi.com/Homelab/actual-budget/actions/runs/104) and [107](https://git.gitchegumi.com/Homelab/actual-budget/actions/runs/107) deployed dev/prod from the same signed release without rebuilding. [Run 118](https://git.gitchegumi.com/Homelab/actual-budget/actions/runs/118/jobs/1/attempt/1) exercised production with dev removed: selected prod, passed 12 required and 7 forbidden permission checks, verified signatures/hashes, rescanned, deployed only the production package, passed rollout/HTTPS health and revoked the OpenBao session. Automatic per-run credentials eliminate manual kubeconfig replacement. Explicitly deferred, NOT passed: remaining live unauthorized repository/ref/audience and credential-expiry cases; comprehensive PR publish/deploy credential-isolation proof; dev namespace delete/recreate acceptance. The owner elected to verify dev recreation naturally on its next use. Existing unchecked compound criteria retain that distinction. These are not blockers for the accepted delivery automation scope. Future apps still require reviewed per-app platform trust/permission onboarding. Closing and moving to Done at the owner’s request.
kiyi closed this issue 2026-09-09 11:18:48 -05:00
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Homelab/workflows#19
No description provided.