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 diff --git a/.bin/readonly.yaml b/.bin/readonly.yaml new file mode 100644 index 0000000..7b5eada --- /dev/null +++ b/.bin/readonly.yaml @@ -0,0 +1,113 @@ +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 + 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/.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 new file mode 100644 index 0000000..e2f832d --- /dev/null +++ b/.github/workflows/ci-readonly.yml @@ -0,0 +1,59 @@ +# 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 + shell: bash + run: | + 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 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 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 d3e5d88..e95e3b8 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" -}} + {{- 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" .) -}} @@ -254,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/configmap-env.yaml b/templates/configmap-env.yaml index 9a8d3e4..f3528a9 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/configmap-readonly.yaml b/templates/configmap-readonly.yaml new file mode 100644 index 0000000..454332f --- /dev/null +++ b/templates/configmap-readonly.yaml @@ -0,0 +1,20 @@ +{{- 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: + readonly.ldif: | + dn: olcDatabase={2}mdb,cn=config + changetype: modify + replace: olcReadOnly + 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..e695b4f --- /dev/null +++ b/templates/service-readonly.yaml @@ -0,0 +1,58 @@ +{{- if (gt (.Values.readOnlyReplicaCount | int) 0) }} +apiVersion: v1 +kind: Service +metadata: +{{- if .Values.serviceReadOnly.annotations }} + annotations: +{{ toYaml .Values.serviceReadOnly.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.serviceReadOnly.type }} + ipFamilyPolicy: {{ .Values.serviceReadOnly.ipFamilyPolicy }} + {{- if and (eq .Values.serviceReadOnly.type "LoadBalancer") .Values.serviceReadOnly.loadBalancerIP }} + loadBalancerIP: {{ .Values.serviceReadOnly.loadBalancerIP }} + {{- end }} + {{- if and (eq .Values.serviceReadOnly.type "LoadBalancer") .Values.serviceReadOnly.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{ toYaml .Values.serviceReadOnly.loadBalancerSourceRanges | nindent 4 }} + {{- end }} + {{- if and (eq .Values.serviceReadOnly.type "ClusterIP") .Values.serviceReadOnly.clusterIP }} + clusterIP: {{ .Values.serviceReadOnly.clusterIP }} + {{- end }} + ports: + {{- if .Values.serviceReadOnly.enableLdapPort }} + - name: ldap-port + protocol: TCP + port: {{ .Values.global.ldapPort }} + targetPort: ldap-port + {{- 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.serviceReadOnly.enableSslLdapPort }} + - name: ssl-ldap-port + protocol: TCP + port: {{ .Values.global.sslLdapPort }} + targetPort: ssl-ldap-port + {{- 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 }} + 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..6bda71b --- /dev/null +++ b/templates/statefulset-readonly.yaml @@ -0,0 +1,362 @@ +{{- 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 + - | + 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/* + 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" (dict "context" . ) | 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: LDAP_EXTRA_SCHEMAS + value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" (dict "context" . "mode" "readonly")) }} + - 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 + {{- 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 + - name: replication-acls + 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" (dict "context" . ) | split ",") }} + - name: custom-schema-files + mountPath: /opt/bitnami/openldap/etc/schema/{{ $file }}.ldif + subPath: {{ $file }}.ldif + {{- end }} +{{- end }} +{{- 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/statefulset.yaml b/templates/statefulset.yaml index 8a8464c..891780f 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 @@ -183,6 +183,8 @@ spec: securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} {{- end }} env: + - name: LDAP_EXTRA_SCHEMAS + value: {{ print "cosine,inetorgperson,nis," (include "openldap.schemaFiles" (dict "context" . )) }} - name: POD_NAME valueFrom: fieldRef: @@ -256,13 +258,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 diff --git a/templates/svc-headless-readonly.yaml b/templates/svc-headless-readonly.yaml new file mode 100644 index 0000000..f240a77 --- /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.serviceReadOnly.headlessEnableLdapPort }} + - port: {{ .Values.global.ldapPort }} + name: ldap-port + targetPort: ldap-port + {{- end }} + {{- if .Values.serviceReadOnly.headlessEnableSslLdapPort }} + - 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 2a1c85d..312bdf4 100644 --- a/values.yaml +++ b/values.yaml @@ -51,6 +51,9 @@ extraDeploy: [] replicaCount: 3 +# Note: you need replication enabled to use readonly replicas! +readOnlyReplicaCount: 0 + image: # From repository https://hub.docker.com/r/bitnami/openldap/ #repository: bitnami/openldap @@ -102,6 +105,39 @@ service: ## Ref: https://kubernetes.io/docs/concepts/services-networking/dual-stack/ ipFamilyPolicy: SingleStack +# 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 + + # 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 + ## + externalIPs: [] + + ## Define a static clusterIP + #clusterIP: + #loadBalancerIP: + #loadBalancerSourceRanges: [] + 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/ # Be careful, do not modify the following values unless you know exactly what your are doing