mirror of
https://github.com/dredx/prole.git
synced 2026-09-23 10:13:58 +00:00
Replace the knoe ASCII art banner with a Prole. banner linking to all four live services (svc/db/git/api.prole.org). Add # Prole. as the top-level header with a one-paragraph description of the homelab deployment and its relationship to upstream knoe-db. Demote the Knoe platform overview to ## Knoe platform. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
547 lines
22 KiB
Markdown
547 lines
22 KiB
Markdown
<div align="center">
|
|
<a href="https://svc.prole.org"><pre>
|
|
# #############################################
|
|
# ╭───────────────────────────────────────╮ #
|
|
# │ │ #
|
|
# │ ___ ____ ___ _ ____ │ #
|
|
# │ | _ \| _ \/ _ \| | | ___| │ #
|
|
# │ | _/| |_) | | | | | |___ \ │ #
|
|
# │ | | | __/| |_| | |___ ___) | │ #
|
|
# │ |_| |_| \___/|_____|____/ . │ #
|
|
# │ │ #
|
|
# │ svc · db · git · api │ #
|
|
# ╰───────────────────────────────────────╯ #
|
|
# #############################################
|
|
</pre></a>
|
|
|
|
[svc.prole.org](https://svc.prole.org) ·
|
|
[db.prole.org](https://db.prole.org) ·
|
|
[git.prole.org](https://git.prole.org) ·
|
|
[api.prole.org](https://api.prole.org)
|
|
|
|
</div>
|
|
|
|
# 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
|
|
|
|
<div align="center">
|
|
|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|
|
|

|
|

|
|

|
|

|
|

|
|

|
|
|
|

|
|

|
|

|
|

|
|
|
|

|
|

|
|

|
|
|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|

|
|
|
|

|
|

|
|

|
|

|
|

|
|

|
|
|
|

|
|

|
|

|
|

|
|
|
|
</div>
|
|
|
|
---
|
|
|
|
## 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 <<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: `cors` plugin only — `basic-auth` plugin **removed** (it blocked oauth2-proxy's proxied requests)
|
|
- The `basic-auth` removal is applied directly to the live ConfigMap and must be re-applied after any `helm upgrade` of the supabase chart
|
|
|
|
Supabase Studio access:
|
|
```bash
|
|
# 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`):
|
|
```xml
|
|
<key>AuthServerAllowlist</key>
|
|
<string>*.prole.org</string>
|
|
<key>AuthNegotiateDelegateAllowlist</key>
|
|
<string>*.prole.org</string>
|
|
```
|
|
|
|
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 <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:
|
|
```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.
|