Compare commits

..

10 Commits

Author SHA1 Message Date
unkinben 7d2e0dfa0f fix(kanidm): prevent ArgoCD from overwriting repl-cert ConfigMap data
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/kubeconform Pipeline was successful
Remove the data keys from kanidm-repl-certs in git so ArgoCD never takes
SSA ownership of them. Add ignoreDifferences for /data on that ConfigMap
in the ApplicationSet template so ArgoCD doesn't flag sidecar-patched
cert values as out-of-sync.
2026-05-24 19:42:32 +10:00
unkinben 11286a1f89 feat(kanidm): automate replication cert exchange via native sidecar
Add a native sidecar (bitnami/kubectl, restartPolicy: Always) that runs
kanidmd renew-replication-certificate on each pod and patches the result
into the kanidm-repl-certs ConfigMap (certs are public keys, not secrets).
The config-init init container reads peer certs from the ConfigMap at
startup, building the replication stanza automatically — no manual cert
exchange required after first deploy.

Add RBAC (Role + RoleBinding) granting the kanidm service account
pods/exec and configmap patch permissions scoped to the kanidm namespace.
2026-05-24 19:42:32 +10:00
unkinben e91fe554eb feat(kanidm): 3 replicas, PDB maxUnavailable=1, host anti-affinity
- Increase replicas from 2 to 3
- Add kanidm-2 headless DNS SAN to TLS certificate
- Add PodDisruptionBudget (maxUnavailable: 1) to maintain quorum during
  node drains
- Add requiredDuringSchedulingIgnoredDuringExecution pod anti-affinity
  on kubernetes.io/hostname to spread replicas across distinct hosts
- Update replication peers comment to include kanidm-2 cert exchange step
2026-05-24 19:42:32 +10:00
unkinben ee76ec199b feat(kanidm): deploy Kanidm 1.10.3 with 2-replica replication
## Summary

- Deploys Kanidm 1.10.3 (ghcr.io/kanidm/server:1.10.3) as a 2-replica
  StatefulSet with built-in replication enabled
- Domain: auth.unkin.net (primary WebAuthn origin); au.auth.unkin.net
  is an additional hostname for this au-syd1 instance
- TLS: cert-manager Certificate (vault-issuer) covering auth.unkin.net,
  au.auth.unkin.net, kanidm.k8s.syd1.au.unkin.net, and internal
  headless pod DNS names — Kanidm terminates TLS itself (passthrough)
- Gateway: TLS passthrough on port 443 via TLSRoute; HTTP on port 80
  redirects to HTTPS; external-dns creates kanidm.k8s.syd1.au.unkin.net
  (not used in server.toml; canonical origin is auth.unkin.net only)
- Replication: init container generates per-pod server.toml with the
  correct repl:// origin (kanidm-{N}.kanidm-headless.kanidm.svc);
  populate kanidm-repl-peers ConfigMap post-deployment after running
  `kanidmd show-replication-certificate` on each pod
- Storage: 10Gi cephrbd-fast-delete PVC per pod via volumeClaimTemplates
- Security: runAsUser/runAsGroup 1000, runAsNonRoot, no privilege
  escalation, allowPrivilegeEscalation=false
- ArgoCD: platform ApplicationSet and Project updated for kanidm namespace

## Requires

- PR benvin/kanidm-artifactapi (add ^kanidm/ to ghcr immutable patterns)
  to be merged first so artifactapi can cache ghcr.io/kanidm/server

## Post-deployment steps

1. Wait for both pods to reach Running state
2. Exchange replication certificates between pods:
   kubectl exec -n kanidm kanidm-0 -- kanidmd show-replication-certificate
   kubectl exec -n kanidm kanidm-1 -- kanidmd show-replication-certificate
3. Edit kanidm-repl-peers ConfigMap with both nodes' certs
   (see template in configmap.yaml comments)
4. kubectl rollout restart statefulset/kanidm -n kanidm

## Test plan

- [x] Sandbox tested in sandbox-kanidm: all 11 resources server dry-run OK
- [ ] After merge: ArgoCD syncs kanidm namespace
- [ ] Verify auth.unkin.net and au.auth.unkin.net reachable via Gateway
- [ ] Verify kanidm.k8s.syd1.au.unkin.net DNS record created by external-dns
- [ ] Complete replication cert exchange and verify replication active
2026-05-24 19:42:32 +10:00
unkinben 6ce92e8ead benvin/artifactapi-mail-images (#158)
Reviewed-on: #158
2026-05-24 14:44:38 +10:00
unkinben af79d86db6 feat(artifactapi): cache stalwart webadmin zip (#157)
## Summary

- Adds \`stalwartlabs/webadmin/releases/latest/download/webadmin.zip\` to \`mutable_patterns\` in the \`github\` generic remote so the stalwart webadmin UI can be fetched through artifactapi rather than directly from GitHub.

## Notes

- Uses \`mutable_patterns\` (not \`immutable\`) because \`releases/latest\` resolves to whichever release is current and changes over time.
- Access URL: \`https://artifactapi.k8s.syd1.au.unkin.net/generic/github/stalwartlabs/webadmin/releases/latest/download/webadmin.zip\`

Reviewed-on: #157
2026-05-24 12:55:16 +10:00
unkinben 5f4c9225bb feat(artifactapi): add mail stack images to docker registry cache (#156)
- ghcr: stalwartlabs/stalwart (Stalwart mail server)
- dockerhub: rspamd/rspamd (spam filter), tozd/postfix (MTA gateway)

Reviewed-on: #156
2026-05-24 12:42:27 +10:00
unkinben cbc2c1cb9f fix(gateways): add explicit group: "" to all certificateRefs entries (#153)
The Gateway API admission server defaults certificateRefs[].group to ""
when it is omitted. ArgoCD diffed the desired state (no group field) against
the live state (group: "") and flagged every gateway as out of sync.

Fix: explicitly set group: "" in all certificateRefs entries so the
rendered manifest matches the API server's canonical form exactly.

Affected: artifactapi, cattle-system, consul, litellm, paperclip,
puppet (puppetboard + puppetdb), vault.

Reviewed-on: #153
2026-05-23 23:47:24 +10:00
unkinben c6f9893804 fix(argocd): add vault and consul to platform project destinations (#152)
Vault and consul namespaces were missing from the platform AppProject
allowed destinations, causing ArgoCD sync failures with:
  destination server 'https://kubernetes.default.svc' and namespace
  'vault' do not match any of the allowed destinations in project 'platform'

Reviewed-on: #152
2026-05-23 23:27:24 +10:00
unkinben e43fb742ad feat(artifactapi): add kanidm to ghcr docker immutable patterns (#151)
Prerequisite for kanidm deployment (PR benvin/kanidm).

Reviewed-on: #151
2026-05-23 23:09:38 +10:00
10 changed files with 26 additions and 10 deletions
+2 -1
View File
@@ -31,6 +31,7 @@ spec:
protocol: HTTPS protocol: HTTPS
tls: tls:
certificateRefs: certificateRefs:
- kind: Secret - group: ""
kind: Secret
name: artifactapi-tls name: artifactapi-tls
mode: Terminate mode: Terminate
@@ -6,8 +6,10 @@ remotes:
immutable_patterns: immutable_patterns:
- "^cloudnative-pg/cloudnative-pg" - "^cloudnative-pg/cloudnative-pg"
- "^emberstack/helm-charts" - "^emberstack/helm-charts"
- "^kanidm/"
- "^openvoxproject/" - "^openvoxproject/"
- "^stakater/reloader" - "^stakater/reloader"
- "^stalwartlabs/stalwart"
- "^voxpupuli/puppetboard" - "^voxpupuli/puppetboard"
- "^woodpecker-ci/helm" - "^woodpecker-ci/helm"
cache: cache:
@@ -34,7 +36,10 @@ remotes:
- "^hashicorp/vault" - "^hashicorp/vault"
- "^jfrog/" - "^jfrog/"
- "^rancher/" - "^rancher/"
- "^rspamd/rspamd"
- "^tozd/postfix"
- "^traefik/" - "^traefik/"
- "^valkey/valkey"
- "^ubi9/ubi-minimal" - "^ubi9/ubi-minimal"
- "^victoriametrics/" - "^victoriametrics/"
- "^woodpeckerci/" - "^woodpeckerci/"
@@ -5,6 +5,7 @@ remotes:
description: "GitHub releases and files" description: "GitHub releases and files"
mutable_patterns: mutable_patterns:
- ".*/archive/refs/heads/.*.tar.gz$" - ".*/archive/refs/heads/.*.tar.gz$"
- "stalwartlabs/webadmin/releases/latest/download/webadmin.zip$"
immutable_patterns: immutable_patterns:
- ".*/archive/refs/tags/.*.tar.gz$" - ".*/archive/refs/tags/.*.tar.gz$"
- "ahmetb/kubectx/.*/kubectx_.*_linux_x86_64.tar.gz$" - "ahmetb/kubectx/.*/kubectx_.*_linux_x86_64.tar.gz$"
+2 -1
View File
@@ -31,6 +31,7 @@ spec:
protocol: HTTPS protocol: HTTPS
tls: tls:
certificateRefs: certificateRefs:
- kind: Secret - group: ""
kind: Secret
name: rancher-tls name: rancher-tls
mode: Terminate mode: Terminate
+4 -2
View File
@@ -35,7 +35,8 @@ spec:
tls: tls:
mode: Terminate mode: Terminate
certificateRefs: certificateRefs:
- kind: Secret - group: ""
kind: Secret
name: consul-tls name: consul-tls
- name: consul-svc - name: consul-svc
port: 443 port: 443
@@ -47,5 +48,6 @@ spec:
tls: tls:
mode: Terminate mode: Terminate
certificateRefs: certificateRefs:
- kind: Secret - group: ""
kind: Secret
name: consul-tls name: consul-tls
+2 -1
View File
@@ -31,6 +31,7 @@ spec:
protocol: HTTPS protocol: HTTPS
tls: tls:
certificateRefs: certificateRefs:
- kind: Secret - group: ""
kind: Secret
name: litellm-tls name: litellm-tls
mode: Terminate mode: Terminate
+2 -1
View File
@@ -31,6 +31,7 @@ spec:
protocol: HTTPS protocol: HTTPS
tls: tls:
certificateRefs: certificateRefs:
- kind: Secret - group: ""
kind: Secret
name: paperclip-tls name: paperclip-tls
mode: Terminate mode: Terminate
+2 -1
View File
@@ -35,6 +35,7 @@ spec:
protocol: HTTPS protocol: HTTPS
tls: tls:
certificateRefs: certificateRefs:
- kind: Secret - group: ""
kind: Secret
name: puppetboard-tls name: puppetboard-tls
mode: Terminate mode: Terminate
+2 -1
View File
@@ -28,6 +28,7 @@ spec:
protocol: HTTPS protocol: HTTPS
tls: tls:
certificateRefs: certificateRefs:
- kind: Secret - group: ""
kind: Secret
name: puppetdb-tls name: puppetdb-tls
mode: Terminate mode: Terminate
+4 -2
View File
@@ -35,7 +35,8 @@ spec:
tls: tls:
mode: Terminate mode: Terminate
certificateRefs: certificateRefs:
- kind: Secret - group: ""
kind: Secret
name: vault-tls name: vault-tls
- name: vault-direct - name: vault-direct
port: 8200 port: 8200
@@ -46,5 +47,6 @@ spec:
tls: tls:
mode: Terminate mode: Terminate
certificateRefs: certificateRefs:
- kind: Secret - group: ""
kind: Secret
name: vault-tls name: vault-tls