# Prole.
**Prole** is the reference homelab deployment of the **[Knoe](https://git.knoe.dev)** platform — running on a three-node k3s ARM64 cluster with Samba Active Directory, Kerberos SSO, and Google Workspace login across all services.
This repo is the `prole.org` fork of [knoe-db](https://git.knoe.dev/knoe-dev/knoe-db), tracking upstream and carrying the cluster-specific manifests, identity configuration, and operational tooling for `prole.org`.
---
## Knoe platform
**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-db` within the `knoe-system` namespace
- 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-system` namespace
- **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-system` cluster
- **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
```mermaid
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`):
```bash
# On myrddin — set AES-only, reset password, export and rekey keytab
sudo ldbmodify -H /var/lib/samba/private/sam.ldb <AuthServerAllowlist
*.prole.org
AuthNegotiateDelegateAllowlist
*.prole.org
```
Deploy to a Mac workstation:
```bash
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 → 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:
```bash
ansible-playbook infrastructure/playbooks/gitea_spnego_keytab.yml -e force_keytab_reset=true
```
Manual rebuild (if source changed):
```bash
# 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:
```bash
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 for `git.prole.org`; proxy issues `WWW-Authenticate: Negotiate` challenge; `gitea_spnego_keytab.yml` Ansible playbook for full provisioning lifecycle (`5077e13`)
- `fix(ansible)` — workstation install script + `make workstation` target for Chrome SPNEGO policy on personal Macs (`b245593`)
- `fix(spnego)` — `Subject.callAs()`, AES-only keytab, and `krb5.conf` sync 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_values` prevents MagicMock reprs from leaking into `conf/*.cfg`
- `feat(env)` — `gke_` kubecontext prefix auto-detected as `prod`; `status.py` context helpers
- `refactor(mock_val)` — `prole_*` shell lib and cfg tooling renamed to `knoe_*` namespace
- `feat(mock_val)` — init scripts rewritten; 10+ new service init scripts added
- `feat(scripts)` — upstream knoe-db sync script + procedure doc
- `feat(pg-knoe-auth)` — upstream PostgreSQL JWT auth extension imported; compiled in `knoe-db` image
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`.
```bash
# 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`](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.