- Add infrastructure/logs/ to .gitignore so ansible run logs (infrastructure/logs/ansible/*.log) are never accidentally committed - Track docs/plans/junie/ekosystem-uuid-cnpg-wire.md — Junie brief for wiring the ekosystem UUID schema to the CNPG cluster (queue item #13) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .idea/runConfigurations | ||
| archive/2026-04-cnpg-and-gitlab-cleanup | ||
| authority | ||
| conf | ||
| demo | ||
| deploy | ||
| docs | ||
| etc | ||
| gitea | ||
| img | ||
| infrastructure | ||
| k3s | ||
| k8s | ||
| knoe | ||
| knoe-db | ||
| mock_val | ||
| modes | ||
| monitoring | ||
| pg-knoe-auth | ||
| scan | ||
| scripts | ||
| src | ||
| supabase | ||
| tests | ||
| tools | ||
| .coveragerc | ||
| .gitignore | ||
| .gitlab-ci.yml | ||
| AGENTS.md | ||
| ansible_min.cfg | ||
| ansible.cfg | ||
| ansible.sh | ||
| BUILD.md | ||
| CLAUDE.md | ||
| config.py | ||
| config.sh | ||
| deploy.sh | ||
| env.sh | ||
| Executing | ||
| install.py | ||
| install.sh | ||
| knoe-db.iml | ||
| knoe.iml | ||
| knoe.sh | ||
| knoe.spec | ||
| LICENSE | ||
| Makefile | ||
| pom.xml | ||
| pyproject.toml | ||
| qodana.yaml | ||
| README.md | ||
| requirements-test.txt | ||
| requirements.txt | ||
| run_with_coverage.sh | ||
| status.py | ||
| supabase.sh | ||
| update.sh | ||
Knoe
Knoe makes it practical to run a Supabase-style platform across air-gapped, edge, and cloud environments.
It packages the core building blocks needed for a modern internal developer platform around PostgreSQL, object storage, secrets, auth, observability, and Kubernetes-native operations — with a bias toward simple deployment, shard-based scale-out, and deterministic ingestion.
Platform badges
What Knoe is
Knoe is an infrastructure stack for running a Supabase-like data and application platform across constrained, sovereign, and cloud environments, including:
- air-gapped networks
- edge and small-cluster deployments (K3s, K3d)
- Google Cloud Platform (GCP) deployments
- sovereign or private data environments
- disconnected labs and field systems
- internal platforms where cloud dependencies are undesirable
The design goal is not to mimic Supabase branding or every managed feature exactly.
The design goal is to provide the useful substrate people actually want:
- PostgreSQL as the center of gravity
- object storage
- auth integration
- secret management
- ingress and service exposure
- observability
- reproducible Kubernetes deployment
- application and worker services around the database
- ingestion patterns that are safe, resumable, and idempotent
Core idea
Knoe can run Supabase-style workloads in an air gap, on the edge, or in the cloud.
That means:
- PostgreSQL remains the system of record, managed as
knoe-dbwithin theknoe-systemnamespace - services are deployed on Kubernetes (K3d locally, K3s on-prem, GKE on GCP)
- auth can come from local identity systems or cloud OIDC where available
- object storage stays inside the environment
- secrets stay inside the environment
- ingestion does not depend on live internet services
- the stack can be deployed in shards for locality, resilience, and operational simplicity
Main components
Application layer
- Next.js app for the user-facing platform
- knoe-agent worker for async and background execution
Data layer
- knoe-db — CloudNativePG-managed PostgreSQL cluster in the
knoe-systemnamespace - PostgreSQL as the primary relational store
- append-only fact tables for durable ingestion and replay-friendly modeling
- PostgreSQL COPY for efficient bulk ingest
Deployed add-ons
- Supabase — self-hosted Supabase stack for auth, realtime, storage, and API gateway
- ArgoCD — GitOps continuous delivery for the
knoe-systemcluster - Gitea — lightweight self-hosted Git service
- GitLab — full-featured self-hosted DevOps platform
Storage and secrets
- Garage for S3-compatible object storage
- OpenBao for secret storage and secret distribution
Identity
- Dev auth: Samba AD + IdP
- Cloud auth: Google Workspace OIDC
Observability
- Vector for log and event shipping
- Prometheus / Grafana for metrics and dashboards
Platform operations
- K3d — local development clusters
- K3s — on-prem lightweight Kubernetes
- GCP / GKE — cloud-hosted cluster tier
- Helm
- ArgoCD
- Ansible
- OpenTofu
Ingestion model
Knoe is designed around deterministic, replayable ingestion.
Key patterns:
- SQLite delta cartridges as portable input units
- append-only fact tables for auditability and recovery
- PostgreSQL COPY for high-throughput loading
- queue-driven workers using
SKIP LOCKED - idempotent ingestion so retries are safe
- shard-based deployment so data movement stays deliberate and bounded
This makes the platform well suited to environments where data may arrive in batches, be transferred physically, or need careful replay and provenance.
Architecture at a glance
flowchart LR
subgraph Clients
U["Users / Operators"]
end
subgraph knoe-system ["knoe-system (Kubernetes)"]
A["Next.js App"]
W["knoe-agent worker"]
SB["Supabase\n(auth · realtime · storage · API)"]
ARGO["ArgoCD\n(GitOps)"]
GITEA["Gitea\n(Git)"]
GITLAB["GitLab\n(DevOps)"]
PG["knoe-db\n(CloudNativePG / PostgreSQL)"]
OBJ["Garage\n(Object Store)"]
SEC["OpenBao\n(Secrets)"]
OBS["Vector / Prometheus / Grafana\n(Observability)"]
ING["Traefik / Kong\n(Ingress)"]
end
subgraph Infra ["Infrastructure"]
K3D["K3d\n(local dev)"]
K3S["K3s\n(on-prem)"]
GCP["GCP / GKE\n(cloud)"]
end
subgraph Identity
AUTH["Samba AD / Google Workspace OIDC"]
end
U --> ING
ING --> A
ING --> SB
ING --> ARGO
ING --> GITEA
ING --> GITLAB
A --> PG
A --> OBJ
A --> SEC
A --> AUTH
W --> PG
W --> OBJ
W --> SEC
SB --> PG
SB --> OBJ
SB --> AUTH
ARGO --> A
ARGO --> W
ARGO --> SB
ARGO --> PG
ARGO --> OBJ
ARGO --> SEC
GITEA --> ARGO
GITLAB --> ARGO
K3D & K3S & GCP --> |hosts| knoe-system
OBS -.-> PG
OBS -.-> A
OBS -.-> W
Deployment model
Knoe favors simple, understandable deployment over excessive platform ceremony.
Typical characteristics:
- Kubernetes-native deployment across K3d (local), K3s (on-prem), and GCP (cloud)
- lightweight K3s/K3d-friendly footprint
- HA where it matters
- shard-oriented layout instead of one giant control surface
- GitOps-driven operations via ArgoCD, backed by Gitea or GitLab
- support for small clusters, including Pi-based or edge environments
Use cases
Knoe is a good fit for teams that need:
- a PostgreSQL-centered application stack inside a disconnected or sovereign environment
- a self-hosted substrate for Supabase-style internal platforms
- ingestion from offline or intermittently connected sources
- reproducible deployment on small Kubernetes clusters (K3s/K3d) or GCP
- strong control over secrets, storage, and identity boundaries
- a full GitOps workflow with ArgoCD, Gitea, and GitLab
Project principles
- Air-gap first
- Postgres first
- Simple over ornate
- Deterministic ingestion
- Kubernetes-native
- Shard-friendly
- Operationally boring where possible
Repository scope
This repository contains the infrastructure and platform materials used to stand up Knoe components, including Kubernetes deployment, database operations (knoe-db in knoe-system), storage, auth, observability, and supporting services.
As the project evolves, this README should stay focused on:
- what Knoe is
- why it exists
- the major building blocks
- the deployment model
- the operational philosophy
Detailed setup docs, cluster procedures, and host-specific notes should live in dedicated documents under docs/, ops/, k8s/, or role-specific subdirectories rather than expanding this file indefinitely.
prole.org deployment
This repository is the prole.org fork of the upstream knoe-db platform. It runs a production k3s cluster on a three-node ARM64 LAN (myrddin / gandalf / merlin) with Samba AD providing Kerberos identity for single sign-on across all platform services.
Live services
| Service | URL | Auth |
|---|---|---|
| Supabase Studio | https://db.prole.org |
SPNEGO → OIDC → Studio |
| Gitea | https://git.prole.org |
SPNEGO (auto) or Gitea login |
| PostgreSQL | pg.prole.org:5432 |
mTLS + CNPG cert |
| SSH (Gitea) | git.prole.org:3022 |
SSH key |
Cluster nodes
| Host | Role | IP |
|---|---|---|
myrddin.prole.org |
k3s server, Samba AD DC, container registry | 10.0.0.3 |
gandalf.prole.org |
k3s agent | 10.0.0.5 |
merlin.prole.org |
k3s agent | 10.0.0.6 |
Kubectl context: prole-service-cluster (kubeconfig at knoe-k3s.kubeconfig).
Key namespaces
| Namespace | Contents |
|---|---|
knoe-system |
knoe-auth, Kong API gateway, KDC, Redis, Traefik |
gitea |
Gitea, gitea-spnego-proxy |
knoe-db |
CloudNativePG cluster |
supabase |
Supabase Studio, Kong (supabase), oauth2-proxy |
Identity & SSO
All platform services use a unified Kerberos SSO stack. The flow from browser to service is:
Browser (Chrome, Safari, curl --negotiate)
│ kinit-obtained TGT from PROLE.ORG KDC (myrddin.prole.org)
▼
Traefik (TLS termination, *.prole.org wildcard cert via ACME)
│
▼
Kong API gateway (knoe-system/knoe-svc-kong)
│ routes by Host header
├── db.prole.org ──► oauth2-proxy ──► knoe-auth (OIDC) ──► Supabase Studio
└── git.prole.org ──► gitea-spnego-proxy (port 4000) ──► Gitea (port 3000)
Kerberos realm
- Realm:
PROLE.ORG - KDC / AD DC:
myrddin.prole.org(Samba 4,10.0.0.3) - Cross-realm trust:
PROLE.ORG ↔ KNOE.LOCAL(in-cluster MIT KDC for knoe-auth internal use) - Encryption: AES256 + AES128 only (
msDS-SupportedEncryptionTypes=24); RC4 disabled on all service accounts
knoe-auth (OIDC provider — api.prole.org/auth)
knoe-auth is a Spring Boot 3 / JDK 21 OIDC authorization server that validates Kerberos SPNEGO tokens and issues OIDC tokens for downstream services.
Key implementation details:
| Detail | Value |
|---|---|
| Deployment | knoe-system/knoe-auth |
| SPNEGO endpoint | https://api.prole.org/auth/spnego |
| Keytab secret | knoe-system/knoe-auth-keytab (HTTP/api.prole.org@PROLE.ORG, AES-only) |
| JDK Subject API | Subject.callAs() — not Subject.doAs() (removed in JDK 21) |
| RC4 | Hard-removed in JDK 21 JGSS — keytab and AD account must be AES-only |
| krb5.conf | Mounted via ConfigMap; permitted_enctypes = aes256 aes128 (cannot re-enable RC4 here) |
Keytab provisioning (etc/init_knoe_users.sh):
# On myrddin — set AES-only, reset password, export and rekey keytab
sudo ldbmodify -H /var/lib/samba/private/sam.ldb <<EOF
dn: CN=knoe-auth,CN=Users,DC=prole,DC=org
changetype: modify
replace: msDS-SupportedEncryptionTypes
msDS-SupportedEncryptionTypes: 24
EOF
sudo samba-tool user setpassword knoe-auth --newpassword="$(openssl rand -base64 32 | tr -d '=/+' | head -c 40)"
# Export full domain keytab; rekey to HTTP/api.prole.org@PROLE.ORG in Python
# (samba-tool exportkeytab --principal=HTTP/... returns empty — see note below)
Note: samba-tool domain exportkeytab --principal=HTTP/hostname always produces an empty keytab on Samba 4 — the filter only matches UPN format, not SPN format. The correct procedure is to export the full domain keytab and rekey the AES entries to the SPN principal name using the Python script embedded in infrastructure/playbooks/gitea_spnego_keytab.yml (same logic applies for all HTTP service principals).
Supabase Studio SSO (db.prole.org)
Browser → Kong → oauth2-proxy → knoe-auth OIDC → oauth2-proxy (cookie set)
→ Kong (upstream to studio)
→ Supabase Studio
- oauth2-proxy handles the OIDC callback and sets a session cookie (
_oauth2_proxy) - Supabase Kong dashboard route:
corsplugin only —basic-authplugin removed (it blocked oauth2-proxy's proxied requests) - The
basic-authremoval is applied directly to the live ConfigMap and must be re-applied after anyhelm upgradeof the supabase chart
Supabase Studio access:
# Via browser (automatic SPNEGO with Chrome policy)
open https://db.prole.org
# Check oauth2-proxy is passing through correctly
curl -I https://db.prole.org/oauth2/sign_in
Chrome SPNEGO policy (/Library/Managed Preferences/com.google.Chrome.plist):
<key>AuthServerAllowlist</key>
<string>*.prole.org</string>
<key>AuthNegotiateDelegateAllowlist</key>
<string>*.prole.org</string>
Deploy to a Mac workstation:
make workstation
# or: ansible-playbook infrastructure/playbooks/workstation_kerberos.yml --ask-become-pass
git.prole.org SPNEGO (Gitea)
Browser/curl → Kong → gitea-spnego-proxy (:4000) → Gitea (:3000)
│
├─ No Authorization header → 401 + WWW-Authenticate: Negotiate
├─ Authorization: Negotiate <token> → SPNEGO validate → X-WEBAUTH-USER → Gitea auto-login
└─ Authorization: Basic/token → pass-through → Gitea auth
Component: gitea/spnego-proxy/ — Go binary using gokrb5/v8, built for linux/arm64.
| Detail | Value |
|---|---|
| Image | myrddin.prole.org:5000/gitea-spnego-proxy:latest |
| Keytab secret | gitea/gitea-krb5-keytab (HTTP/git.prole.org@PROLE.ORG, AES-only, KVNO 4) |
| AD account | CN=gitea-http,CN=Users,DC=prole,DC=org (msDS-SupportedEncryptionTypes=24) |
| Rebuild | Build on myrddin (native arm64); docker build then docker push localhost:5000/... |
Keytab rotation:
ansible-playbook infrastructure/playbooks/gitea_spnego_keytab.yml -e force_keytab_reset=true
Manual rebuild (if source changed):
# Transfer source and build on myrddin (all nodes are arm64)
tar -czf /tmp/src.tar.gz gitea/spnego-proxy/ && scp /tmp/src.tar.gz myrddin:/tmp/
ssh myrddin "mkdir -p /tmp/spnego-build && tar -xzf /tmp/src.tar.gz -C /tmp/spnego-build && \
sudo docker build -t localhost:5000/gitea-spnego-proxy:latest /tmp/spnego-build/gitea/spnego-proxy/ && \
sudo docker push localhost:5000/gitea-spnego-proxy:latest"
kubectl --context=prole-service-cluster -n gitea rollout restart deployment/gitea-spnego-proxy
Smoke test:
curl -s -o /dev/null -w "%{http_code}\n" https://git.prole.org/ # → 401 (challenge)
curl -s -o /dev/null -w "%{http_code}\n" --negotiate -u : https://git.prole.org/ # → 200 (authed)
Status
As of 2026-05-28 the following work has shipped on the prole.org fork:
Identity / SSO (May 2026)
feat(gitea)— SPNEGO Kerberos SSO forgit.prole.org; proxy issuesWWW-Authenticate: Negotiatechallenge;gitea_spnego_keytab.ymlAnsible playbook for full provisioning lifecycle (5077e13)fix(ansible)— workstation install script +make workstationtarget for Chrome SPNEGO policy on personal Macs (b245593)fix(spnego)—Subject.callAs(), AES-only keytab, andkrb5.confsync for JDK 21 knoe-auth (c1d2a91)feat(oidc)— knoe-auth routing through Kong; Flyway schema baseline for clean OIDC DB (9523045)feat(prole)— knoe-auth bootstrap on k3s; tenant onboarding; cluster stabilisation (cf33342)
Infrastructure (earlier)
fix(cfg)—_validate_cfg_valuesprevents MagicMock reprs from leaking intoconf/*.cfgfeat(env)—gke_kubecontext prefix auto-detected asprod;status.pycontext helpersrefactor(mock_val)—prole_*shell lib and cfg tooling renamed toknoe_*namespacefeat(mock_val)— init scripts rewritten; 10+ new service init scripts addedfeat(scripts)— upstream knoe-db sync script + procedure docfeat(pg-knoe-auth)— upstream PostgreSQL JWT auth extension imported; compiled inknoe-dbimage
Working tree is clean. Browser SPNEGO SSO is live on db.prole.org and git.prole.org.
Upstream fork — knoe-db
This repository is an independent fork of the upstream knoe-db project:
git@git.knoe.dev:knoe-dev/knoe-db.git
Upstream changes are pulled into a dated review branch (upstream/knoe-db/YYYYMMDD) using the sync script, inspected, and selectively merged into main.
# Preview what the script will do
./scripts/sync_upstream_knoe_db.sh --dry-run
# Run the sync (requires a clean working tree)
./scripts/sync_upstream_knoe_db.sh
See docs/upstream-knoe-db-sync.md for the full review-and-merge procedure.
Fork-specific files
Files added or substantially modified in the prole.org fork (not present or not relevant upstream):
| Path | Purpose |
|---|---|
infrastructure/ |
Ansible roles, playbooks, and inventory for the prole.org cluster |
infrastructure/playbooks/gitea_spnego_keytab.yml |
Gitea SPNEGO keytab provisioning |
infrastructure/playbooks/workstation_kerberos.yml |
Chrome SPNEGO policy + krb5.conf for macOS workstations |
infrastructure/playbooks/kerberos_trust_setup.yml |
PROLE.ORG ↔ KNOE.LOCAL cross-realm trust |
infrastructure/bin/install_workstation.sh |
Wrapper for workstation Ansible (adds --ask-become-pass) |
gitea/spnego-proxy/ |
Go SPNEGO reverse proxy for git.prole.org |
deploy/opentofu/k3s/manifests/knoe/gitea-spnego-proxy.yaml |
k8s deployment for the SPNEGO proxy |
conf/k3s.cfg |
prole.org k3s cluster configuration |
License
Add the project license here.