- Go Template 62.9%
- Makefile 37.1%
|
|
||
|---|---|---|
| .gitea/workflows | ||
| charts/traefik-control | ||
| .editorconfig | ||
| .gitignore | ||
| ct.yaml | ||
| lintconf.yaml | ||
| Makefile | ||
| README.md | ||
helm
Helm charts of White Ghost Cyber Systems, published as OCI artifacts to
oci://git.enclaveis.com/white_ghost_cyber_systems.
Layout
charts/<name>/ one directory per chart (Chart.yaml, values.yaml, templates/)
ct.yaml chart-testing config
lintconf.yaml yamllint rules used by `ct lint`
Makefile local dev tasks
.gitea/workflows/ CI
Requirements
- helm 4.x
- chart-testing (
ct) andyamllint, only formake ct-lint - kubeconform and crane, only for
make validate
Usage
make help # list targets
make lint # helm lint --strict + helm template, once per charts/<name>/ci/*-values.yaml
make validate # render each chart, check manifests against Kubernetes schemas (kubeconform) and that every image tag exists (crane); CHARTS=charts/foo to limit
make ct-lint # chart-testing lint against main
make package # write .tgz files to .packages/
make publish # push new chart versions to the OCI registry
Every change to a chart raises its version in Chart.yaml (ct lint checks
it). .gitea/workflows/lint.yaml runs on pull requests; on a push to main
.gitea/workflows/publish.yaml pushes each chart version that is not in the
registry yet and links the package to this repository. It needs a
REGISTRY_TOKEN repository secret with write:package (a token limited to
repositories cannot hold package scopes).
Charts
traefik-control
Traefik Control, the multi-tenant control plane for Traefik nodes.
helm install control oci://git.enclaveis.com/white_ghost_cyber_systems/traefik-control \
--version <version> -n traefik-control --create-namespace \
--set host=control.example.com --set ingress.enabled=true \
--set ingress.className=traefik --set ingress.tlsSecretName=control-tls
host is required. By default (scheme: https) it is served as
https://<host>: the application builds https links and redirects plain http
(the health checks excepted), so terminate TLS in front of it. With
scheme: http (and urlPort when the address carries one) it builds
http://<host>[:<port>] links and neither redirects nor sends HSTS, for use
over a VPN or behind a proxy that does not use TLS. Passkeys (WebAuthn) then
only work on localhost; TOTP is unaffected. Needs an application release that
knows PHX_SCHEME (1.2.0 and later).
| Pin | Value | Where |
|---|---|---|
| Traefik Control | 1.2.0 |
image.tag (and appVersion) |
| CloudNativePG PostgreSQL image | 18.6-standard-trixie |
database.cnpg.image |
The application is built once per database backend, so the image follows
database.mode:
cnpg(default, recommended): a CloudNativePGCluster(3 instances, 10Gi each) and thetraefik-control-postgresimage. Needs the CloudNativePG operator in the cluster first. Backups are not configured by default; usedatabase.cnpg.extraSpec.external: your own PostgreSQL;database.external.existingSecretholdsDATABASE_URL(ecto://user:pass@host/db).sqlite: thetraefik-control-sqlite3image with its database on a volume (persistence). One pod,Recreaterollouts; for trying it out and small setups.
Behaviour worth knowing:
- Secrets. The chart creates a Secret with
SECRET_KEY_BASEandRELEASE_COOKIE(random, kept across upgrades, kept on uninstall); bring your own withsecret.existingSecret. ChangingSECRET_KEY_BASEsigns everybody out. - Probes. Startup and liveness use
/healthz; readiness uses/readyz, which checks the database. The startup probe allows 5 minutes for migrations. - Several replicas (cnpg or external) work: the application keeps no state
in one pod that another needs. With
clustering.enabled(default) the pods also form an Erlang cluster, through a headless Service and a distribution cookie, so live updates in the web interface reach every pod. Allow pod to pod traffic on 4369 andclustering.distPort(9100) if you use NetworkPolicies. A PodDisruptionBudget is created above one replica. - Hardening. uid 65534, read-only root filesystem (an
emptyDiron/tmp), all capabilities dropped,RuntimeDefaultseccomp, no service account token. - Behind the Ingress,
TRAEFIK_CONTROL_TRUST_PROXY=trueis set so login throttling sees the client address; override it underconfig. Other settings of the application go underconfig(plain) andextraEnv(secrets); the list is in the application's README. - Extra containers.
extraInitContainersandextraVolumesare rendered as they are, andstrategyreplaces the Deployment strategy. An init container withrestartPolicy: Alwaysis a native sidecar (Kubernetes 1.29 or later), for example a VPN client that gives the pod an address of its own. Such a container that keeps state on a ReadWriteOnce volume needsstrategy: {type: Recreate}, or a second pod cannot mount the volume. - The first person to register becomes the server administrator: register before the address is public.
To upgrade: set the new release in image.tag and appVersion and bump the
chart version. Read the application's release notes first.