From 329ec14365db1a280b3a6bce61ee74eed0ff2b43 Mon Sep 17 00:00:00 2001 From: David Frickert Date: Thu, 20 Jun 2024 12:30:47 +0200 Subject: [PATCH 01/22] split LDAP_EXTRA_SCHEMAS from main configmap - this change is needed to ensure that generic configmap can be used by both writable and readonly replicas. then a schemas configmap for writable replicas and one for readonly can be created without much duplication. --- templates/configmap-env-schemas.yaml | 21 +++++++++++++++++++++ templates/configmap-env.yaml | 1 - templates/statefulset.yaml | 2 ++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 templates/configmap-env-schemas.yaml diff --git a/templates/configmap-env-schemas.yaml b/templates/configmap-env-schemas.yaml new file mode 100644 index 0000000..eb37359 --- /dev/null +++ b/templates/configmap-env-schemas.yaml @@ -0,0 +1,21 @@ +# +# A ConfigMap spec for openldap slapd that map directly to env variables in the Pod. +# List of environment variables supported is from the docker image: +# https://hub.docker.com/r/bitnami/openldap/ +# Note that passwords are defined as secrets +# +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "openldap.fullname" . }}-env-schemas + labels: + app: {{ template "openldap.name" . }} + chart: {{ template "openldap.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.extraLabels }} +{{ toYaml .Values.extraLabels | indent 4 }} +{{- end }} +data: + LDAP_EXTRA_SCHEMAS: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) }} +{{ toYaml .Values.env | indent 2 }} diff --git a/templates/configmap-env.yaml b/templates/configmap-env.yaml index b298910..1ad8935 100755 --- a/templates/configmap-env.yaml +++ b/templates/configmap-env.yaml @@ -18,7 +18,6 @@ metadata: {{- end }} data: LDAP_ROOT: {{ include "global.baseDomain" . }} - LDAP_EXTRA_SCHEMAS: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) }} {{- if .Values.users }} LDAP_USERS: {{ .Values.users }} {{- end }} diff --git a/templates/statefulset.yaml b/templates/statefulset.yaml index 6cedc13..5a0560e 100644 --- a/templates/statefulset.yaml +++ b/templates/statefulset.yaml @@ -193,6 +193,8 @@ spec: {{- end }} - configMapRef: name: {{ template "openldap.fullname" . }}-env + - configMapRef: + name: {{ template "openldap.fullname" . }}-env-schemas {{- if .Values.extraEnvVarsSecret }} - secretRef: name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} From e31a2a0d93861a62e121e55cf9d151a8570a855c Mon Sep 17 00:00:00 2001 From: David Frickert Date: Thu, 20 Jun 2024 12:31:21 +0200 Subject: [PATCH 02/22] support creating a read only replica statefulset --- templates/_helpers.tpl | 28 ++ templates/configmap-env-readonly-schemas.yaml | 23 ++ templates/configmap-readonly.yaml | 19 + templates/service-readonly.yaml | 57 +++ templates/statefulset-readonly.yaml | 375 ++++++++++++++++++ templates/svc-headless-readonly.yaml | 29 ++ values.yaml | 3 + 7 files changed, 534 insertions(+) create mode 100644 templates/configmap-env-readonly-schemas.yaml create mode 100644 templates/configmap-readonly.yaml create mode 100644 templates/service-readonly.yaml create mode 100644 templates/statefulset-readonly.yaml create mode 100644 templates/svc-headless-readonly.yaml diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 2a76fd5..ed66518 100755 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -61,6 +61,11 @@ Generate olcServerID list {{- $index1 := $index0 | add1 }} olcServerID: {{ $index1 }} ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 {{- end -}} +{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }} + {{- range $index0 := until $readonlyNodeCount }} + {{- $index1 := $index0 | add $nodeCount | add 1 }} + olcServerID: {{ $index1 }} ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389 + {{- end -}} {{- end -}} {{/* @@ -81,6 +86,11 @@ Generate olcSyncRepl list {{- $index1 := $index0 | add1 }} olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshAndPersist retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} {{- end -}} +{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }} + {{- range $index0 := until $readonlyNodeCount }} + {{- $index1 := $index0 | add $nodeCount | add 1 }} + olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshAndPersist retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} + {{- end -}} {{- end -}} {{/* @@ -99,6 +109,7 @@ Generate olcSyncRepl list {{- $tls_reqcert := .Values.replication.tls_reqcert }} {{- $interval := .Values.replication.interval }} {{- $nodeCount := .Values.replicaCount | int }} +{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }} {{- range $index0 := until $nodeCount }} {{- $index1 := $index0 | add1 }} olcSyncrepl: @@ -116,6 +127,23 @@ Generate olcSyncRepl list starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} {{- end -}} + {{- range $index0 := until $readonlyNodeCount }} + {{- $index1 := $index0 | add $nodeCount | add 1 }} + olcSyncrepl: + rid=10{{ $index1 }} + provider=ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389 + binddn={{ printf "cn=%s,%s" $bindDNUser $domain }} + bindmethod=simple + credentials={{ $adminPassword }} + searchbase={{ $domain }} + type=refreshAndPersist + interval={{ $interval }} + network-timeout=0 + retry="{{ $retry }} +" + timeout={{ $timeout }} + starttls={{ $starttls }} + tls_reqcert={{ $tls_reqcert }} + {{- end -}} {{- end -}} {{/* diff --git a/templates/configmap-env-readonly-schemas.yaml b/templates/configmap-env-readonly-schemas.yaml new file mode 100644 index 0000000..b2af670 --- /dev/null +++ b/templates/configmap-env-readonly-schemas.yaml @@ -0,0 +1,23 @@ +# +# A ConfigMap spec for openldap slapd that map directly to env variables in the Pod. +# List of environment variables supported is from the docker image: +# https://hub.docker.com/r/bitnami/openldap/ +# Note that passwords are defined as secrets +# +{{- if (gt (.Values.readOnlyReplicaCount | int) 0) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "openldap.fullname" . }}-env-readonly-schemas + labels: + app: {{ template "openldap.name" . }} + chart: {{ template "openldap.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.extraLabels }} +{{ toYaml .Values.extraLabels | indent 4 }} +{{- end }} +data: + LDAP_EXTRA_SCHEMAS: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) ",readonly"}} +{{ toYaml .Values.env | indent 2 }} +{{- end }} \ No newline at end of file diff --git a/templates/configmap-readonly.yaml b/templates/configmap-readonly.yaml new file mode 100644 index 0000000..aa69d47 --- /dev/null +++ b/templates/configmap-readonly.yaml @@ -0,0 +1,19 @@ +{{- if (gt (.Values.readOnlyReplicaCount | int) 0) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "openldap.fullname" . }}-readonly + labels: + app: {{ template "openldap.name" . }} + chart: {{ template "openldap.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.extraLabels }} +{{ toYaml .Values.extraLabels | indent 4 }} +{{- end }} +data: + # replication + readonly.ldif: | + dn: olcDatabase={2}mdb,cn=config + olcReadonly: TRUE +{{- end }} \ No newline at end of file diff --git a/templates/service-readonly.yaml b/templates/service-readonly.yaml new file mode 100644 index 0000000..74fe24b --- /dev/null +++ b/templates/service-readonly.yaml @@ -0,0 +1,57 @@ +{{- if (gt (.Values.readOnlyReplicaCount | int) 0) }} +apiVersion: v1 +kind: Service +metadata: +{{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} + name: {{ template "openldap.fullname" . }}-readonly + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/component: {{ template "openldap.fullname" . }} + chart: {{ template "openldap.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.extraLabels }} +{{ toYaml .Values.extraLabels | indent 4 }} +{{- end }} +spec: + type: {{ .Values.service.type }} + {{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + {{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{ toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }} + {{- end }} + {{- if and (eq .Values.service.type "ClusterIP") .Values.service.clusterIP }} + clusterIP: {{ .Values.service.clusterIP }} + {{- end }} + ports: + {{- if .Values.service.enableLdapPort }} + - name: ldap-port + protocol: TCP + port: {{ .Values.global.ldapPort }} + targetPort: ldap-port + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.ldapPortNodePort)) }} + nodePort: {{ .Values.service.ldapPortNodePort }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- end }} + {{- if .Values.service.enableSslLdapPort }} + - name: ssl-ldap-port + protocol: TCP + port: {{ .Values.global.sslLdapPort }} + targetPort: ssl-ldap-port + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.sslLdapPortNodePort)) }} + nodePort: {{ .Values.service.sslLdapPortNodePort }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- end }} + sessionAffinity: {{ .Values.service.sessionAffinity }} + selector: + app.kubernetes.io/component: {{ template "openldap.fullname" . }}-readonly + release: {{ .Release.Name }} +{{- end }} \ No newline at end of file diff --git a/templates/statefulset-readonly.yaml b/templates/statefulset-readonly.yaml new file mode 100644 index 0000000..7a9d419 --- /dev/null +++ b/templates/statefulset-readonly.yaml @@ -0,0 +1,375 @@ +{{- if (gt (.Values.readOnlyReplicaCount | int) 0) }} +apiVersion: {{ include "common.capabilities.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ template "openldap.fullname" . }}-readonly + labels: {{- include "common.labels.standard" . | nindent 4 }} + app.kubernetes.io/component: {{ template "openldap.fullname" . }}-readonly + chart: {{ template "openldap.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + {{- if .Values.commonLabels }} + {{- include "common.tplvalues.render" ( dict "value" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- end }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.readOnlyReplicaCount }} + selector: + matchLabels: {{ include "common.labels.matchLabels" . | nindent 6 }} + app.kubernetes.io/component: {{ template "openldap.fullname" . }}-readonly + serviceName: {{ template "openldap.fullname" . }}-headless-readonly + {{- if .Values.updateStrategy }} + updateStrategy: +{{ toYaml .Values.updateStrategy | nindent 4 }} + {{- end }} + template: + metadata: + annotations: + {{- if .Values.podAnnotations }} + {{- include "common.tplvalues.render" (dict "value" .Values.podAnnotations "context" $) | nindent 8 }} + {{- end }} + checksum/configmap-env: {{ include (print $.Template.BasePath "/configmap-env.yaml") . | sha256sum }} + {{- if .Values.customLdifFiles}} + checksum/configmap-customldif: {{ include (print $.Template.BasePath "/configmap-customldif.yaml") . | sha256sum }} + {{- end }} + labels: {{- include "common.labels.standard" . | nindent 8 }} + app.kubernetes.io/component: {{ template "openldap.fullname" . }}-readonly + release: {{ .Release.Name }} + {{- if .Values.podLabels }} + {{- include "common.tplvalues.render" (dict "value" .Values.podLabels "context" $) | nindent 8 }} + {{- end }} + spec: + initContainers: + - name: init-schema + image: {{ include "openldap.initSchemaImage" . }} + imagePullPolicy: {{ .Values.initSchema.image.pullPolicy | quote }} + command: + - sh + - -c + - | + host=$(hostname) + if [ "$host" = "{{ template "openldap.fullname" . }}-readonly-0" ] + then + echo "This is the main openldap so let's init all additional schemas and ldifs here" + cp -p -f /cm-schemas-acls/*.ldif /custom_config/ + if [ -d /cm-schemas ]; then + cp -p -f /cm-schemas/*.ldif /custom-schemas/ + fi + if [ -d /cm-ldifs ]; then + cp -p -f /cm-ldifs/*.ldif /custom-ldifs/ + fi + else + cp -p -f /cm-schemas-acls/*.ldif /custom_config/ + echo "let the replication takes care of everything :)" + fi + {{- if .Values.global.existingSecret }} + sed -i -e "s/%%CONFIG_PASSWORD%%/${LDAP_CONFIG_ADMIN_PASSWORD}/g" /custom_config/* + sed -i -e "s/%%ADMIN_PASSWORD%%/${LDAP_ADMIN_PASSWORD}/g" /custom_config/* + {{- end }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.initTLSSecret.resources }} + resources: {{- toYaml .Values.initTLSSecret.resources | nindent 12 }} + {{- end }} + volumeMounts: + {{- if .Values.customSchemaFiles }} + {{- range $file := (include "openldap.customSchemaFiles" . | split ",") }} + - name: cm-custom-schema-files + mountPath: /cm-schemas/{{ $file }}.ldif + subPath: {{ $file }}.ldif + {{- end }} + - name: custom-schema-files + mountPath: /custom-schemas/ + {{- end }} + {{- if or (.Values.customLdifFiles) (.Values.customLdifCm) }} + - name: cm-custom-ldif-files + mountPath: /cm-ldifs/ + - name: custom-ldif-files + mountPath: /custom-ldifs/ + {{- end }} + - name: cm-replication-acls + mountPath: "/cm-schemas-acls" + - name: replication-acls + mountPath: "/custom_config" + {{- if .Values.global.existingSecret }} + envFrom: + - secretRef: + name: {{ template "openldap.secretName" . }} + {{- end }} + {{- if .Values.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.initContainers "context" $) | nindent 8 }} + {{- end }} + - name: init-tls-secret + image: {{ include "openldap.initTLSSecretImage" . }} + imagePullPolicy: {{ .Values.initTLSSecret.image.pullPolicy | quote }} + command: + - sh + - -c + - | + {{- if and .Values.initTLSSecret.tls_enabled .Values.initTLSSecret.secret }} + {{- else }} + openssl req -x509 -newkey rsa:4096 -nodes -subj '/CN={{ .Values.global.ldapDomain }}' -keyout /tmp-certs/tls.key -out /tmp-certs/tls.crt -days 365 + chmod 777 /tmp-certs/* + {{- end }} + cp -Lr /tmp-certs/* /certs + [ -e /certs/ca.crt ] || cp -a /certs/tls.crt /certs/ca.crt + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.initTLSSecret.resources }} + resources: {{- toYaml .Values.initTLSSecret.resources | nindent 12 }} + {{- end }} + volumeMounts: + - name: certs + mountPath: "/certs" + - name: secret-certs + mountPath: "/tmp-certs" + {{- if .Values.volumePermissions.enabled }} + - name: volume-permissions + image: {{ include "openldap.volumePermissionsImage" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.volumePermissions.image.command "context" $) | nindent 12 }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- end }} + volumeMounts: + - mountPath: /bitnami + name: data + {{- end }} + + serviceAccountName: {{ template "openldap.serviceAccountName" . }} + {{- include "openldap.imagePullSecrets" . | nindent 6 }} + {{- if .Values.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.affinity }} + affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "component" "openldap-readonly" "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "component" "openldap-readonly" "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.schedulerName }} + schedulerName: {{- .Values.schedulerName | quote }} + {{- end }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.priorityClassName }} + priorityClassName: {{ .Values.priorityClassName | quote }} + {{- end }} + {{- if .Values.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.tolerations "context" $) | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + image: {{ include "openldap.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + {{- if .Values.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + envFrom: + {{- if .Values.extraEnvVarsCM }} + - configMapRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsCM "context" $) }} + {{- end }} + - configMapRef: + name: {{ template "openldap.fullname" . }}-env + - configMapRef: + name: {{ template "openldap.fullname" . }}-env-readonly-schemas + {{- if .Values.extraEnvVarsSecret }} + - secretRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} + {{- end }} + - secretRef: + name: {{ template "openldap.secretName" . }} + {{- if .Values.resources }} + resources: {{- toYaml .Values.resources | nindent 12 }} + {{- end }} + ports: + - name: ldap-port + containerPort: 1389 + - name: ssl-ldap-port + containerPort: 1636 + {{- if .Values.livenessProbe.enabled }} + livenessProbe: + tcpSocket: + port: ldap-port + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + {{- end }} + {{- if .Values.readinessProbe.enabled }} + readinessProbe: + tcpSocket: + port: ldap-port + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + {{- end }} + {{- if .Values.startupProbe.enabled }} + startupProbe: + tcpSocket: + port: ldap-port + initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.startupProbe.periodSeconds }} + timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }} + successThreshold: {{ .Values.startupProbe.successThreshold }} + failureThreshold: {{ .Values.startupProbe.failureThreshold }} + {{- else if .Values.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.customStartupProbe "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + - name: data + mountPath: /bitnami/openldap/ + - name: certs + mountPath: /opt/bitnami/openldap/certs + {{- range $file := (include "openldap.builtinSchemaFiles" . | split ",") }} + - name: replication-acls + mountPath: /opt/bitnami/openldap/etc/schema/{{ $file }}.ldif + subPath: {{ $file }}.ldif + {{- end }} +{{- if .Values.customSchemaFiles}} + {{- range $file := (include "openldap.customSchemaFiles" . | split ",") }} + - name: custom-schema-files + mountPath: /opt/bitnami/openldap/etc/schema/{{ $file }}.ldif + subPath: {{ $file }}.ldif + {{- end }} +{{- end }} + - name: readonly-ldif + mountPath: /opt/bitnami/openldap/etc/schema/readonly.ldif + subPath: readonly.ldif + +{{- if or (.Values.customLdifFiles) (.Values.customLdifCm) }} + - name: custom-ldif-files + mountPath: /ldifs/ +{{- end }} +{{- range .Values.customFileSets }} +{{- $fs := . }} +{{- range .files }} + - name: {{ $fs.name }} + mountPath: {{ $fs.targetPath }}/{{ .filename }} + subPath: {{ .filename }} +{{- end }} +{{- end }} +{{- if .Values.extraVolumeMounts }} +{{- include "common.tplvalues.render" (dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }} +{{- end }} +{{- if .Values.sidecars }} +{{- include "common.tplvalues.render" ( dict "value" .Values.sidecars "context" $) | nindent 8 }} +{{- end }} + volumes: +{{- if .Values.persistence.enabled }} +{{- if .Values.persistence.existingClaim }} + - name: data + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim }} +{{- end }} +{{- end }} + - name: cm-replication-acls + configMap: + name: {{ template "openldap.fullname" . }}-replication-acls + - name: replication-acls + emptyDir: + medium: Memory + +{{- if .Values.customLdifFiles }} + - name: cm-custom-ldif-files + configMap: + name: {{ template "openldap.fullname" . }}-customldif + - name: custom-ldif-files + emptyDir: + medium: Memory +{{- else if .Values.customLdifCm }} + - name: cm-custom-ldif-files + configMap: + name: {{ .Values.customLdifCm }} + - name: custom-ldif-files + emptyDir: + medium: Memory +{{- end }} +{{- if .Values.customSchemaFiles }} + - name: cm-custom-schema-files + configMap: + name: {{ template "openldap.fullname" . }}-customschema + - name: custom-schema-files + emptyDir: + medium: Memory +{{- end }} + - name: readonly-ldif + configMap: + name: {{ template "openldap.fullname" . }}-readonly + - name: certs + emptyDir: + medium: Memory +{{- if .Values.initTLSSecret.tls_enabled }} + - name: secret-certs + secret: + secretName: {{ .Values.initTLSSecret.secret }} +{{- else }} + - name: secret-certs + emptyDir: + medium: Memory +{{- end }} +{{- range .Values.customFileSets }} + - name: {{ .name }} + configMap: + name: {{ template "openldap.fullname" $ }}-fs-{{ .name }} +{{- end }} + {{- if .Values.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.extraVolumes "context" $) | nindent 8 }} + {{- end }} +{{- if and (not .Values.persistence.existingClaim) .Values.persistence.enabled }} + volumeClaimTemplates: + - metadata: + name: data + annotations: + {{- range $key, $value := .Values.persistence.annotations }} + {{ $key }}: {{ $value }} + {{- end }} + spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- if .Values.persistence.storageClass }} + {{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.persistence.storageClass }}" + {{- end }} +{{- end }} +{{- else if (not .Values.persistence.enabled) }} + - name: data + emptyDir: {} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/templates/svc-headless-readonly.yaml b/templates/svc-headless-readonly.yaml new file mode 100644 index 0000000..b0be7f1 --- /dev/null +++ b/templates/svc-headless-readonly.yaml @@ -0,0 +1,29 @@ +{{- if (gt (.Values.readOnlyReplicaCount | int) 0) -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "openldap.fullname" . }}-headless-readonly + labels: + app.kubernetes.io/component: {{ template "openldap.fullname" . }}-readonly + chart: {{ template "openldap.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + ports: + {{- if .Values.service.enableLdapPort }} + - port: {{ .Values.global.ldapPort }} + name: ldap-port + targetPort: ldap-port + {{- end }} + {{- if .Values.service.enableSslLdapPort }} + - port: {{ .Values.global.sslLdapPort }} + name: ssl-ldap-port + targetPort: ssl-ldap-port + {{- end }} + clusterIP: None + selector: + app.kubernetes.io/component: {{ template "openldap.fullname" . }}-readonly + release: {{ .Release.Name }} + type: ClusterIP + sessionAffinity: None +{{- end }} \ No newline at end of file diff --git a/values.yaml b/values.yaml index 2b94626..740bc73 100644 --- a/values.yaml +++ b/values.yaml @@ -51,6 +51,9 @@ extraDeploy: [] replicaCount: 3 +# Note: you need replication enabled to use readonly replicas! +readOnlyReplicaCount: 1 + image: # From repository https://hub.docker.com/r/bitnami/openldap/ #repository: bitnami/openldap From a790f756a81911b9ad873147fa0a68c2cbc2f7a5 Mon Sep 17 00:00:00 2001 From: David Frickert Date: Fri, 21 Jun 2024 12:14:06 +0200 Subject: [PATCH 03/22] separate values for read only services from normal service --- templates/service-readonly.yaml | 34 ++++++++++++++-------------- templates/svc-headless-readonly.yaml | 4 ++-- values.yaml | 24 ++++++++++++++++++++ 3 files changed, 43 insertions(+), 19 deletions(-) diff --git a/templates/service-readonly.yaml b/templates/service-readonly.yaml index 74fe24b..a9a24b8 100644 --- a/templates/service-readonly.yaml +++ b/templates/service-readonly.yaml @@ -2,9 +2,9 @@ apiVersion: v1 kind: Service metadata: -{{- if .Values.service.annotations }} +{{- if .Values.serviceReadOnly.annotations }} annotations: -{{ toYaml .Values.service.annotations | indent 4 }} +{{ toYaml .Values.serviceReadOnly.annotations | indent 4 }} {{- end }} name: {{ template "openldap.fullname" . }}-readonly namespace: {{ .Release.Namespace }} @@ -17,36 +17,36 @@ metadata: {{ toYaml .Values.extraLabels | indent 4 }} {{- end }} spec: - type: {{ .Values.service.type }} - {{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP }} - loadBalancerIP: {{ .Values.service.loadBalancerIP }} + type: {{ .Values.serviceReadOnly.type }} + {{- if and (eq .Values.serviceReadOnly.type "LoadBalancer") .Values.serviceReadOnly.loadBalancerIP }} + loadBalancerIP: {{ .Values.serviceReadOnly.loadBalancerIP }} {{- end }} - {{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerSourceRanges }} - loadBalancerSourceRanges: {{ toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }} + {{- if and (eq .Values.serviceReadOnly.type "LoadBalancer") .Values.serviceReadOnly.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{ toYaml .Values.serviceReadOnly.loadBalancerSourceRanges | nindent 4 }} {{- end }} - {{- if and (eq .Values.service.type "ClusterIP") .Values.service.clusterIP }} - clusterIP: {{ .Values.service.clusterIP }} + {{- if and (eq .Values.serviceReadOnly.type "ClusterIP") .Values.serviceReadOnly.clusterIP }} + clusterIP: {{ .Values.serviceReadOnly.clusterIP }} {{- end }} ports: - {{- if .Values.service.enableLdapPort }} + {{- if .Values.serviceReadOnly.enableLdapPort }} - name: ldap-port protocol: TCP port: {{ .Values.global.ldapPort }} targetPort: ldap-port - {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.ldapPortNodePort)) }} - nodePort: {{ .Values.service.ldapPortNodePort }} - {{- else if eq .Values.service.type "ClusterIP" }} + {{- if and (or (eq .Values.serviceReadOnly.type "NodePort") (eq .Values.serviceReadOnly.type "LoadBalancer")) (not (empty .Values.serviceReadOnly.ldapPortNodePort)) }} + nodePort: {{ .Values.serviceReadOnly.ldapPortNodePort }} + {{- else if eq .Values.serviceReadOnly.type "ClusterIP" }} nodePort: null {{- end }} {{- end }} - {{- if .Values.service.enableSslLdapPort }} + {{- if .Values.serviceReadOnly.enableSslLdapPort }} - name: ssl-ldap-port protocol: TCP port: {{ .Values.global.sslLdapPort }} targetPort: ssl-ldap-port - {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.sslLdapPortNodePort)) }} - nodePort: {{ .Values.service.sslLdapPortNodePort }} - {{- else if eq .Values.service.type "ClusterIP" }} + {{- if and (or (eq .Values.serviceReadOnly.type "NodePort") (eq .Values.serviceReadOnly.type "LoadBalancer")) (not (empty .Values.serviceReadOnly.sslLdapPortNodePort)) }} + nodePort: {{ .Values.serviceReadOnly.sslLdapPortNodePort }} + {{- else if eq .Values.serviceReadOnly.type "ClusterIP" }} nodePort: null {{- end }} {{- end }} diff --git a/templates/svc-headless-readonly.yaml b/templates/svc-headless-readonly.yaml index b0be7f1..de61e90 100644 --- a/templates/svc-headless-readonly.yaml +++ b/templates/svc-headless-readonly.yaml @@ -10,12 +10,12 @@ metadata: heritage: {{ .Release.Service }} spec: ports: - {{- if .Values.service.enableLdapPort }} + {{- if .Values.serviceReadOnly.enableLdapPort }} - port: {{ .Values.global.ldapPort }} name: ldap-port targetPort: ldap-port {{- end }} - {{- if .Values.service.enableSslLdapPort }} + {{- if .Values.serviceReadOnly.enableSslLdapPort }} - port: {{ .Values.global.sslLdapPort }} name: ssl-ldap-port targetPort: ssl-ldap-port diff --git a/values.yaml b/values.yaml index 740bc73..20589bf 100644 --- a/values.yaml +++ b/values.yaml @@ -99,6 +99,30 @@ service: type: ClusterIP sessionAffinity: None +# Service for read only cluster pods (if enabled) +serviceReadOnly: + annotations: {} + ## If service type NodePort, define the value here + #ldapPortNodePort: + #sslLdapPortNodePort: + + # Disable if you do not want to expose port on service + enableLdapPort: true + enableSslLdapPort: true + + ## List of IP addresses at which the service is available + ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips + ## + externalIPs: [] + + ## Define a static clusterIP + #clusterIP: + #loadBalancerIP: + #loadBalancerSourceRanges: [] + type: ClusterIP + sessionAffinity: None + + # Default configuration for openldap as environment variables. These get injected directly in the container. # Use the env variables from https://hub.docker.com/r/bitnami/openldap/ # Be careful, do not modify the following values unless you know exactly what your are doing From 389e1cf594bcc8b6c08ca3da09cbade7fe145bc6 Mon Sep 17 00:00:00 2001 From: David Frickert Date: Fri, 21 Jun 2024 12:21:46 +0200 Subject: [PATCH 04/22] splitenable ldap port values - allows for example to only enable SSL port on service but allow both ports on internal headless service --- templates/svc-headless-readonly.yaml | 4 ++-- values.yaml | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/templates/svc-headless-readonly.yaml b/templates/svc-headless-readonly.yaml index de61e90..f240a77 100644 --- a/templates/svc-headless-readonly.yaml +++ b/templates/svc-headless-readonly.yaml @@ -10,12 +10,12 @@ metadata: heritage: {{ .Release.Service }} spec: ports: - {{- if .Values.serviceReadOnly.enableLdapPort }} + {{- if .Values.serviceReadOnly.headlessEnableLdapPort }} - port: {{ .Values.global.ldapPort }} name: ldap-port targetPort: ldap-port {{- end }} - {{- if .Values.serviceReadOnly.enableSslLdapPort }} + {{- if .Values.serviceReadOnly.headlessEnableSslLdapPort }} - port: {{ .Values.global.sslLdapPort }} name: ssl-ldap-port targetPort: ssl-ldap-port diff --git a/values.yaml b/values.yaml index 20589bf..a611412 100644 --- a/values.yaml +++ b/values.yaml @@ -110,6 +110,10 @@ serviceReadOnly: enableLdapPort: true enableSslLdapPort: true + # Control ports used in statefulset + headlessEnableLdapPort: true + headlessEnableSslLdapPort: true + ## List of IP addresses at which the service is available ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips ## From 95f06a765a856d90894c8502ed8a5654587bbbcb Mon Sep 17 00:00:00 2001 From: David Frickert Date: Mon, 24 Jun 2024 16:43:32 +0200 Subject: [PATCH 05/22] WIP: Write test that verifies readonly replica --- .bin/readonly.yaml | 30 ++++++++++++++++ .github/workflows/ci-readonly.yml | 58 +++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 .bin/readonly.yaml create mode 100644 .github/workflows/ci-readonly.yml diff --git a/.bin/readonly.yaml b/.bin/readonly.yaml new file mode 100644 index 0000000..cfb207c --- /dev/null +++ b/.bin/readonly.yaml @@ -0,0 +1,30 @@ +persistence: + accessModes: + - ReadWriteOnce + enabled: true + size: 1Gi +ltb-passwd: + enabled : false +phpldapadmin: + enabled: false +replicaCount: 3 +readOnlyReplicaCount: 1 +replication: + clusterName: cluster.local + enabled: true + interval: "00:00:00:10" + retry: 60 + starttls: critical + timeout: 1 + tls_reqcert: never +initTLSSecret: + tls_enabled: true + secret: "custom-cert" +service: + ldapPortNodePort: 30389 + sslLdapPortNodePort: 30636 + type: NodePort +serviceReadOnly: + ldapPortNodePort: 31389 + sslLdapPortNodePort: 31636 + type: NodePort \ No newline at end of file diff --git a/.github/workflows/ci-readonly.yml b/.github/workflows/ci-readonly.yml new file mode 100644 index 0000000..1cbdb17 --- /dev/null +++ b/.github/workflows/ci-readonly.yml @@ -0,0 +1,58 @@ +# WIP! +name: Test readonly replica +on: + workflow_call: +jobs: + qualif: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v1 + - name: Run custom action + # Use the location in the repository (without action.yml) + uses: ./.github/actions/setup + with: + install-chaos: false + - name: setup certs + shell: bash + run: | + openssl req -x509 -newkey rsa:4096 -nodes -subj '/CN=example.com' -keyout tls.key -out tls.crt -days 365 + cp tls.crt ca.crt + kubectl create secret generic custom-cert --from-file=./tls.crt --from-file=./tls.key --from-file=./ca.crt + - name: deploy openldap-stack-ha + shell: bash + run: | + cd "$GITHUB_WORKSPACE" + helm install openldap-stack-ha -f .bin/readonly.yaml . + kubectl rollout status sts openldap-stack-ha + - name: verify deployment + shell: bash + run: | + echo "test access to openldap database" + sleep 10 + LDAPTLS_REQCERT=never ldapsearch -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' + - name: verify certs + shell: bash + run: | + echo "verify certificate" + echo | openssl s_client -showcerts -servername example.com -connect localhost:30636 2>/dev/null | openssl x509 -inform pem -noout -text > /tmp/test-cert.txt + if ! grep -q "CN = example.com" /tmp/test-cert.txt; then echo exit 1; fi + - name: test write on main cluster + shell: bash + run: | + echo "Write test to openldap database" + LDAPTLS_REQCERT=never ldapadd -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -f .bin/user.ldif + LDAPTLS_REQCERT=never ldapsearch -o nettimeout=20 -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' > /tmp/test-write.txt + if ! grep "Einstein" /tmp/test-write.txt; then echo 'no Einstein entry found' ; fi + if ! grep "objectClass: ownCloud" /tmp/test-write.txt; then echo 'no ownCloud entry found'; fi + - name: test memberOf on main cluster + shell: bash + run: | + echo "MemberOf test to openldap database" + LDAPTLS_REQCERT=never ldapsearch -o nettimeout=20 -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' "(memberOf=cn=testgroup,ou=Group,dc=example,dc=org)" > /tmp/test-write.txt + if [ $(grep "numResponses" /tmp/test-write.txt | cut -d ":" -f 2 | tr -d ' ') -ne 2 ]; then exit 1 ; fi + if ! grep -q "uid=test1,ou=People,dc=example,dc=org" /tmp/test-write.txt; then echo exit 1; fi + - name: test write on readonly replica + run: | + echo "Write test to openldap readonly replica" + LDAPTLS_REQCERT=never ldapadd -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:31636 -f .bin/user.ldif From d0dc98458bddcbff26001e3d329050ed529237a2 Mon Sep 17 00:00:00 2001 From: David Frickert Date: Mon, 24 Jun 2024 16:58:44 +0200 Subject: [PATCH 06/22] Code review fixes - removed env cm for schemas and instead just use env in each SS - removed part of readonly init container that only applies to master cluster --- templates/configmap-env-readonly-schemas.yaml | 23 ------------------- templates/configmap-env-schemas.yaml | 21 ----------------- templates/statefulset-readonly.yaml | 21 ++++------------- templates/statefulset.yaml | 4 ++-- 4 files changed, 6 insertions(+), 63 deletions(-) delete mode 100644 templates/configmap-env-readonly-schemas.yaml delete mode 100644 templates/configmap-env-schemas.yaml diff --git a/templates/configmap-env-readonly-schemas.yaml b/templates/configmap-env-readonly-schemas.yaml deleted file mode 100644 index b2af670..0000000 --- a/templates/configmap-env-readonly-schemas.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# -# A ConfigMap spec for openldap slapd that map directly to env variables in the Pod. -# List of environment variables supported is from the docker image: -# https://hub.docker.com/r/bitnami/openldap/ -# Note that passwords are defined as secrets -# -{{- if (gt (.Values.readOnlyReplicaCount | int) 0) }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "openldap.fullname" . }}-env-readonly-schemas - labels: - app: {{ template "openldap.name" . }} - chart: {{ template "openldap.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{- if .Values.extraLabels }} -{{ toYaml .Values.extraLabels | indent 4 }} -{{- end }} -data: - LDAP_EXTRA_SCHEMAS: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) ",readonly"}} -{{ toYaml .Values.env | indent 2 }} -{{- end }} \ No newline at end of file diff --git a/templates/configmap-env-schemas.yaml b/templates/configmap-env-schemas.yaml deleted file mode 100644 index eb37359..0000000 --- a/templates/configmap-env-schemas.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# -# A ConfigMap spec for openldap slapd that map directly to env variables in the Pod. -# List of environment variables supported is from the docker image: -# https://hub.docker.com/r/bitnami/openldap/ -# Note that passwords are defined as secrets -# -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "openldap.fullname" . }}-env-schemas - labels: - app: {{ template "openldap.name" . }} - chart: {{ template "openldap.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{- if .Values.extraLabels }} -{{ toYaml .Values.extraLabels | indent 4 }} -{{- end }} -data: - LDAP_EXTRA_SCHEMAS: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) }} -{{ toYaml .Values.env | indent 2 }} diff --git a/templates/statefulset-readonly.yaml b/templates/statefulset-readonly.yaml index 7a9d419..a1b18c0 100644 --- a/templates/statefulset-readonly.yaml +++ b/templates/statefulset-readonly.yaml @@ -49,21 +49,8 @@ spec: - sh - -c - | - host=$(hostname) - if [ "$host" = "{{ template "openldap.fullname" . }}-readonly-0" ] - then - echo "This is the main openldap so let's init all additional schemas and ldifs here" - cp -p -f /cm-schemas-acls/*.ldif /custom_config/ - if [ -d /cm-schemas ]; then - cp -p -f /cm-schemas/*.ldif /custom-schemas/ - fi - if [ -d /cm-ldifs ]; then - cp -p -f /cm-ldifs/*.ldif /custom-ldifs/ - fi - else - cp -p -f /cm-schemas-acls/*.ldif /custom_config/ - echo "let the replication takes care of everything :)" - fi + cp -p -f /cm-schemas-acls/*.ldif /custom_config/ + echo "let the replication takes care of everything :)" {{- if .Values.global.existingSecret }} sed -i -e "s/%%CONFIG_PASSWORD%%/${LDAP_CONFIG_ADMIN_PASSWORD}/g" /custom_config/* sed -i -e "s/%%ADMIN_PASSWORD%%/${LDAP_ADMIN_PASSWORD}/g" /custom_config/* @@ -187,6 +174,8 @@ spec: {{- if .Values.extraEnvVars }} {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} {{- end }} + - name: LDAP_EXTRA_SCHEMAS + value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) ",readonly"}} envFrom: {{- if .Values.extraEnvVarsCM }} - configMapRef: @@ -194,8 +183,6 @@ spec: {{- end }} - configMapRef: name: {{ template "openldap.fullname" . }}-env - - configMapRef: - name: {{ template "openldap.fullname" . }}-env-readonly-schemas {{- if .Values.extraEnvVarsSecret }} - secretRef: name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} diff --git a/templates/statefulset.yaml b/templates/statefulset.yaml index 5a0560e..9516e29 100644 --- a/templates/statefulset.yaml +++ b/templates/statefulset.yaml @@ -186,6 +186,8 @@ spec: {{- if .Values.extraEnvVars }} {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} {{- end }} + - name: LDAP_EXTRA_SCHEMAS + value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .)}} envFrom: {{- if .Values.extraEnvVarsCM }} - configMapRef: @@ -193,8 +195,6 @@ spec: {{- end }} - configMapRef: name: {{ template "openldap.fullname" . }}-env - - configMapRef: - name: {{ template "openldap.fullname" . }}-env-schemas {{- if .Values.extraEnvVarsSecret }} - secretRef: name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} From 44c8ae95454843f9815b91c7717e205a507673ce Mon Sep 17 00:00:00 2001 From: David Frickert Date: Tue, 25 Jun 2024 09:54:00 +0200 Subject: [PATCH 07/22] ci - call readonly job --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 195004a..3aef15d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,4 +13,6 @@ jobs: call-ci-other: uses: ./.github/workflows/ci-other.yml call-ci-ha: - uses: ./.github/workflows/ci-ha.yml \ No newline at end of file + uses: ./.github/workflows/ci-ha.yml + call-ci-readonly: + uses: ./.github/workflows/ci-readonly.yml \ No newline at end of file From 26156ba18d0acf3876ab01c00ee83d7ba66dc3bf Mon Sep 17 00:00:00 2001 From: David Frickert Date: Tue, 25 Jun 2024 14:35:43 +0200 Subject: [PATCH 08/22] need to load custom ldif for test to work as expected --- .bin/readonly.yaml | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/.bin/readonly.yaml b/.bin/readonly.yaml index cfb207c..7b5eada 100644 --- a/.bin/readonly.yaml +++ b/.bin/readonly.yaml @@ -1,3 +1,86 @@ +customSchemaFiles: + 00-memberof.ldif: |- + # Load memberof module + dn: cn=module,cn=config + cn: module + objectClass: olcModuleList + olcModuleLoad: memberof + olcModulePath: /opt/bitnami/openldap/lib/openldap + + dn: olcOverlay=memberof,olcDatabase={2}mdb,cn=config + changetype: add + objectClass: olcOverlayConfig + objectClass: olcMemberOf + olcOverlay: memberof + olcMemberOfRefint: TRUE + + 10_owncloud_schema.ldif: |- + # This LDIF files describes the ownCloud schema and can be used to + # add two optional attributes: ownCloudQuota and ownCloudUUID + # The ownCloudUUID is used to store a unique, non-reassignable, persistent identifier for users and groups + dn: cn=owncloud,cn=schema,cn=config + objectClass: olcSchemaConfig + cn: owncloud + olcObjectIdentifier: ownCloudOid 1.3.6.1.4.1.39430 + olcAttributeTypes: ( ownCloudOid:1.1.1 NAME 'ownCloudQuota' + DESC 'User Quota (e.g. 2 GB)' + EQUALITY caseExactMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE ) + olcAttributeTypes: ( ownCloudOid:1.1.2 NAME 'ownCloudUUID' + DESC 'A non-reassignable and persistent account ID)' + EQUALITY uuidMatch + SUBSTR caseIgnoreSubstringsMatch + SYNTAX 1.3.6.1.1.16.1 SINGLE-VALUE ) + olcObjectClasses: ( ownCloudOid:1.2.1 NAME 'ownCloud' + DESC 'ownCloud LDAP Schema' + AUXILIARY + MAY ( ownCloudQuota $ ownCloudUUID ) ) +customLdifFiles: + 00-root.ldif: |- + # Root creation + dn: dc=example,dc=org + objectClass: dcObject + objectClass: organization + o: Example, Inc + 01-default-group.ldif: |- + dn: cn=myGroup,dc=example,dc=org + cn: myGroup + gidnumber: 500 + objectclass: posixGroup + objectclass: top + 02-default-user.ldif: |- + dn: cn=Jean Dupond,dc=example,dc=org + cn: Jean Dupond + gidnumber: 500 + givenname: Jean + homedirectory: /home/users/jdupond + objectclass: inetOrgPerson + objectclass: posixAccount + objectClass: ownCloud + objectclass: top + sn: Dupond + uid: jdupond + uidnumber: 1000 + userpassword: {MD5}KOULhzfBhPTq9k7a9XfCGw== + 03-test-memberof.ldif: |- + dn: ou=Group,dc=example,dc=org + objectclass: organizationalUnit + ou: Group + + dn: ou=People,dc=example,dc=org + objectclass: organizationalUnit + ou: People + + dn: uid=test1,ou=People,dc=example,dc=org + objectclass: account + uid: test1 + + dn: cn=testgroup,ou=Group,dc=example,dc=org + objectclass: groupOfNames + cn: testgroup + member: uid=test1,ou=People,dc=example,dc=org + persistence: accessModes: - ReadWriteOnce From 2a410cdbbd5fb6e054384496399149bf03236a28 Mon Sep 17 00:00:00 2001 From: David Frickert Date: Tue, 25 Jun 2024 14:40:24 +0200 Subject: [PATCH 09/22] use 0 read only replicas as the default --- values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/values.yaml b/values.yaml index a611412..5815937 100644 --- a/values.yaml +++ b/values.yaml @@ -52,7 +52,7 @@ extraDeploy: [] replicaCount: 3 # Note: you need replication enabled to use readonly replicas! -readOnlyReplicaCount: 1 +readOnlyReplicaCount: 0 image: # From repository https://hub.docker.com/r/bitnami/openldap/ From 9740e503e955a9bc50ef5d861d66678d7570a727 Mon Sep 17 00:00:00 2001 From: David Frickert Date: Tue, 25 Jun 2024 14:43:37 +0200 Subject: [PATCH 10/22] add kind ports for read only ldap tests --- .bin/kind-conf.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.bin/kind-conf.yml b/.bin/kind-conf.yml index 67a046a..3e64ee8 100644 --- a/.bin/kind-conf.yml +++ b/.bin/kind-conf.yml @@ -20,5 +20,9 @@ nodes: hostPort: 30636 - containerPort: 30389 hostPort: 30389 + - containerPort: 31389 + hostPort: 31389 + - containerPort: 31636 + hostPort: 31636 - role: worker - role: worker From 4fe875e3840f4dad3e089069cf09fd6a69d84ef1 Mon Sep 17 00:00:00 2001 From: David Frickert Date: Wed, 26 Jun 2024 15:10:16 +0200 Subject: [PATCH 11/22] changes in replication to support readonly replica - use refreshOnly mode and exclude readonly replica from server list so that main cluster does not receive changes from readonly replica - remove readonly configmap as not needed anymore - add readonly specific replication ldif without mirror mode enabled - add ldif to remove mirror mode from readonly (needs to be manually executed for now) --- templates/_helpers.tpl | 51 +++++++++++------------ templates/configmap-readonly.yaml | 19 --------- templates/configmap-replication-acls.yaml | 20 +++++++++ templates/statefulset-readonly.yaml | 8 +--- 4 files changed, 46 insertions(+), 52 deletions(-) delete mode 100644 templates/configmap-readonly.yaml diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index ed66518..1daa84b 100755 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -84,13 +84,8 @@ Generate olcSyncRepl list {{- $nodeCount := .Values.replicaCount | int }} {{- range $index0 := until $nodeCount }} {{- $index1 := $index0 | add1 }} - olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshAndPersist retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} - {{- end -}} -{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }} - {{- range $index0 := until $readonlyNodeCount }} - {{- $index1 := $index0 | add $nodeCount | add 1 }} - olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshAndPersist retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} - {{- end -}} + olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshOnly retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} + {{- end -}} {{- end -}} {{/* @@ -119,30 +114,14 @@ Generate olcSyncRepl list bindmethod=simple credentials={{ $adminPassword }} searchbase={{ $domain }} - type=refreshAndPersist - interval={{ $interval }} - network-timeout=0 - retry="{{ $retry }} +" - timeout={{ $timeout }} - starttls={{ $starttls }} - tls_reqcert={{ $tls_reqcert }} - {{- end -}} - {{- range $index0 := until $readonlyNodeCount }} - {{- $index1 := $index0 | add $nodeCount | add 1 }} - olcSyncrepl: - rid=10{{ $index1 }} - provider=ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389 - binddn={{ printf "cn=%s,%s" $bindDNUser $domain }} - bindmethod=simple - credentials={{ $adminPassword }} - searchbase={{ $domain }} - type=refreshAndPersist + type=refreshOnly interval={{ $interval }} network-timeout=0 retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} + exattrs=olcMirrorMode,olcMultiProvider {{- end -}} {{- end -}} @@ -203,13 +182,21 @@ Cannot return list => return string comma separated {{- define "openldap.builtinSchemaFiles" -}} {{- $schemas := "" -}} {{- if .Values.replication.enabled -}} - {{- $schemas = "syncprov,serverid,csyncprov,rep,bsyncprov,brep,acls" -}} + {{- $schemas = "syncprov,serverid,csyncprov,rep,mirrorcfg,bsyncprov,brep,mirrormdb,acls" -}} {{- else -}} {{- $schemas = "acls" -}} {{- end -}} {{- print $schemas -}} {{- end -}} - +{{- define "openldap.builtinSchemaFilesReadOnly" -}} + {{- $schemas := "" -}} + {{- if .Values.replication.enabled -}} + {{- $schemas = "serverid,readonlybrep,readonlyrep,readonlyremovemirror" -}} + {{- else -}} + {{- $schemas = "" -}} + {{- end -}} + {{- print $schemas -}} +{{- end -}} {{/* Return the list of custom schema files to use Cannot return list => return string comma separated @@ -233,6 +220,16 @@ Cannot return list => return string comma separated {{- print $schemas -}} {{- end -}} +{{- define "openldap.schemaFilesReadOnly" -}} + {{- $schemas := (include "openldap.builtinSchemaFilesReadOnly" .) -}} + {{- $custom_schemas := (include "openldap.customSchemaFiles" .) -}} + {{- if gt (len $custom_schemas) 0 -}} + {{- $schemas = print $schemas "," $custom_schemas -}} + {{- end -}} + {{- print $schemas -}} +{{- end -}} + + {{/* Return the proper base domain */}} diff --git a/templates/configmap-readonly.yaml b/templates/configmap-readonly.yaml deleted file mode 100644 index aa69d47..0000000 --- a/templates/configmap-readonly.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{- if (gt (.Values.readOnlyReplicaCount | int) 0) }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "openldap.fullname" . }}-readonly - labels: - app: {{ template "openldap.name" . }} - chart: {{ template "openldap.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{- if .Values.extraLabels }} -{{ toYaml .Values.extraLabels | indent 4 }} -{{- end }} -data: - # replication - readonly.ldif: | - dn: olcDatabase={2}mdb,cn=config - olcReadonly: TRUE -{{- end }} \ No newline at end of file diff --git a/templates/configmap-replication-acls.yaml b/templates/configmap-replication-acls.yaml index 2b9382d..02a45e4 100755 --- a/templates/configmap-replication-acls.yaml +++ b/templates/configmap-replication-acls.yaml @@ -61,6 +61,26 @@ data: changetype: modify add: olcMirrorMode olcMirrorMode: TRUE + readonlybrep.ldif: | + dn: olcDatabase={2}mdb,cn=config + changetype: modify + add: olcSyncrepl + {{- include "olcSyncRepls2" . }} + # TODO - currently this needs to be executed manually e.g. via kubectl exec in each read only replica + # need to see if there is a way to make olcMultiProvider not be propagated from main cluster to readonly replicas. + readonlyremovemirror.ldif: | + dn: olcDatabase={2}mdb,cn=config + changetype: modify + delete: olcMultiProvider + + dn: olcDatabase={0}config,cn=config + changetype: modify + delete: olcMultiProvider + readonlyrep.ldif: | + dn: olcDatabase={0}config,cn=config + changetype: modify + add: olcSyncRepl + {{- include "olcSyncRepls" . }} # acls acls.ldif: | {{- if .Values.customAcls }} diff --git a/templates/statefulset-readonly.yaml b/templates/statefulset-readonly.yaml index a1b18c0..66354c4 100644 --- a/templates/statefulset-readonly.yaml +++ b/templates/statefulset-readonly.yaml @@ -175,7 +175,7 @@ spec: {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} {{- end }} - name: LDAP_EXTRA_SCHEMAS - value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) ",readonly"}} + value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFilesReadOnly" .)}} envFrom: {{- if .Values.extraEnvVarsCM }} - configMapRef: @@ -237,7 +237,7 @@ spec: mountPath: /bitnami/openldap/ - name: certs mountPath: /opt/bitnami/openldap/certs - {{- range $file := (include "openldap.builtinSchemaFiles" . | split ",") }} + {{- range $file := (include "openldap.builtinSchemaFilesReadOnly" . | split ",") }} - name: replication-acls mountPath: /opt/bitnami/openldap/etc/schema/{{ $file }}.ldif subPath: {{ $file }}.ldif @@ -249,10 +249,6 @@ spec: subPath: {{ $file }}.ldif {{- end }} {{- end }} - - name: readonly-ldif - mountPath: /opt/bitnami/openldap/etc/schema/readonly.ldif - subPath: readonly.ldif - {{- if or (.Values.customLdifFiles) (.Values.customLdifCm) }} - name: custom-ldif-files mountPath: /ldifs/ From 685cba1077cd195cc9f52145af680a5ada1ebf71 Mon Sep 17 00:00:00 2001 From: David Frickert Date: Wed, 26 Jun 2024 15:10:52 +0200 Subject: [PATCH 12/22] CI readonly test fix --- .bin/user2.ldif | 17 ++++++++++++++ .github/workflows/ci-readonly.yml | 38 +++++++++++++++++-------------- 2 files changed, 38 insertions(+), 17 deletions(-) create mode 100644 .bin/user2.ldif diff --git a/.bin/user2.ldif b/.bin/user2.ldif new file mode 100644 index 0000000..7df7f49 --- /dev/null +++ b/.bin/user2.ldif @@ -0,0 +1,17 @@ +dn: uid=ro,ou=users,dc=example,dc=org +objectClass: inetOrgPerson +objectClass: organizationalPerson +objectClass: person +objectClass: posixAccount +objectClass: top +uid: ro +givenName: u +sn: u +cn: u +displayName: U +description: User to test that readonly cluster cannot be used to add more users. +mail: u@example.org +uidNumber: 21000 +gidNumber: 31000 +homeDirectory: /home/u +userPassword:: p1NTSEF9TXJEcXpFNGdKbXZxbVRVTGhvWEZ1VzJBbkV3NWFLK3J3WTIvbHc9PQ== \ No newline at end of file diff --git a/.github/workflows/ci-readonly.yml b/.github/workflows/ci-readonly.yml index 1cbdb17..cb46ef3 100644 --- a/.github/workflows/ci-readonly.yml +++ b/.github/workflows/ci-readonly.yml @@ -28,31 +28,35 @@ jobs: - name: verify deployment shell: bash run: | - echo "test access to openldap database" - sleep 10 - LDAPTLS_REQCERT=never ldapsearch -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' + echo "test access to openldap database" + sleep 10 + LDAPTLS_REQCERT=never ldapsearch -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' - name: verify certs shell: bash run: | - echo "verify certificate" - echo | openssl s_client -showcerts -servername example.com -connect localhost:30636 2>/dev/null | openssl x509 -inform pem -noout -text > /tmp/test-cert.txt - if ! grep -q "CN = example.com" /tmp/test-cert.txt; then echo exit 1; fi + echo "verify certificate" + echo | openssl s_client -showcerts -servername example.com -connect localhost:30636 2>/dev/null | openssl x509 -inform pem -noout -text > /tmp/test-cert.txt + if ! grep -q "CN = example.com" /tmp/test-cert.txt; then echo exit 1; fi - name: test write on main cluster shell: bash run: | - echo "Write test to openldap database" - LDAPTLS_REQCERT=never ldapadd -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -f .bin/user.ldif - LDAPTLS_REQCERT=never ldapsearch -o nettimeout=20 -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' > /tmp/test-write.txt - if ! grep "Einstein" /tmp/test-write.txt; then echo 'no Einstein entry found' ; fi - if ! grep "objectClass: ownCloud" /tmp/test-write.txt; then echo 'no ownCloud entry found'; fi + echo "Write test to openldap database" + LDAPTLS_REQCERT=never ldapadd -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -f .bin/user.ldif + LDAPTLS_REQCERT=never ldapsearch -o nettimeout=20 -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' > /tmp/test-write.txt + if ! grep "Einstein" /tmp/test-write.txt; then echo 'no Einstein entry found' ; fi + if ! grep "objectClass: ownCloud" /tmp/test-write.txt; then echo 'no ownCloud entry found'; fi - name: test memberOf on main cluster shell: bash run: | - echo "MemberOf test to openldap database" - LDAPTLS_REQCERT=never ldapsearch -o nettimeout=20 -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' "(memberOf=cn=testgroup,ou=Group,dc=example,dc=org)" > /tmp/test-write.txt - if [ $(grep "numResponses" /tmp/test-write.txt | cut -d ":" -f 2 | tr -d ' ') -ne 2 ]; then exit 1 ; fi - if ! grep -q "uid=test1,ou=People,dc=example,dc=org" /tmp/test-write.txt; then echo exit 1; fi + echo "MemberOf test to openldap database" + LDAPTLS_REQCERT=never ldapsearch -o nettimeout=20 -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:30636 -b 'dc=example,dc=org' "(memberOf=cn=testgroup,ou=Group,dc=example,dc=org)" > /tmp/test-write.txt + if [ $(grep "numResponses" /tmp/test-write.txt | cut -d ":" -f 2 | tr -d ' ') -ne 2 ]; then exit 1 ; fi + if ! grep -q "uid=test1,ou=People,dc=example,dc=org" /tmp/test-write.txt; then echo exit 1; fi - name: test write on readonly replica + shell: bash run: | - echo "Write test to openldap readonly replica" - LDAPTLS_REQCERT=never ldapadd -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:31636 -f .bin/user.ldif + echo "Ensure readonly replica does not have mirror mode enabled" + kubectl exec openldap-stack-ha-readonly-0 -- bash -c "/opt/bitnami/openldap/bin/ldapmodify -Y EXTERNAL -H ldapi:/// -f /opt/bitnami/openldap/etc/schema/readonlyremovemirror.ldif" + + echo "Write test to openldap readonly replica" + if LDAPTLS_REQCERT=never ldapadd -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:31636 -f .bin/user2.ldif; then echo exit 1; fi From a8f0e11863441b6cad2f378a8a2ccff6b5acda66 Mon Sep 17 00:00:00 2001 From: jpgouin Date: Thu, 18 Jul 2024 07:38:59 +0000 Subject: [PATCH 13/22] save current readlonly strategy --- .bin/kind-conf.yml | 4 ++ templates/NOTES.txt | 1 + templates/_helpers.tpl | 28 -------------- templates/configmap-env-readonly-schemas.yaml | 23 ------------ templates/configmap-env-schemas.yaml | 21 ----------- templates/configmap-readonly.yaml | 7 +++- templates/statefulset-readonly.yaml | 37 ++++++------------- templates/statefulset.yaml | 4 +- 8 files changed, 23 insertions(+), 102 deletions(-) delete mode 100644 templates/configmap-env-readonly-schemas.yaml delete mode 100644 templates/configmap-env-schemas.yaml diff --git a/.bin/kind-conf.yml b/.bin/kind-conf.yml index 67a046a..75e2272 100644 --- a/.bin/kind-conf.yml +++ b/.bin/kind-conf.yml @@ -20,5 +20,9 @@ nodes: hostPort: 30636 - containerPort: 30389 hostPort: 30389 + - containerPort: 31636 + hostPort: 31636 + - containerPort: 31389 + hostPort: 31389 - role: worker - role: worker diff --git a/templates/NOTES.txt b/templates/NOTES.txt index 3ffe651..7f5f035 100755 --- a/templates/NOTES.txt +++ b/templates/NOTES.txt @@ -1,3 +1,4 @@ + ** Please be patient while the chart is being deployed ** OpenLDAP-Stack-HA has been installed. You can access the server from within the k8s cluster using: diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index ed66518..2a76fd5 100755 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -61,11 +61,6 @@ Generate olcServerID list {{- $index1 := $index0 | add1 }} olcServerID: {{ $index1 }} ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 {{- end -}} -{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }} - {{- range $index0 := until $readonlyNodeCount }} - {{- $index1 := $index0 | add $nodeCount | add 1 }} - olcServerID: {{ $index1 }} ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389 - {{- end -}} {{- end -}} {{/* @@ -86,11 +81,6 @@ Generate olcSyncRepl list {{- $index1 := $index0 | add1 }} olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshAndPersist retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} {{- end -}} -{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }} - {{- range $index0 := until $readonlyNodeCount }} - {{- $index1 := $index0 | add $nodeCount | add 1 }} - olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshAndPersist retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} - {{- end -}} {{- end -}} {{/* @@ -109,7 +99,6 @@ Generate olcSyncRepl list {{- $tls_reqcert := .Values.replication.tls_reqcert }} {{- $interval := .Values.replication.interval }} {{- $nodeCount := .Values.replicaCount | int }} -{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }} {{- range $index0 := until $nodeCount }} {{- $index1 := $index0 | add1 }} olcSyncrepl: @@ -127,23 +116,6 @@ Generate olcSyncRepl list starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} {{- end -}} - {{- range $index0 := until $readonlyNodeCount }} - {{- $index1 := $index0 | add $nodeCount | add 1 }} - olcSyncrepl: - rid=10{{ $index1 }} - provider=ldap://{{ $name }}-readonly-{{ $index0 }}.{{ $name }}-headless-readonly.{{ $namespace }}.svc.{{ $cluster }}:1389 - binddn={{ printf "cn=%s,%s" $bindDNUser $domain }} - bindmethod=simple - credentials={{ $adminPassword }} - searchbase={{ $domain }} - type=refreshAndPersist - interval={{ $interval }} - network-timeout=0 - retry="{{ $retry }} +" - timeout={{ $timeout }} - starttls={{ $starttls }} - tls_reqcert={{ $tls_reqcert }} - {{- end -}} {{- end -}} {{/* diff --git a/templates/configmap-env-readonly-schemas.yaml b/templates/configmap-env-readonly-schemas.yaml deleted file mode 100644 index b2af670..0000000 --- a/templates/configmap-env-readonly-schemas.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# -# A ConfigMap spec for openldap slapd that map directly to env variables in the Pod. -# List of environment variables supported is from the docker image: -# https://hub.docker.com/r/bitnami/openldap/ -# Note that passwords are defined as secrets -# -{{- if (gt (.Values.readOnlyReplicaCount | int) 0) }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "openldap.fullname" . }}-env-readonly-schemas - labels: - app: {{ template "openldap.name" . }} - chart: {{ template "openldap.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{- if .Values.extraLabels }} -{{ toYaml .Values.extraLabels | indent 4 }} -{{- end }} -data: - LDAP_EXTRA_SCHEMAS: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) ",readonly"}} -{{ toYaml .Values.env | indent 2 }} -{{- end }} \ No newline at end of file diff --git a/templates/configmap-env-schemas.yaml b/templates/configmap-env-schemas.yaml deleted file mode 100644 index eb37359..0000000 --- a/templates/configmap-env-schemas.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# -# A ConfigMap spec for openldap slapd that map directly to env variables in the Pod. -# List of environment variables supported is from the docker image: -# https://hub.docker.com/r/bitnami/openldap/ -# Note that passwords are defined as secrets -# -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ template "openldap.fullname" . }}-env-schemas - labels: - app: {{ template "openldap.name" . }} - chart: {{ template "openldap.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} -{{- if .Values.extraLabels }} -{{ toYaml .Values.extraLabels | indent 4 }} -{{- end }} -data: - LDAP_EXTRA_SCHEMAS: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) }} -{{ toYaml .Values.env | indent 2 }} diff --git a/templates/configmap-readonly.yaml b/templates/configmap-readonly.yaml index aa69d47..f20a432 100644 --- a/templates/configmap-readonly.yaml +++ b/templates/configmap-readonly.yaml @@ -12,8 +12,11 @@ metadata: {{ toYaml .Values.extraLabels | indent 4 }} {{- end }} data: - # replication readonly.ldif: | dn: olcDatabase={2}mdb,cn=config - olcReadonly: TRUE + changetype: modify + add: olcAccess + olcAccess: to * + by dn.exact="{{ include "global.bindDN" . }}" write + by * read {{- end }} \ No newline at end of file diff --git a/templates/statefulset-readonly.yaml b/templates/statefulset-readonly.yaml index 7a9d419..b97f84b 100644 --- a/templates/statefulset-readonly.yaml +++ b/templates/statefulset-readonly.yaml @@ -49,21 +49,8 @@ spec: - sh - -c - | - host=$(hostname) - if [ "$host" = "{{ template "openldap.fullname" . }}-readonly-0" ] - then - echo "This is the main openldap so let's init all additional schemas and ldifs here" - cp -p -f /cm-schemas-acls/*.ldif /custom_config/ - if [ -d /cm-schemas ]; then - cp -p -f /cm-schemas/*.ldif /custom-schemas/ - fi - if [ -d /cm-ldifs ]; then - cp -p -f /cm-ldifs/*.ldif /custom-ldifs/ - fi - else - cp -p -f /cm-schemas-acls/*.ldif /custom_config/ - echo "let the replication takes care of everything :)" - fi + cp -p -f /cm-schemas-acls/brep.ldif /custom_config/ + echo "let the replication takes care of everything :)" {{- if .Values.global.existingSecret }} sed -i -e "s/%%CONFIG_PASSWORD%%/${LDAP_CONFIG_ADMIN_PASSWORD}/g" /custom_config/* sed -i -e "s/%%ADMIN_PASSWORD%%/${LDAP_ADMIN_PASSWORD}/g" /custom_config/* @@ -91,9 +78,9 @@ spec: mountPath: /custom-ldifs/ {{- end }} - name: cm-replication-acls - mountPath: "/cm-schemas-acls" + mountPath: /cm-schemas-acls - name: replication-acls - mountPath: "/custom_config" + mountPath: /custom_config {{- if .Values.global.existingSecret }} envFrom: - secretRef: @@ -179,6 +166,8 @@ spec: securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} {{- end }} env: + - name: LDAP_EXTRA_SCHEMAS + value: {{ print "cosine,inetorgperson,nis,brep,readonly" }} - name: POD_NAME valueFrom: fieldRef: @@ -194,8 +183,6 @@ spec: {{- end }} - configMapRef: name: {{ template "openldap.fullname" . }}-env - - configMapRef: - name: {{ template "openldap.fullname" . }}-env-readonly-schemas {{- if .Values.extraEnvVarsSecret }} - secretRef: name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} @@ -250,11 +237,12 @@ spec: mountPath: /bitnami/openldap/ - name: certs mountPath: /opt/bitnami/openldap/certs - {{- range $file := (include "openldap.builtinSchemaFiles" . | split ",") }} - name: replication-acls - mountPath: /opt/bitnami/openldap/etc/schema/{{ $file }}.ldif - subPath: {{ $file }}.ldif - {{- end }} + mountPath: /opt/bitnami/openldap/etc/schema/brep.ldif + subPath: brep.ldif + - name: readonly-ldif + mountPath: /opt/bitnami/openldap/etc/schema/readonly.ldif + subPath: readonly.ldif {{- if .Values.customSchemaFiles}} {{- range $file := (include "openldap.customSchemaFiles" . | split ",") }} - name: custom-schema-files @@ -262,9 +250,6 @@ spec: subPath: {{ $file }}.ldif {{- end }} {{- end }} - - name: readonly-ldif - mountPath: /opt/bitnami/openldap/etc/schema/readonly.ldif - subPath: readonly.ldif {{- if or (.Values.customLdifFiles) (.Values.customLdifCm) }} - name: custom-ldif-files diff --git a/templates/statefulset.yaml b/templates/statefulset.yaml index 5a0560e..9acf223 100644 --- a/templates/statefulset.yaml +++ b/templates/statefulset.yaml @@ -178,6 +178,8 @@ spec: securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} {{- end }} env: + - name: LDAP_EXTRA_SCHEMAS + value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) }} - name: POD_NAME valueFrom: fieldRef: @@ -193,8 +195,6 @@ spec: {{- end }} - configMapRef: name: {{ template "openldap.fullname" . }}-env - - configMapRef: - name: {{ template "openldap.fullname" . }}-env-schemas {{- if .Values.extraEnvVarsSecret }} - secretRef: name: {{ include "common.tplvalues.render" (dict "value" .Values.extraEnvVarsSecret "context" $) }} From b3c79d4c96d71ea8aba375df8339aff84a5b6864 Mon Sep 17 00:00:00 2001 From: David Frickert Date: Tue, 3 Sep 2024 16:43:50 +0200 Subject: [PATCH 14/22] commit some changes that were uncommitted for readonly functionality --- templates/_helpers.tpl | 51 ++++++++++++++++++++++- templates/configmap-replication-acls.yaml | 5 ++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 1daa84b..2c2adae 100755 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -88,6 +88,23 @@ Generate olcSyncRepl list {{- end -}} {{- end -}} +{{- define "olcSyncReplsReadOnly" -}} +{{- $name := (include "openldap.fullname" .) }} +{{- $namespace := .Release.Namespace }} +{{- $bindDNUser := .Values.global.adminUser }} +{{- $cluster := .Values.replication.clusterName }} +{{- $configPassword := ternary .Values.global.configPassword "%%CONFIG_PASSWORD%%" (empty .Values.global.existingSecret) }} +{{- $retry := .Values.replication.retry }} +{{- $timeout := .Values.replication.timeout }} +{{- $starttls := .Values.replication.starttls }} +{{- $tls_reqcert := .Values.replication.tls_reqcert }} +{{- $nodeCount := .Values.replicaCount | int }} + {{- range $index0 := until $nodeCount }} + {{- $index1 := $index0 | add1 }} + olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshOnly retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} + {{- end -}} +{{- end -}} + {{/* Generate olcSyncRepl list */}} @@ -104,7 +121,39 @@ Generate olcSyncRepl list {{- $tls_reqcert := .Values.replication.tls_reqcert }} {{- $interval := .Values.replication.interval }} {{- $nodeCount := .Values.replicaCount | int }} -{{- $readonlyNodeCount := .Values.readOnlyReplicaCount | int }} + {{- range $index0 := until $nodeCount }} + {{- $index1 := $index0 | add1 }} + olcSyncrepl: + rid=10{{ $index1 }} + provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 + binddn={{ printf "cn=%s,%s" $bindDNUser $domain }} + bindmethod=simple + credentials={{ $adminPassword }} + searchbase={{ $domain }} + type=refreshOnly + interval={{ $interval }} + network-timeout=0 + retry="{{ $retry }} +" + timeout={{ $timeout }} + starttls={{ $starttls }} + tls_reqcert={{ $tls_reqcert }} + exattrs=olcMirrorMode,olcMultiProvider + {{- end -}} +{{- end -}} + +{{- define "olcSyncRepls2ReadOnly" -}} +{{- $name := (include "openldap.fullname" .) }} +{{- $domain := (include "global.baseDomain" .) }} +{{- $bindDNUser := .Values.global.adminUser }} +{{- $namespace := .Release.Namespace }} +{{- $cluster := .Values.replication.clusterName }} +{{- $adminPassword := ternary .Values.global.adminPassword "%%ADMIN_PASSWORD%%" (empty .Values.global.existingSecret) }} +{{- $retry := .Values.replication.retry }} +{{- $timeout := .Values.replication.timeout }} +{{- $starttls := .Values.replication.starttls }} +{{- $tls_reqcert := .Values.replication.tls_reqcert }} +{{- $interval := .Values.replication.interval }} +{{- $nodeCount := .Values.replicaCount | int }} {{- range $index0 := until $nodeCount }} {{- $index1 := $index0 | add1 }} olcSyncrepl: diff --git a/templates/configmap-replication-acls.yaml b/templates/configmap-replication-acls.yaml index 02a45e4..4d5c2be 100755 --- a/templates/configmap-replication-acls.yaml +++ b/templates/configmap-replication-acls.yaml @@ -65,7 +65,7 @@ data: dn: olcDatabase={2}mdb,cn=config changetype: modify add: olcSyncrepl - {{- include "olcSyncRepls2" . }} + {{- include "olcSyncRepls2ReadOnly" . }} # TODO - currently this needs to be executed manually e.g. via kubectl exec in each read only replica # need to see if there is a way to make olcMultiProvider not be propagated from main cluster to readonly replicas. readonlyremovemirror.ldif: | @@ -76,11 +76,12 @@ data: dn: olcDatabase={0}config,cn=config changetype: modify delete: olcMultiProvider + readonlyrep.ldif: | dn: olcDatabase={0}config,cn=config changetype: modify add: olcSyncRepl - {{- include "olcSyncRepls" . }} + {{- include "olcSyncReplsReadOnly" . }} # acls acls.ldif: | {{- if .Values.customAcls }} From d1c380ca699bb85e16152b1539224011d45365e9 Mon Sep 17 00:00:00 2001 From: jpgouin Date: Fri, 27 Sep 2024 12:00:05 +0000 Subject: [PATCH 15/22] add read-only replica --- templates/_helpers.tpl | 17 +++++++++++++---- templates/configmap-readonly.yaml | 6 ++---- templates/statefulset-readonly.yaml | 2 +- templates/statefulset.yaml | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 2a76fd5..f89047c 100755 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -174,8 +174,14 @@ Cannot return list => return string comma separated */}} {{- define "openldap.builtinSchemaFiles" -}} {{- $schemas := "" -}} - {{- if .Values.replication.enabled -}} - {{- $schemas = "syncprov,serverid,csyncprov,rep,bsyncprov,brep,acls" -}} + {{- $context := index . "context" -}} + {{- $mode := index . "mode" -}} + {{- if $context.Values.replication.enabled -}} + {{- if $mode -}} + {{- $schemas = "brep,readonly,acls" -}} + {{- else -}} + {{- $schemas = "syncprov,serverid,csyncprov,rep,bsyncprov,brep,acls" -}} + {{- end -}} {{- else -}} {{- $schemas = "acls" -}} {{- end -}} @@ -187,8 +193,9 @@ Return the list of custom schema files to use Cannot return list => return string comma separated */}} {{- define "openldap.customSchemaFiles" -}} + {{- $context := index . "context" -}} {{- $schemas := "" -}} - {{- $schemas := ((join "," (.Values.customSchemaFiles | keys | sortAlpha)) | replace ".ldif" "") -}} + {{- $schemas := ((join "," ($context.Values.customSchemaFiles | keys | sortAlpha)) | replace ".ldif" "") -}} {{- print $schemas -}} {{- end -}} @@ -197,6 +204,8 @@ Return the list of all schema files to use Cannot return list => return string comma separated */}} {{- define "openldap.schemaFiles" -}} + {{- $context := index . "context" -}} + {{- $mode := index . "mode" -}} {{- $schemas := (include "openldap.builtinSchemaFiles" .) -}} {{- $custom_schemas := (include "openldap.customSchemaFiles" .) -}} {{- if gt (len $custom_schemas) 0 -}} @@ -236,7 +245,7 @@ Return the server name {{- end -}} {{/* -Return the bdmin indDN +Return the admin bindDN */}} {{- define "global.bindDN" -}} {{- printf "cn=%s,%s" .Values.global.adminUser (include "global.baseDomain" .) -}} diff --git a/templates/configmap-readonly.yaml b/templates/configmap-readonly.yaml index f20a432..454332f 100644 --- a/templates/configmap-readonly.yaml +++ b/templates/configmap-readonly.yaml @@ -15,8 +15,6 @@ data: readonly.ldif: | dn: olcDatabase={2}mdb,cn=config changetype: modify - add: olcAccess - olcAccess: to * - by dn.exact="{{ include "global.bindDN" . }}" write - by * read + replace: olcReadOnly + olcReadOnly: TRUE {{- end }} \ No newline at end of file diff --git a/templates/statefulset-readonly.yaml b/templates/statefulset-readonly.yaml index b97f84b..e03a2c2 100644 --- a/templates/statefulset-readonly.yaml +++ b/templates/statefulset-readonly.yaml @@ -167,7 +167,7 @@ spec: {{- end }} env: - name: LDAP_EXTRA_SCHEMAS - value: {{ print "cosine,inetorgperson,nis,brep,readonly" }} + value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" (dict "context" . "mode" "readonly")) }} - name: POD_NAME valueFrom: fieldRef: diff --git a/templates/statefulset.yaml b/templates/statefulset.yaml index 9acf223..c6c871f 100644 --- a/templates/statefulset.yaml +++ b/templates/statefulset.yaml @@ -179,7 +179,7 @@ spec: {{- end }} env: - name: LDAP_EXTRA_SCHEMAS - value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .) }} + value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" (dict "context" . )) }} - name: POD_NAME valueFrom: fieldRef: From 0ba252811af6146d0a95b6561465b63c1fed4e1d Mon Sep 17 00:00:00 2001 From: jpgouin Date: Fri, 27 Sep 2024 12:10:28 +0000 Subject: [PATCH 16/22] merge helper --- templates/_helpers.tpl | 63 ------------------------------------------ 1 file changed, 63 deletions(-) diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 9471d13..2aa02f6 100755 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -79,30 +79,8 @@ Generate olcSyncRepl list {{- $nodeCount := .Values.replicaCount | int }} {{- range $index0 := until $nodeCount }} {{- $index1 := $index0 | add1 }} -<<<<<<< HEAD olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshAndPersist retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} {{- end -}} -======= - olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshOnly retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} - {{- end -}} -{{- end -}} - -{{- define "olcSyncReplsReadOnly" -}} -{{- $name := (include "openldap.fullname" .) }} -{{- $namespace := .Release.Namespace }} -{{- $bindDNUser := .Values.global.adminUser }} -{{- $cluster := .Values.replication.clusterName }} -{{- $configPassword := ternary .Values.global.configPassword "%%CONFIG_PASSWORD%%" (empty .Values.global.existingSecret) }} -{{- $retry := .Values.replication.retry }} -{{- $timeout := .Values.replication.timeout }} -{{- $starttls := .Values.replication.starttls }} -{{- $tls_reqcert := .Values.replication.tls_reqcert }} -{{- $nodeCount := .Values.replicaCount | int }} - {{- range $index0 := until $nodeCount }} - {{- $index1 := $index0 | add1 }} - olcSyncRepl: rid=00{{ $index1 }} provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 binddn="cn={{ $bindDNUser }},cn=config" bindmethod=simple credentials={{ $configPassword }} searchbase="cn=config" type=refreshOnly retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} - {{- end -}} ->>>>>>> b3c79d4c96d71ea8aba375df8339aff84a5b6864 {{- end -}} {{/* @@ -139,42 +117,6 @@ Generate olcSyncRepl list tls_reqcert={{ $tls_reqcert }} exattrs=olcMirrorMode,olcMultiProvider {{- end -}} -<<<<<<< HEAD -======= -{{- end -}} - -{{- define "olcSyncRepls2ReadOnly" -}} -{{- $name := (include "openldap.fullname" .) }} -{{- $domain := (include "global.baseDomain" .) }} -{{- $bindDNUser := .Values.global.adminUser }} -{{- $namespace := .Release.Namespace }} -{{- $cluster := .Values.replication.clusterName }} -{{- $adminPassword := ternary .Values.global.adminPassword "%%ADMIN_PASSWORD%%" (empty .Values.global.existingSecret) }} -{{- $retry := .Values.replication.retry }} -{{- $timeout := .Values.replication.timeout }} -{{- $starttls := .Values.replication.starttls }} -{{- $tls_reqcert := .Values.replication.tls_reqcert }} -{{- $interval := .Values.replication.interval }} -{{- $nodeCount := .Values.replicaCount | int }} - {{- range $index0 := until $nodeCount }} - {{- $index1 := $index0 | add1 }} - olcSyncrepl: - rid=10{{ $index1 }} - provider=ldap://{{ $name }}-{{ $index0 }}.{{ $name }}-headless.{{ $namespace }}.svc.{{ $cluster }}:1389 - binddn={{ printf "cn=%s,%s" $bindDNUser $domain }} - bindmethod=simple - credentials={{ $adminPassword }} - searchbase={{ $domain }} - type=refreshOnly - interval={{ $interval }} - network-timeout=0 - retry="{{ $retry }} +" - timeout={{ $timeout }} - starttls={{ $starttls }} - tls_reqcert={{ $tls_reqcert }} - exattrs=olcMirrorMode,olcMultiProvider - {{- end -}} ->>>>>>> b3c79d4c96d71ea8aba375df8339aff84a5b6864 {{- end -}} {{/* @@ -233,7 +175,6 @@ Cannot return list => return string comma separated */}} {{- define "openldap.builtinSchemaFiles" -}} {{- $schemas := "" -}} -<<<<<<< HEAD {{- $context := index . "context" -}} {{- $mode := index . "mode" -}} {{- if $context.Values.replication.enabled -}} @@ -242,10 +183,6 @@ Cannot return list => return string comma separated {{- else -}} {{- $schemas = "syncprov,serverid,csyncprov,rep,bsyncprov,brep,acls" -}} {{- end -}} -======= - {{- if .Values.replication.enabled -}} - {{- $schemas = "syncprov,serverid,csyncprov,rep,mirrorcfg,bsyncprov,brep,mirrormdb,acls" -}} ->>>>>>> b3c79d4c96d71ea8aba375df8339aff84a5b6864 {{- else -}} {{- $schemas = "acls" -}} {{- end -}} From baee6c971e1dbedba334719cb97b4da3fe3642f8 Mon Sep 17 00:00:00 2001 From: jpgouin Date: Fri, 27 Sep 2024 12:12:47 +0000 Subject: [PATCH 17/22] merge helper --- templates/configmap-replication-acls.yaml | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/templates/configmap-replication-acls.yaml b/templates/configmap-replication-acls.yaml index 4d5c2be..2b9382d 100755 --- a/templates/configmap-replication-acls.yaml +++ b/templates/configmap-replication-acls.yaml @@ -61,27 +61,6 @@ data: changetype: modify add: olcMirrorMode olcMirrorMode: TRUE - readonlybrep.ldif: | - dn: olcDatabase={2}mdb,cn=config - changetype: modify - add: olcSyncrepl - {{- include "olcSyncRepls2ReadOnly" . }} - # TODO - currently this needs to be executed manually e.g. via kubectl exec in each read only replica - # need to see if there is a way to make olcMultiProvider not be propagated from main cluster to readonly replicas. - readonlyremovemirror.ldif: | - dn: olcDatabase={2}mdb,cn=config - changetype: modify - delete: olcMultiProvider - - dn: olcDatabase={0}config,cn=config - changetype: modify - delete: olcMultiProvider - - readonlyrep.ldif: | - dn: olcDatabase={0}config,cn=config - changetype: modify - add: olcSyncRepl - {{- include "olcSyncReplsReadOnly" . }} # acls acls.ldif: | {{- if .Values.customAcls }} From 8567aafda2d73a6508488f85d9fdf117153f5d10 Mon Sep 17 00:00:00 2001 From: jpgouin Date: Fri, 27 Sep 2024 12:26:06 +0000 Subject: [PATCH 18/22] fix ci --- .github/workflows/ci-readonly.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci-readonly.yml b/.github/workflows/ci-readonly.yml index cb46ef3..e2f832d 100644 --- a/.github/workflows/ci-readonly.yml +++ b/.github/workflows/ci-readonly.yml @@ -55,8 +55,5 @@ jobs: - name: test write on readonly replica shell: bash run: | - echo "Ensure readonly replica does not have mirror mode enabled" - kubectl exec openldap-stack-ha-readonly-0 -- bash -c "/opt/bitnami/openldap/bin/ldapmodify -Y EXTERNAL -H ldapi:/// -f /opt/bitnami/openldap/etc/schema/readonlyremovemirror.ldif" - echo "Write test to openldap readonly replica" if LDAPTLS_REQCERT=never ldapadd -x -D 'cn=admin,dc=example,dc=org' -w Not@SecurePassw0rd -H ldaps://localhost:31636 -f .bin/user2.ldif; then echo exit 1; fi From 7bb4a28de2fd595abfa8f144a49033a66ca35527 Mon Sep 17 00:00:00 2001 From: jpgouin Date: Tue, 1 Oct 2024 15:17:48 +0000 Subject: [PATCH 19/22] fix load of schema --- templates/statefulset.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/templates/statefulset.yaml b/templates/statefulset.yaml index 7ba1809..8646d81 100644 --- a/templates/statefulset.yaml +++ b/templates/statefulset.yaml @@ -188,8 +188,6 @@ spec: {{- if .Values.extraEnvVars }} {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} {{- end }} - - name: LDAP_EXTRA_SCHEMAS - value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" .)}} envFrom: {{- if .Values.extraEnvVarsCM }} - configMapRef: @@ -251,13 +249,13 @@ spec: mountPath: /bitnami/openldap/ - name: certs mountPath: /opt/bitnami/openldap/certs - {{- range $file := (include "openldap.builtinSchemaFiles" . | split ",") }} + {{- range $file := (include "openldap.builtinSchemaFiles" (dict "context" . ) | split ",") }} - name: replication-acls mountPath: /opt/bitnami/openldap/etc/schema/{{ $file }}.ldif subPath: {{ $file }}.ldif {{- end }} {{- if .Values.customSchemaFiles}} - {{- range $file := (include "openldap.customSchemaFiles" . | split ",") }} + {{- range $file := (include "openldap.customSchemaFiles" (dict "context" . ) | split ",") }} - name: custom-schema-files mountPath: /opt/bitnami/openldap/etc/schema/{{ $file }}.ldif subPath: {{ $file }}.ldif From cff4c665d04a65241f770fbecb64128ca8359c06 Mon Sep 17 00:00:00 2001 From: jpgouin Date: Wed, 2 Oct 2024 09:28:02 +0000 Subject: [PATCH 20/22] fix mount custom schema --- templates/statefulset-readonly.yaml | 4 ++-- templates/statefulset.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/statefulset-readonly.yaml b/templates/statefulset-readonly.yaml index d161b03..7d30ad8 100644 --- a/templates/statefulset-readonly.yaml +++ b/templates/statefulset-readonly.yaml @@ -63,7 +63,7 @@ spec: {{- end }} volumeMounts: {{- if .Values.customSchemaFiles }} - {{- range $file := (include "openldap.customSchemaFiles" . | split ",") }} + {{- range $file := (include "openldap.customSchemaFiles" (dict "context" . ) | split ",") }} - name: cm-custom-schema-files mountPath: /cm-schemas/{{ $file }}.ldif subPath: {{ $file }}.ldif @@ -246,7 +246,7 @@ spec: mountPath: /opt/bitnami/openldap/etc/schema/readonly.ldif subPath: readonly.ldif {{- if .Values.customSchemaFiles}} - {{- range $file := (include "openldap.customSchemaFiles" . | split ",") }} + {{- range $file := (include "openldap.customSchemaFiles" (dict "context" . ) | split ",") }} - name: custom-schema-files mountPath: /opt/bitnami/openldap/etc/schema/{{ $file }}.ldif subPath: {{ $file }}.ldif diff --git a/templates/statefulset.yaml b/templates/statefulset.yaml index 8646d81..451f276 100644 --- a/templates/statefulset.yaml +++ b/templates/statefulset.yaml @@ -75,7 +75,7 @@ spec: {{- end }} volumeMounts: {{- if .Values.customSchemaFiles }} - {{- range $file := (include "openldap.customSchemaFiles" . | split ",") }} + {{- range $file := (include "openldap.customSchemaFiles" (dict "context" . ) | split ",") }} - name: cm-custom-schema-files mountPath: /cm-schemas/{{ $file }}.ldif subPath: {{ $file }}.ldif From ae47cb49584f523290c444614e8ec124bc02651f Mon Sep 17 00:00:00 2001 From: jpgouin Date: Thu, 3 Oct 2024 12:17:42 +0000 Subject: [PATCH 21/22] allow read only to load custom schema during startup --- templates/_helpers.tpl | 27 ++++----------------------- templates/statefulset-readonly.yaml | 9 +++++---- 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 2aa02f6..935f0d4 100755 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -108,14 +108,13 @@ Generate olcSyncRepl list bindmethod=simple credentials={{ $adminPassword }} searchbase={{ $domain }} - type=refreshOnly + type=refreshAndPersist interval={{ $interval }} network-timeout=0 retry="{{ $retry }} +" timeout={{ $timeout }} starttls={{ $starttls }} tls_reqcert={{ $tls_reqcert }} - exattrs=olcMirrorMode,olcMultiProvider {{- end -}} {{- end -}} @@ -179,7 +178,7 @@ Cannot return list => return string comma separated {{- $mode := index . "mode" -}} {{- if $context.Values.replication.enabled -}} {{- if $mode -}} - {{- $schemas = "brep,readonly,acls" -}} + {{- $schemas = "brep,readonly" -}} {{- else -}} {{- $schemas = "syncprov,serverid,csyncprov,rep,bsyncprov,brep,acls" -}} {{- end -}} @@ -188,15 +187,7 @@ Cannot return list => return string comma separated {{- end -}} {{- print $schemas -}} {{- end -}} -{{- define "openldap.builtinSchemaFilesReadOnly" -}} - {{- $schemas := "" -}} - {{- if .Values.replication.enabled -}} - {{- $schemas = "serverid,readonlybrep,readonlyrep,readonlyremovemirror" -}} - {{- else -}} - {{- $schemas = "" -}} - {{- end -}} - {{- print $schemas -}} -{{- end -}} + {{/* Return the list of custom schema files to use Cannot return list => return string comma separated @@ -223,16 +214,6 @@ Cannot return list => return string comma separated {{- print $schemas -}} {{- end -}} -{{- define "openldap.schemaFilesReadOnly" -}} - {{- $schemas := (include "openldap.builtinSchemaFilesReadOnly" .) -}} - {{- $custom_schemas := (include "openldap.customSchemaFiles" .) -}} - {{- if gt (len $custom_schemas) 0 -}} - {{- $schemas = print $schemas "," $custom_schemas -}} - {{- end -}} - {{- print $schemas -}} -{{- end -}} - - {{/* Return the proper base domain */}} @@ -282,4 +263,4 @@ Return the ldap port */}} {{- define "global.ldapPort" -}} {{- printf "%d" .Values.global.ldapPort -}} -{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/templates/statefulset-readonly.yaml b/templates/statefulset-readonly.yaml index 7d30ad8..6bda71b 100644 --- a/templates/statefulset-readonly.yaml +++ b/templates/statefulset-readonly.yaml @@ -49,7 +49,10 @@ spec: - sh - -c - | - cp -p -f /cm-schemas-acls/brep.ldif /custom_config/ + cp -p -f /cm-schemas-acls/*.ldif /custom_config/ + if [ -d /cm-schemas ]; then + cp -p -f /cm-schemas/*.ldif /custom-schemas/ + fi echo "let the replication takes care of everything :)" {{- if .Values.global.existingSecret }} sed -i -e "s/%%CONFIG_PASSWORD%%/${LDAP_CONFIG_ADMIN_PASSWORD}/g" /custom_config/* @@ -175,9 +178,7 @@ spec: fieldPath: metadata.name {{- if .Values.extraEnvVars }} {{- include "common.tplvalues.render" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }} - {{- end }} - - name: LDAP_EXTRA_SCHEMAS - value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFilesReadOnly" .)}} + {{- end }} envFrom: {{- if .Values.extraEnvVarsCM }} - configMapRef: From 02187ad133b567b53708b86b94709ea32fb76395 Mon Sep 17 00:00:00 2001 From: jpgouin Date: Wed, 9 Oct 2024 07:17:15 +0000 Subject: [PATCH 22/22] resolve conflicts --- templates/_helpers.tpl | 2 +- templates/service-readonly.yaml | 1 + values.yaml | 12 ++++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 935f0d4..e95e3b8 100755 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -69,7 +69,7 @@ Generate olcSyncRepl list {{- define "olcSyncRepls" -}} {{- $name := (include "openldap.fullname" .) }} {{- $namespace := .Release.Namespace }} -{{- $bindDNUser := .Values.global.adminUser }} +{{- $bindDNUser := .Values.global.configUser }} {{- $cluster := .Values.replication.clusterName }} {{- $configPassword := ternary .Values.global.configPassword "%%CONFIG_PASSWORD%%" (empty .Values.global.existingSecret) }} {{- $retry := .Values.replication.retry }} diff --git a/templates/service-readonly.yaml b/templates/service-readonly.yaml index a9a24b8..e695b4f 100644 --- a/templates/service-readonly.yaml +++ b/templates/service-readonly.yaml @@ -18,6 +18,7 @@ metadata: {{- end }} spec: type: {{ .Values.serviceReadOnly.type }} + ipFamilyPolicy: {{ .Values.serviceReadOnly.ipFamilyPolicy }} {{- if and (eq .Values.serviceReadOnly.type "LoadBalancer") .Values.serviceReadOnly.loadBalancerIP }} loadBalancerIP: {{ .Values.serviceReadOnly.loadBalancerIP }} {{- end }} diff --git a/values.yaml b/values.yaml index 5815937..4168418 100644 --- a/values.yaml +++ b/values.yaml @@ -99,6 +99,12 @@ service: type: ClusterIP sessionAffinity: None + ## Represents the dual-stack-ness requested or required by this Service. Possible values are + ## SingleStack, PreferDualStack or RequireDualStack. + ## The ipFamilies and clusterIPs fields depend on the value of this field. + ## Ref: https://kubernetes.io/docs/concepts/services-networking/dual-stack/ + ipFamilyPolicy: SingleStack + # Service for read only cluster pods (if enabled) serviceReadOnly: annotations: {} @@ -126,6 +132,12 @@ serviceReadOnly: type: ClusterIP sessionAffinity: None + ## Represents the dual-stack-ness requested or required by this Service. Possible values are + ## SingleStack, PreferDualStack or RequireDualStack. + ## The ipFamilies and clusterIPs fields depend on the value of this field. + ## Ref: https://kubernetes.io/docs/concepts/services-networking/dual-stack/ + ipFamilyPolicy: SingleStack + # Default configuration for openldap as environment variables. These get injected directly in the container. # Use the env variables from https://hub.docker.com/r/bitnami/openldap/