Establish clean homelab infrastructure baseline
lint / yaml (push) Has been cancelled
lint / ansible (push) Has been cancelled
lint / terraform (push) Has been cancelled

Reorganize the brownfield repository, remove retired and generated artifacts, harden ignore rules, and record the GitOps/IaC redesign.
This commit is contained in:
2026-09-09 16:47:20 +00:00
commit 88a02ababa
418 changed files with 50579 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
# Casdoor — RETIRED (2026-07-10)
Casdoor was an SSO/IdP experiment, evaluated and rejected in favour of **Authelia**
(see `../../apps/authelia/`). Decommissioned:
- Deleted the entire `casdoor` Kubernetes namespace (Helm releases `casdoor` +
`casdoor-postgresql`, deployment, services, secrets, configmap, in-namespace Postgres).
- Dropped the orphaned `casdoor` database from the shared Postgres (`shared-db`).
It was never publicly routed (no cloudflared/gateway ingress) and had no consumers.
This directory is kept only as a tombstone.
+32
View File
@@ -0,0 +1,32 @@
# Keycloak — RETIRED (2026-07-10)
Keycloak has been **decommissioned** and replaced by **Authelia** as the SSO / OIDC
provider (issuer `https://auth.ddupan.top`, backed by Samba AD via LDAP). See
`../../apps/authelia/`.
## What was removed
- The entire `keycloak` Kubernetes namespace (Deployment, Service, bootstrap Job,
ConfigMaps, `keycloak-db-secret`) — `kubectl delete namespace keycloak`.
- A **second, abandoned Keycloak** in the `shared-db` namespace (raw manifests:
`deploy/svc/job/cm keycloak*`) that never became ready (crashlooped ~21.8k times over
82 days). Deleted the four Keycloak objects only; the `shared-postgresql` CNPG tenant in
that namespace was left untouched.
- The `idm.ddupan.top` public-hostname route from the cloudflared tunnel ingress
(`../../infrastructure/cloudflared/terraform/main.tf`). `idm.ddupan.top` now returns HTTP 404.
## Consumers migrated
- **Gitea** — OIDC provider switched from `keycloak` to `authelia`
(`../../apps/gitea/gitea-values.yaml`, secret `gitea-oidc-secret`). The `panxiao81`
account was re-linked to the Authelia source by email (`ACCOUNT_LINKING=auto`).
## Leftovers (intentionally not cleaned up)
- **Orphaned tables** in the shared `postgres` database: Keycloak ran against
`jdbc:postgresql://shared-postgresql.shared-db.svc:5432/postgres` as the
superuser, creating its tables in that DB's `public` schema. They are inert;
dropping ~90 tables by hand was judged risky/low-value. Drop them manually if
you want the DB tidy.
- **DNS**: the `idm.ddupan.top` CNAME still exists at Cloudflare (points at the
tunnel, so it just hits the 404 catch-all). Remove it in the Cloudflare dash if
desired; it is not managed by Terraform.
The manifests in this directory are kept for reference only. Safe to delete.
+25
View File
@@ -0,0 +1,25 @@
apiVersion: batch/v1
kind: Job
metadata:
name: keycloak-bootstrap
namespace: keycloak
spec:
backoffLimit: 2
template:
spec:
serviceAccountName: keycloak-bootstrap
restartPolicy: OnFailure
volumes:
- name: bootstrap
configMap:
name: keycloak-bootstrap
containers:
- name: bootstrap
image: curlimages/curl:8.12.1
command:
- /bin/sh
- -ec
- sh /bootstrap/bootstrap.sh
volumeMounts:
- name: bootstrap
mountPath: /bootstrap
@@ -0,0 +1,26 @@
apiVersion: batch/v1
kind: Job
metadata:
name: keycloak-db-secret-sync
namespace: keycloak
spec:
backoffLimit: 2
template:
spec:
serviceAccountName: keycloak-bootstrap
restartPolicy: OnFailure
volumes:
- name: sync
configMap:
name: keycloak-db-secret-sync
defaultMode: 493
containers:
- name: sync
image: registry.k8s.io/kubectl:v1.31.0
command:
- /bin/sh
- -ec
- /sync/sync.sh
volumeMounts:
- name: sync
mountPath: /sync
@@ -0,0 +1,22 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: keycloak-db-secret-sync
namespace: keycloak
data:
sync.sh: |
#!/bin/sh
set -eu
until kubectl -n shared-db get secret shared-postgresql-superuser-secret >/dev/null 2>&1; do
sleep 5
done
username=$(kubectl -n shared-db get secret shared-postgresql-superuser-secret -o jsonpath='{.data.username}' | base64 -d)
password=$(kubectl -n shared-db get secret shared-postgresql-superuser-secret -o jsonpath='{.data.password}' | base64 -d)
kubectl create secret generic keycloak-db-secret \
--namespace keycloak \
--from-literal=username="${username}" \
--from-literal=password="${password}" \
--dry-run=client -o yaml | kubectl -n keycloak apply -f -
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: keycloak
+53
View File
@@ -0,0 +1,53 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: keycloak-bootstrap
namespace: keycloak
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: keycloak-secret-writer
namespace: keycloak
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: keycloak-secret-writer
namespace: keycloak
subjects:
- kind: ServiceAccount
name: keycloak-bootstrap
namespace: keycloak
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: keycloak-secret-writer
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: shared-postgresql-secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["shared-postgresql-superuser-secret"]
verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: shared-postgresql-secret-reader
namespace: shared-db
subjects:
- kind: ServiceAccount
name: keycloak-bootstrap
namespace: keycloak
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: shared-postgresql-secret-reader
+10
View File
@@ -0,0 +1,10 @@
# Traefik Gateway API helpers
- Define the GatewayClass/Gateway that Traefik's controller expects so later HTTPRoutes can bind to it.
- All manifests live here for GitOps sync; the Gateway uses the `traefik` controller name (`traefik.io/gateway-controller`) that k3s bundled Traefik advertises.
- Apply with:
```bash
kubectl apply -f ~/services/archive/traefik/gatewayclass.yaml
kubectl apply -f ~/services/archive/traefik/gateway.yaml
```
- Once accepted you can add HTTPRoute objects (e.g., `~/services/apps/http-echo/httproute-traefik.yaml`) targeting the Gateway.
+17
View File
@@ -0,0 +1,17 @@
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: traefik-gateway
namespace: default
spec:
gatewayClassName: traefik
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
kinds:
- group: gateway.networking.k8s.io
kind: HTTPRoute
+6
View File
@@ -0,0 +1,6 @@
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: traefik
spec:
controllerName: traefik.io/gateway-controller