Deploy self-hosted Infisical to any Kubernetes cluster, built with chant
  • TypeScript 98.2%
  • Just 1.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
jhgaylor 91cdf13039 Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster
Component-based (namespace/db/redis/migrate/app), tiered (light/production/
production-ha), BYO-everything adoption seams, generated CI (GitHub/GitLab/
Forgejo), and 11 lifecycle Ops (seed/backup/restore/rotate/watch/reconcile/
upgrade/teardown/local k3d up-down). Built with chant and its Kubernetes
lexicon, in the style of INTENTIUS/loomster.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 23:57:02 +00:00
.chant/rules Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
.forgejo/workflows Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
.github/workflows Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
.gitlab Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
docs Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
ops Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
skills/infisical-chant Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
src Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
.gitignore Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
.gitlab-ci.yml Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
chant.config.ts Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
justfile Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
package-lock.json Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
package.json Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
README.md Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
tsconfig.json Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00
vitest.config.ts Initial commit: Infisical on chant — deploy self-hosted Infisical to any Kubernetes cluster 2026-07-24 23:57:02 +00:00

infisical-chant

A deployment of Infisical (self-hosted) you drive from the repo, for any Kubernetes cluster — a local k3d cluster, EKS, GKE, AKS, k3s, OpenShift, whatever kubectl can reach. Five components, three tiers (light / production / production-ha), generated CI, and a naming scheme that lets many Infisical instances coexist in one namespace or across many clusters without collision. Built with chant and its Kubernetes lexicon, in the style of loomster — chant's own AWS/CDK reference deployment — though you run infisical-chant by its verbs, not by knowing chant.

Drive it with your agent

Clone it and your agent already knows how to operate it:

git clone <this-repo>
cd infisical-chant && npm install

The checkout ships skills/infisical-chant/SKILL.md, the capability map an agent reads on its own — every lifecycle verb, the golden paths, and the guardrails that keep a deploy from locking itself out. chant also serves an MCP server (chant serve mcp, stdio) for inspecting and building the graph. From the checkout, ask your agent to "stand up Infisical locally" and it knows what to run.

Docs: Tiers & targets · Naming & cross-stack wiring · Adoption (BYO) · Run it locally · Seeding · Backup & restore

Where it runs

  • Locally, on a real k3d Kubernetes cluster in Docker, no cloud account — just local-up (see docs/local.md). Unlike an AWS-emulator-based local loop, this is an actual (if small) Kubernetes cluster running the exact manifests a real deploy uses.
  • Anywhere else kubectl can reach — this project makes no cloud-specific assumptions in its core composites; cloud-managed pieces (ingress, storage class) are opt-in adoption seams, not defaults (see docs/adoption.md).

Run it locally

just local-up     # a real k3d cluster + the full stack, needs Docker + k3d
just local-down   # tear it down

See docs/local.md for the full walkthrough, including seeding the first admin org and reaching the app through a port-forward.

Develop

package.json consumes published @intentius/chant and its lexicons from npm. No sibling checkout, no codegen step.

just install   # npm install
just build     # typecheck
just lint      # chant lint . — core k8s-lexicon rules + .chant/rules/ project-local rules
just test      # vitest run
just check     # all of the above

Components

Five stacks, deployed in dependency order:

Component Depends on What it is
infisical-namespace — Namespace + ResourceQuota + LimitRange + default-deny NetworkPolicy
infisical-db infisical-namespace Postgres (single-replica StatefulSet, or reference-existing a managed database)
infisical-redis infisical-namespace Redis (single-replica StatefulSet, or reference-existing a managed cache)
infisical-migrate infisical-db One-shot Job — runs Infisical's database migrations
infisical-app infisical-db, infisical-redis, infisical-migrate Infisical's own container (backend API + built frontend), Service, optional Ingress

Every physical name and label comes from the shared naming helper (src/lib/naming.ts); nothing is a literal (.chant/rules/no-hardcoded-name.ts, INF001). Cross-component wiring is a deterministically-derived Secret name, not a live cross-stack lookup — see docs/naming.md for why that's the right call on Kubernetes (where loomster, an AWS/CloudFormation project, needs stackOutput(...)).

Deploy

Each component synthesizes to a plain Kubernetes manifest (chant build src/<component> --lexicon k8s); applying it is kubectl apply, since the k8s lexicon is a synthesis compiler, not a deploy orchestrator (see the chant-k8s skill). The generated CI component pipeline (.github/workflows/components.yml / .gitlab/components.yml / .forgejo/workflows/components.yml, regenerated via chant build --components --generate <target>) wires exactly that: build → lint → synth → kubectl apply, one job per component, needs: mirroring dependsOn. deploy.yml gates it — inert until:

  1. Repo variable DEPLOY = true.
  2. A CI environment named production holding the kubeconfig the job uses.

Lifecycle Ops

Beyond one-shot component deploys, ops/ holds the durable, gated concerns for a running Infisical deployment, as chant Ops on Temporal where they need an approval gate, or on the local executor where they don't.

Op What it does Gated?
infisical-watch Drift detection — kubectl diff against fresh synth. Every tier. No
infisical-reconcile On drift, opens a cloud-to-code PR (owned-only, never mutates the cluster). production/production-ha. No
infisical-upgrade-light Re-run migrations, roll infisical-app to a new image tag. No — local executor
infisical-upgrade-production Same, gated behind an approval phase. Yes
infisical-rotate-auth-secret Rotate the JWT signing secret + restart the app. Never touches ENCRYPTION_KEY (see the skill's Guardrails). Yes
infisical-backup pg_dump via kubectl exec. Additive. No — local executor
infisical-restore-drill Restore the latest backup to a throwaway namespace, assert it's healthy, delete it. No — local executor
infisical-restore Restore a named backup and cut infisical-app over to it. Yes — cutover is destructive
infisical-seed Bootstrap the first admin org via Infisical's own API. No — local executor
infisical-teardown Gated, owned-only, marker-scoped namespace delete. No foreign deletes. Yes
infisical-local-up / infisical-local-down k3d cluster lifecycle for local dev. No — local executor
chant build ops                                    # compile to dist/ops/<name>/
chant run infisical-upgrade-light                  # local executor, no Temporal needed
chant run infisical-upgrade-production --temporal  # pauses at "Approve"
chant run signal infisical-upgrade-production approve-infisical-upgrade-production
npm run watch                                      # one-shot infisical-watch
npm run reconcile                                  # one-shot infisical-reconcile

Generated CI

chant build --components --generate gitlab synthesizes the component pipeline from the same component graph chant graph --components reads. One stage per parallel-safe wave, one job per component, needs: mirroring dependsOn. It's written to .gitlab/components.yml; the root .gitlab-ci.yml includes it and adds a gated deploy job and the scheduled lifecycle jobs.

npm run generate:gitlab   # writes .gitlab/components.yml
just gitlab-validate      # regenerate + diff against the committed copy (fails on drift)

Same for GitHub Actions (npm run generate:github, just github-validate) and Forgejo Actions (npm run generate:forgejo, just forgejo-validate).

Adoption (bring your own infrastructure)

Every referenceable seam — database, cache, app secrets, ingress — exposes provision | reference-existing, set from INFISICAL_* env vars, with no forking of a composite. src/examples/byo/ wires every seam to reference-existing at once. Full matrix: docs/adoption.md.

What this starter is (and isn't)

This is a starter kit: real, typed, lint-clean, unit-tested chant source that synthesizes to valid Kubernetes manifests and generates real CI pipelines — not a hand-wavy sketch. It has not been applied to a live cluster as part of building it (this environment has no Docker/kubectl available to prove that final mile) — just local-up's k3d loop is the intended way to close that gap yourself, and is the first thing to run after cloning. Treat chant build/chant lint/vitest passing as "this compiles and is internally consistent," and a real kubectl apply as the step that proves it deploys.