benvin/kanidm #159

Merged
unkinben merged 4 commits from benvin/kanidm into main 2026-05-24 19:55:23 +10:00
15 changed files with 445 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: kanidm-tls
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
spec:
secretName: kanidm-tls
issuerRef:
kind: ClusterIssuer
name: vault-issuer
commonName: auth.unkin.net
dnsNames:
- auth.unkin.net
- au.auth.unkin.net
- kanidm.k8s.syd1.au.unkin.net
- kanidm.kanidm.svc.cluster.local
- kanidm-0.kanidm-headless.kanidm.svc.cluster.local
- kanidm-1.kanidm-headless.kanidm.svc.cluster.local
- kanidm-2.kanidm-headless.kanidm.svc.cluster.local
privateKey:
algorithm: RSA
size: 4096
+40
View File
@@ -0,0 +1,40 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: kanidm-config
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
data:
server.toml: |
version = "2"
domain = "auth.unkin.net"
origin = "https://auth.unkin.net"
bindaddress = "[::]:8443"
db_path = "/data/kanidm.db"
db_arc_size = 2048
tls_chain = "/data/tls/tls.crt"
tls_key = "/data/tls/tls.key"
log_level = "info"
[online_backup]
path = "/data/backups/"
schedule = "0 22 * * *"
versions = 7
[replication]
origin = "__REPL_ORIGIN__"
bindaddress = "[::]:8444"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: kanidm-repl-certs
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
data: {}
+30
View File
@@ -0,0 +1,30 @@
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: kanidm
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
traefik.io/instance: internal
annotations:
external-dns.alpha.kubernetes.io/hostname: kanidm.k8s.syd1.au.unkin.net
external-dns.alpha.kubernetes.io/target: 198.18.200.4
spec:
gatewayClassName: traefik-internal
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: Same
- name: https-passthrough
port: 443
protocol: TLS
tls:
mode: Passthrough
allowedRoutes:
namespaces:
from: Same
+27
View File
@@ -0,0 +1,27 @@
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: kanidm-http-redirect
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
spec:
hostnames:
- kanidm.k8s.syd1.au.unkin.net
- auth.unkin.net
- au.auth.unkin.net
parentRefs:
- name: kanidm
sectionName: http
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
matches:
- path:
type: PathPrefix
value: /
+16
View File
@@ -0,0 +1,16 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- serviceaccount.yaml
- rbac.yaml
- certificate.yaml
- configmap.yaml
- service.yaml
- statefulset.yaml
- poddisruptionbudget.yaml
- gateway.yaml
- httproute.yaml
- tlsroute.yaml
+5
View File
@@ -0,0 +1,5 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: kanidm
+15
View File
@@ -0,0 +1,15 @@
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: kanidm
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
spec:
maxUnavailable: 1
selector:
matchLabels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
+37
View File
@@ -0,0 +1,37 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: kanidm-repl
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
- apiGroups: [""]
resources: ["configmaps"]
resourceNames: ["kanidm-repl-certs"]
verbs: ["get", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kanidm-repl
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
subjects:
- kind: ServiceAccount
name: kanidm
namespace: kanidm
roleRef:
kind: Role
name: kanidm-repl
apiGroup: rbac.authorization.k8s.io
+43
View File
@@ -0,0 +1,43 @@
---
apiVersion: v1
kind: Service
metadata:
name: kanidm
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
spec:
type: ClusterIP
ports:
- name: https
port: 8443
targetPort: https
protocol: TCP
selector:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
---
apiVersion: v1
kind: Service
metadata:
name: kanidm-headless
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
spec:
type: ClusterIP
clusterIP: None
ports:
- name: https
port: 8443
targetPort: https
protocol: TCP
- name: replication
port: 8444
targetPort: replication
protocol: TCP
selector:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
+9
View File
@@ -0,0 +1,9 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: kanidm
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
+161
View File
@@ -0,0 +1,161 @@
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: kanidm
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
spec:
serviceName: kanidm-headless
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
template:
metadata:
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
spec:
serviceAccountName: kanidm
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
topologyKey: kubernetes.io/hostname
securityContext:
runAsUser: 1000
runAsGroup: 1000
runAsNonRoot: true
fsGroup: 1000
initContainers:
- name: config-init
image: ghcr.io/kanidm/server:1.10.3
command: ["/bin/sh", "-c"]
args:
- |
set -e
REPL_ORIGIN="repl://${POD_NAME}.kanidm-headless.kanidm.svc.cluster.local:8444"
sed "s|__REPL_ORIGIN__|${REPL_ORIGIN}|g" /config-template/server.toml > /config/server.toml
for peer in kanidm-0 kanidm-1 kanidm-2; do
if [ "${peer}" = "${POD_NAME}" ]; then
continue
fi
cert_file="/repl-certs/${peer}"
if [ -s "${cert_file}" ]; then
fqdn="${peer}.kanidm-headless.kanidm.svc.cluster.local"
printf '\n[replication."repl://%s:8444"]\ntype = "mutual-pull"\npartner_cert = "%s"\n' \
"${fqdn}" "$(cat ${cert_file})" >> /config/server.toml
fi
done
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
volumeMounts:
- name: config-template
mountPath: /config-template
- name: config
mountPath: /config
- name: repl-certs
mountPath: /repl-certs
readOnly: true
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
- name: repl-cert-publisher
image: bitnami/kubectl:1.33
restartPolicy: Always
command: ["/bin/sh", "-c"]
args:
- |
until kubectl exec "${POD_NAME}" -c kanidm -- /sbin/kanidmd renew-replication-certificate 2>/dev/null | grep -q '^# certificate:'; do
sleep 30
done
while true; do
cert=$(kubectl exec "${POD_NAME}" -c kanidm -- /sbin/kanidmd renew-replication-certificate 2>/dev/null \
| grep '^# certificate:' | sed 's/^# certificate: "\(.*\)"$/\1/')
if [ -n "${cert}" ]; then
kubectl patch configmap kanidm-repl-certs \
--type=merge \
-p "{\"data\":{\"${POD_NAME}\":\"${cert}\"}}"
fi
sleep 3600
done
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
containers:
- name: kanidm
image: ghcr.io/kanidm/server:1.10.3
command: ["/sbin/kanidmd"]
args: ["server", "-c", "/config/server.toml"]
ports:
- name: https
containerPort: 8443
protocol: TCP
- name: replication
containerPort: 8444
protocol: TCP
volumeMounts:
- name: data
mountPath: /data
- name: config
mountPath: /config
readOnly: true
- name: tls
mountPath: /data/tls
readOnly: true
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
resources:
requests:
memory: 256Mi
cpu: 100m
limits:
memory: 1Gi
cpu: 500m
readinessProbe:
tcpSocket:
port: 8443
initialDelaySeconds: 15
periodSeconds: 10
livenessProbe:
tcpSocket:
port: 8443
initialDelaySeconds: 30
periodSeconds: 30
volumes:
- name: config-template
configMap:
name: kanidm-config
- name: config
emptyDir: {}
- name: repl-certs
configMap:
name: kanidm-repl-certs
- name: tls
secret:
secretName: kanidm-tls
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ReadWriteOnce]
storageClassName: cephrbd-fast-delete
resources:
requests:
storage: 10Gi
+21
View File
@@ -0,0 +1,21 @@
---
apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
name: kanidm
namespace: kanidm
labels:
app.kubernetes.io/name: kanidm
app.kubernetes.io/instance: kanidm
spec:
hostnames:
- kanidm.k8s.syd1.au.unkin.net
- auth.unkin.net
- au.auth.unkin.net
parentRefs:
- name: kanidm
sectionName: https-passthrough
rules:
- backendRefs:
- name: kanidm
port: 8443
@@ -0,0 +1,6 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../../base/kanidm
+7
View File
@@ -20,6 +20,7 @@ spec:
- path: apps/overlays/*/externaldns
- path: apps/overlays/*/inteldeviceplugins-system
- path: apps/overlays/*/jfrog
- path: apps/overlays/*/kanidm
- path: apps/overlays/*/node-feature-discovery
- path: apps/overlays/*/puppet
- path: apps/overlays/*/purelb
@@ -43,6 +44,12 @@ spec:
destination:
server: https://kubernetes.default.svc
namespace: '{{path[3]}}' # Use directory name as namespace
ignoreDifferences:
- group: ""
kind: ConfigMap
name: kanidm-repl-certs
jsonPointers:
- /data
syncPolicy:
automated:
prune: true
+2
View File
@@ -27,6 +27,8 @@ spec:
server: https://kubernetes.default.svc
- namespace: 'jfrog'
server: https://kubernetes.default.svc
- namespace: 'kanidm'
server: https://kubernetes.default.svc
- namespace: 'node-feature-discovery'
server: https://kubernetes.default.svc
- namespace: 'purelb'