From 61d6274b3a5f76edbed7c3a7bd2e4c7403d69ab1 Mon Sep 17 00:00:00 2001
From: Valery Kharseko <vharseko@3a-systems.ru>
Date: Mon, 28 Sep 2026 16:25:00 +0000
Subject: [PATCH] [#1087] Copy the secret volume on every start of the Docker image (#1100)

---
 opendj-packages/opendj-docker/run.sh            |   87 ++++++++++++--
 opendj-packages/opendj-docker/Dockerfile-alpine |    3 
 opendj-packages/opendj-docker/README.md         |   73 ++++++++++++
 .github/workflows/build.yml                     |  168 ++++++++++++++++++++++++++++
 opendj-packages/opendj-docker/Dockerfile        |    3 
 5 files changed, 316 insertions(+), 18 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ea69ca8..327a02a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -648,6 +648,90 @@
           done
           docker exec test_replica test -e /dev/shm/opendj-replicate.5444.other || { echo "::error::run.sh of test_replica removed the password file of another container"; false; }
           cleanup
+      - name: Docker test secret volume
+        # a keystore mounted at SECRET_VOLUME is what LDAPS serves from the first start on, a
+        # renewed one - a new password included - is copied while the server runs and served
+        # without a restart, and the server is PID 1 of the container, stopping on SIGTERM
+        # (#1087, #1085); a start copies what was renewed while no container ran, over the
+        # instance already there, and SECRET_VOLUME_REFRESH=0 runs no watcher
+        shell: bash
+        env:
+          IMAGE: localhost:5000/${{ env.image_repository }}:${{ env.release_version }}
+        run: |
+          set -E
+          trap 'code=$?; echo "::group::container logs (test_secret)"; docker logs test_secret 2>&1 || true; echo "::endgroup::"; exit $code' ERR
+          SECRETS=$(mktemp -d)
+          chmod 777 "$SECRETS"
+          # a key under an alias other than setup's own, since setup binds no connection handler
+          # to an alias, and a truststore holding its certificate; the alias is kept by a
+          # renewal the server is to load while it runs, which takes a keystore only when it
+          # holds a key under an alias the one before it did
+          keystore() {
+            local pass=${2:-changeit} alias=${3:-$1}
+            docker run --rm --entrypoint keytool -v "$SECRETS":/secrets "$IMAGE" -genkeypair -alias "$alias" \
+              -keyalg RSA -keysize 2048 -validity 30 -dname "CN=$1" -storetype PKCS12 \
+              -keystore /secrets/keystore.new -storepass "$pass" -keypass "$pass"
+            docker run --rm --entrypoint keytool -v "$SECRETS":/secrets "$IMAGE" -exportcert -rfc -alias "$alias" \
+              -keystore /secrets/keystore.new -storepass "$pass" -file /secrets/cert.pem
+            rm -f "$SECRETS/truststore.new"
+            docker run --rm --entrypoint keytool -v "$SECRETS":/secrets "$IMAGE" -importcert -noprompt -alias "$1" \
+              -file /secrets/cert.pem -keystore /secrets/truststore.new -storetype JKS -storepass changeit
+            rm -f "$SECRETS/cert.pem"
+            printf %s "$pass" > "$SECRETS/keystore.pin"
+            printf changeit > "$SECRETS/truststore.pin"
+            mv -f "$SECRETS/truststore.new" "$SECRETS/truststore"
+            mv -f "$SECRETS/keystore.new" "$SECRETS/keystore"
+          }
+          served() { echo | openssl s_client -connect 127.0.0.1:1637 2>/dev/null | openssl x509 -noout -subject -nameopt RFC2253; }
+          healthy() { timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test_secret | grep -q \"healthy\"; do sleep 10; done'; }
+          copies() { docker logs test_secret 2>&1 | grep -c "^Copied $1 from the secret volume$" || true; }
+          keystore secret-v1
+          docker run -d --memory="512m" -e SECRET_VOLUME_REFRESH=5 -p 127.0.0.1:1637:1636 --name=test_secret \
+            -v "$SECRETS":/var/secrets/opendj:ro -v test_secret_data:/opt/opendj/data "$IMAGE"
+          healthy
+          grep -q "CN=secret-v1" <<< "$(served)"
+          test "$(docker exec test_secret cat /proc/1/comm)" = java
+          test "$(docker exec test_secret stat -c %a /opt/opendj/data/config/keystore.pin)" = 600
+          docker exec test_secret cmp -s /var/secrets/opendj/truststore /opt/opendj/data/config/truststore
+          # the bootstrap's server is stopped before the instance is marked bootstrapped
+          test "$(docker logs test_secret 2>&1 | grep -e '^Stopping Server' -e '^The instance is bootstrapped' | paste -sd '|' -)" \
+            = "Stopping Server...|The instance is bootstrapped, the health check may probe it"
+          keystore secret-v2 changeit secret-v1
+          timeout 1m bash -c 'until docker exec test_secret cmp -s /var/secrets/opendj/keystore /opt/opendj/data/config/keystore; do sleep 5; done'
+          # the server loads the keystore the watcher copied on the next handshake
+          grep -q "CN=secret-v2" <<< "$(served)"
+          # the watcher has looked at the volume every 5 s since the start, and copied the
+          # keystore only when it changed: on the start and once more for v2
+          sleep 6
+          test "$(copies keystore)" = 2
+          # a new password is copied along with its keystore, and the server loads both
+          keystore secret-v3 changeit2 secret-v1
+          timeout 1m bash -c 'until docker exec test_secret sh -c "cmp -s /var/secrets/opendj/keystore /opt/opendj/data/config/keystore && cmp -s /var/secrets/opendj/keystore.pin /opt/opendj/data/config/keystore.pin"; do sleep 5; done'
+          grep -q "CN=secret-v3" <<< "$(served)"
+          test "$(copies keystore.pin)" = 2
+          start=$SECONDS
+          docker stop -t 60 test_secret
+          test $((SECONDS - start)) -lt 30
+          test "$(docker inspect --format='{{.State.ExitCode}}' test_secret)" = 143
+          docker start test_secret
+          healthy
+          grep -q "CN=secret-v3" <<< "$(served)"
+          docker stop -t 60 test_secret
+          docker rm test_secret
+          # renewed while no container runs, the keystore, its new password and its new alias
+          # are copied by the start, over the instance already there
+          keystore secret-v4 changeit3
+          docker run -d --memory="512m" -e SECRET_VOLUME_REFRESH=0 -p 127.0.0.1:1637:1636 --name=test_secret \
+            -v "$SECRETS":/var/secrets/opendj:ro -v test_secret_data:/opt/opendj/data "$IMAGE"
+          healthy
+          grep -q "CN=secret-v4" <<< "$(served)"
+          # no watcher, whose sleep is nearly always there, and nothing copied while the server runs
+          docker exec test_secret sh -c '! grep -sqx sleep /proc/[0-9]*/comm'
+          keystore secret-v5 changeit3
+          sleep 15
+          docker exec test_secret sh -c '! cmp -s /var/secrets/opendj/keystore /opt/opendj/data/config/keystore'
+          docker rm -f test_secret
+          docker volume rm test_secret_data
       - name: Docker test bootstrap LDIFs
         shell: bash
         run: |
@@ -1010,6 +1094,90 @@
           done
           docker exec test_replica test -e /dev/shm/opendj-replicate.5444.other || { echo "::error::run.sh of test_replica removed the password file of another container"; false; }
           cleanup
+      - name: Docker test secret volume
+        # a keystore mounted at SECRET_VOLUME is what LDAPS serves from the first start on, a
+        # renewed one - a new password included - is copied while the server runs and served
+        # without a restart, and the server is PID 1 of the container, stopping on SIGTERM
+        # (#1087, #1085); a start copies what was renewed while no container ran, over the
+        # instance already there, and SECRET_VOLUME_REFRESH=0 runs no watcher
+        shell: bash
+        env:
+          IMAGE: localhost:5000/${{ env.image_repository }}:${{ env.release_version }}-alpine
+        run: |
+          set -E
+          trap 'code=$?; echo "::group::container logs (test_secret)"; docker logs test_secret 2>&1 || true; echo "::endgroup::"; exit $code' ERR
+          SECRETS=$(mktemp -d)
+          chmod 777 "$SECRETS"
+          # a key under an alias other than setup's own, since setup binds no connection handler
+          # to an alias, and a truststore holding its certificate; the alias is kept by a
+          # renewal the server is to load while it runs, which takes a keystore only when it
+          # holds a key under an alias the one before it did
+          keystore() {
+            local pass=${2:-changeit} alias=${3:-$1}
+            docker run --rm --entrypoint keytool -v "$SECRETS":/secrets "$IMAGE" -genkeypair -alias "$alias" \
+              -keyalg RSA -keysize 2048 -validity 30 -dname "CN=$1" -storetype PKCS12 \
+              -keystore /secrets/keystore.new -storepass "$pass" -keypass "$pass"
+            docker run --rm --entrypoint keytool -v "$SECRETS":/secrets "$IMAGE" -exportcert -rfc -alias "$alias" \
+              -keystore /secrets/keystore.new -storepass "$pass" -file /secrets/cert.pem
+            rm -f "$SECRETS/truststore.new"
+            docker run --rm --entrypoint keytool -v "$SECRETS":/secrets "$IMAGE" -importcert -noprompt -alias "$1" \
+              -file /secrets/cert.pem -keystore /secrets/truststore.new -storetype JKS -storepass changeit
+            rm -f "$SECRETS/cert.pem"
+            printf %s "$pass" > "$SECRETS/keystore.pin"
+            printf changeit > "$SECRETS/truststore.pin"
+            mv -f "$SECRETS/truststore.new" "$SECRETS/truststore"
+            mv -f "$SECRETS/keystore.new" "$SECRETS/keystore"
+          }
+          served() { echo | openssl s_client -connect 127.0.0.1:1637 2>/dev/null | openssl x509 -noout -subject -nameopt RFC2253; }
+          healthy() { timeout 3m bash -c 'until docker inspect --format="{{json .State.Health.Status}}" test_secret | grep -q \"healthy\"; do sleep 10; done'; }
+          copies() { docker logs test_secret 2>&1 | grep -c "^Copied $1 from the secret volume$" || true; }
+          keystore secret-v1
+          docker run -d --memory="1g" -e SECRET_VOLUME_REFRESH=5 -p 127.0.0.1:1637:1636 --name=test_secret \
+            -v "$SECRETS":/var/secrets/opendj:ro -v test_secret_data:/opt/opendj/data "$IMAGE"
+          healthy
+          grep -q "CN=secret-v1" <<< "$(served)"
+          test "$(docker exec test_secret cat /proc/1/comm)" = java
+          test "$(docker exec test_secret stat -c %a /opt/opendj/data/config/keystore.pin)" = 600
+          docker exec test_secret cmp -s /var/secrets/opendj/truststore /opt/opendj/data/config/truststore
+          # the bootstrap's server is stopped before the instance is marked bootstrapped
+          test "$(docker logs test_secret 2>&1 | grep -e '^Stopping Server' -e '^The instance is bootstrapped' | paste -sd '|' -)" \
+            = "Stopping Server...|The instance is bootstrapped, the health check may probe it"
+          keystore secret-v2 changeit secret-v1
+          timeout 1m bash -c 'until docker exec test_secret cmp -s /var/secrets/opendj/keystore /opt/opendj/data/config/keystore; do sleep 5; done'
+          # the server loads the keystore the watcher copied on the next handshake
+          grep -q "CN=secret-v2" <<< "$(served)"
+          # the watcher has looked at the volume every 5 s since the start, and copied the
+          # keystore only when it changed: on the start and once more for v2
+          sleep 6
+          test "$(copies keystore)" = 2
+          # a new password is copied along with its keystore, and the server loads both
+          keystore secret-v3 changeit2 secret-v1
+          timeout 1m bash -c 'until docker exec test_secret sh -c "cmp -s /var/secrets/opendj/keystore /opt/opendj/data/config/keystore && cmp -s /var/secrets/opendj/keystore.pin /opt/opendj/data/config/keystore.pin"; do sleep 5; done'
+          grep -q "CN=secret-v3" <<< "$(served)"
+          test "$(copies keystore.pin)" = 2
+          start=$SECONDS
+          docker stop -t 60 test_secret
+          test $((SECONDS - start)) -lt 30
+          test "$(docker inspect --format='{{.State.ExitCode}}' test_secret)" = 143
+          docker start test_secret
+          healthy
+          grep -q "CN=secret-v3" <<< "$(served)"
+          docker stop -t 60 test_secret
+          docker rm test_secret
+          # renewed while no container runs, the keystore, its new password and its new alias
+          # are copied by the start, over the instance already there
+          keystore secret-v4 changeit3
+          docker run -d --memory="1g" -e SECRET_VOLUME_REFRESH=0 -p 127.0.0.1:1637:1636 --name=test_secret \
+            -v "$SECRETS":/var/secrets/opendj:ro -v test_secret_data:/opt/opendj/data "$IMAGE"
+          healthy
+          grep -q "CN=secret-v4" <<< "$(served)"
+          # no watcher, whose sleep is nearly always there, and nothing copied while the server runs
+          docker exec test_secret sh -c '! grep -sqx sleep /proc/[0-9]*/comm'
+          keystore secret-v5 changeit3
+          sleep 15
+          docker exec test_secret sh -c '! cmp -s /var/secrets/opendj/keystore /opt/opendj/data/config/keystore'
+          docker rm -f test_secret
+          docker volume rm test_secret_data
       - name: Docker test bootstrap LDIFs
         shell: bash
         run: |
diff --git a/opendj-packages/opendj-docker/Dockerfile b/opendj-packages/opendj-docker/Dockerfile
index 16b141f..3ffaac8 100644
--- a/opendj-packages/opendj-docker/Dockerfile
+++ b/opendj-packages/opendj-docker/Dockerfile
@@ -24,7 +24,8 @@
 ENV ROOT_USER_DN="cn=Directory Manager"
 # ROOT_PASSWORD should be passed at runtime via: docker run -e ROOT_PASSWORD=...
 # Default value if not provided: "password"
-#ENV SECRET_VOLUME
+#ENV SECRET_VOLUME="/var/secrets/opendj"
+#ENV SECRET_VOLUME_REFRESH=60
 ENV OPENDJ_SSL_OPTIONS="--generateSelfSignedCertificate"
 #ENV MASTER_SERVER
 #ENV OPENDJ_REPLICATION_TYPE
diff --git a/opendj-packages/opendj-docker/Dockerfile-alpine b/opendj-packages/opendj-docker/Dockerfile-alpine
index b4b8a03..55658cb 100644
--- a/opendj-packages/opendj-docker/Dockerfile-alpine
+++ b/opendj-packages/opendj-docker/Dockerfile-alpine
@@ -24,7 +24,8 @@
 ENV ROOT_USER_DN="cn=Directory Manager"
 # ROOT_PASSWORD should be passed at runtime via: docker run -e ROOT_PASSWORD=...
 # Default value if not provided: "password"
-#ENV SECRET_VOLUME
+#ENV SECRET_VOLUME="/var/secrets/opendj"
+#ENV SECRET_VOLUME_REFRESH=60
 ENV OPENDJ_SSL_OPTIONS="--generateSelfSignedCertificate"
 #ENV MASTER_SERVER
 #ENV OPENDJ_REPLICATION_TYPE
diff --git a/opendj-packages/opendj-docker/README.md b/opendj-packages/opendj-docker/README.md
index cf5a290..dcc0f25 100644
--- a/opendj-packages/opendj-docker/README.md
+++ b/opendj-packages/opendj-docker/README.md
@@ -67,6 +67,76 @@
 logs`, and where the server is up at all the container is left running to be looked at,
 turning `unhealthy` once the start period is over.
 
+The server runs as PID 1 of the container, and a JVM does not reap the processes left
+behind to it - those of a health check that ran past its timeout, say. Run the container
+with `docker run --init` (`init: true` in Compose) to put a PID 1 in front of the server
+that reaps them and passes SIGTERM on to it.
+
+## Certificates
+
+With the default `OPENDJ_SSL_OPTIONS` the instance serves LDAPS and StartTLS with a
+self-signed certificate from `config/keystore`, whose password is in `config/keystore.pin`.
+To serve your own certificate, mount a directory holding a `keystore` (JKS or PKCS12) and
+its `keystore.pin` at `SECRET_VOLUME`, and a `truststore` next to them if clients present
+certificates. With `--generateSelfSignedCertificate` setup binds the connection handlers to
+no alias, even when a `--certNickname` is given as well, so the key entry of the keystore
+may have any alias. Only when `OPENDJ_SSL_OPTIONS` sets up a keystore of its own
+(`--useJavaKeystore`, `--usePkcs12keyStore`) with a `--certNickname` does the key have to be
+under that alias:
+
+```bash
+docker run -d --name opendj -v opendj-data:/opt/opendj/data \
+  -v "$PWD/secrets":/var/secrets/opendj:ro openidentityplatform/opendj
+```
+
+Every `key*` and `trust*` file of that directory is copied into `/opt/opendj/data/config`
+before the server starts - on the first start and on every later one, so a certificate
+renewed on the volume reaches an instance kept on a persistent volume. While the server
+runs, the directory is checked again every `SECRET_VOLUME_REFRESH` seconds and a changed
+file is copied again. The server loads a copied keystore or truststore on the next TLS
+handshake, so a renewed certificate is served without a restart, a new password in
+`keystore.pin` or `truststore.pin` included; connections already open keep the certificate
+they were set up with. While it runs, the server takes a renewed keystore only if it holds
+its key under an alias the previous one used as well - cert-manager keeps the alias from
+one renewal to the next. A keystore with only new aliases is served from the next restart,
+and until then the server logs that it could not load it. So does a keystore caught by a
+handshake between its copy and that of its `.pin` file, until the second file is copied as
+well. The administration connector and replication keep keys of their own and are not
+affected.
+
+On Kubernetes, the PEM files of a `kubernetes.io/tls` Secret cannot be used as they are:
+OpenDJ reads keystores, not PEM. cert-manager can add a PKCS12 keystore to the Secret it
+issues, and a projected volume mounts it under the names above:
+
+```yaml
+# the Certificate
+spec:
+  secretName: opendj-tls
+  keystores:
+    pkcs12:
+      create: true
+      passwordSecretRef: { name: opendj-keystore-password, key: password }
+---
+# the pod template of the StatefulSet
+volumes:
+  - name: secrets
+    projected:
+      sources:
+        - secret:
+            name: opendj-tls
+            items: [{ key: keystore.p12, path: keystore }]
+        - secret:
+            name: opendj-keystore-password
+            items: [{ key: password, path: keystore.pin }]
+containers:
+  - name: opendj
+    volumeMounts:
+      - { name: secrets, mountPath: /var/secrets/opendj, readOnly: true }
+```
+
+Mount the volume as a whole, not with `subPath`: Kubernetes does not update files mounted
+with `subPath` when the Secret changes.
+
 ## Environment Variables
 
 | Variable                | Default Value                   | Description                                                                                                                                                                                                                                             |
@@ -78,7 +148,8 @@
 | BASE_DN                 | dc=example,dc=com               | OpenDJ Base DN                                                                                                                                                                                                                                          |
 | ROOT_USER_DN            | cn=Directory Manager            | Initial root user DN                                                                                                                                                                                                                                    |
 | ROOT_PASSWORD           | password                        | Initial root user password; the bootstrap fails if it contains a line break (CR or LF)                                                                                                                                                                  |
-| SECRET_VOLUME           | -                               | Mounted keystore volume, if present copies keystore over                                                                                                                                                                                                |
+| SECRET_VOLUME           | /var/secrets/opendj             | Mounted keystore volume, if present its `key*` and `trust*` files are copied into the instance on every start, see [Certificates](#certificates)                                                                                                        |
+| SECRET_VOLUME_REFRESH   | 60                              | While the server runs, `SECRET_VOLUME` is checked again every that many seconds and changed files are copied again; `0` copies them on start only                                                                                                       |
 | MASTER_SERVER           | -                               | Replication master server                                                                                                                                                                                                                               |
 | VERSION                 | -                               | OpenDJ version                                                                                                                                                                                                                                          |
 | OPENDJ_USER             | opendj                          | user which runs OpenDJ                                                                                                                                                                                                                                  |
diff --git a/opendj-packages/opendj-docker/run.sh b/opendj-packages/opendj-docker/run.sh
index 08a1bf7..d7f1943 100755
--- a/opendj-packages/opendj-docker/run.sh
+++ b/opendj-packages/opendj-docker/run.sh
@@ -45,6 +45,72 @@
 rm -f /dev/shm/opendj-replicate."$ADMIN_PORT".*
 rm -f /dev/shm/opendj-setup-password."$ADMIN_PORT".* /tmp/opendj-setup-password.*
 
+# Keystores and truststores mounted as a volume (a Kubernetes Secret, say) are copied into
+# the instance on every start, not only on the one that bootstraps it: the instance lives on
+# a persistent volume, and a renewed certificate in the Secret has to reach it.
+SECRET_VOLUME=${SECRET_VOLUME:-/var/secrets/opendj}
+# Kubernetes updates a mounted Secret in place, so while the server runs the volume is
+# checked again every that many seconds; 0 checks it on start only
+SECRET_VOLUME_REFRESH=${SECRET_VOLUME_REFRESH:-60}
+
+# Copies the key* and trust* files of the secret volume that differ from those in
+# ./data/config. Each one is written next to its target and renamed over it, so the server
+# never reads a file half copied, and it is readable by the server's user only: a keystore
+# holds the private key, a .pin file its password. Succeeds when it copied a file.
+copy_secrets() {
+  local src dst tmp copied=1
+  [ -d "$SECRET_VOLUME" ] || return 1
+  for src in "$SECRET_VOLUME"/key* "$SECRET_VOLUME"/trust*; do
+    [ -f "$src" ] || continue
+    dst=./data/config/$(basename -- "$src")
+    cmp -s "$src" "$dst" && continue
+    if tmp=$(mktemp "$dst.XXXXXX") && cp "$src" "$tmp" && chmod 600 "$tmp" && mv -f "$tmp" "$dst"; then
+      echo "Copied $(basename -- "$src") from the secret volume"
+      copied=0
+    else
+      rm -f "$tmp"
+      echo "Could not copy $(basename -- "$src") from the secret volume"
+    fi
+  done
+  return $copied
+}
+
+# The files are compared one at a time, so a Secret updated in the middle of a pass can leave
+# a keystore of one version next to the .pin of the other. Passes are repeated until one finds
+# nothing left to copy, which puts the files of a single version back together.
+sync_secrets() {
+  local passes=0
+  while copy_secrets && [ $((passes += 1)) -lt 5 ]; do :; done
+}
+
+# The server loads a keystore or truststore again, together with its .pin file, on the first
+# handshake after either file has changed (#1095), so a store copied while the server runs is
+# served without a restart, a new password included - a keystore as long as it keeps an alias of
+# the one before it, else from the next start. A handshake that comes between the copy of a store
+# and that of its .pin finds a pair it cannot open: the server keeps the store it loaded last,
+# logs that it could not load the new one, and loads it once the second file is copied.
+watch_secrets() {
+  while sleep "$SECRET_VOLUME_REFRESH"; do
+    sync_secrets
+  done
+}
+
+# Both kinds of start end here, with the server as PID 1 of the container: that is the
+# process the container runtime sends SIGTERM to, and the server stops cleanly on it.
+start_server() {
+  if [ -d "$SECRET_VOLUME" ]; then
+    echo "Secret volume is present. Will copy any keystores and truststore"
+    sync_secrets
+    if [[ $SECRET_VOLUME_REFRESH =~ ^[0-9]+$ ]] && [ "$SECRET_VOLUME_REFRESH" -gt 0 ]; then
+      watch_secrets &
+    elif ! [[ $SECRET_VOLUME_REFRESH =~ ^0+$ ]]; then
+      echo "SECRET_VOLUME_REFRESH=$SECRET_VOLUME_REFRESH is not a whole number of seconds above 0, the secret volume is copied on start only"
+    fi
+  fi
+  echo "Starting OpenDJ"
+  exec ./bin/start-ds --nodetach
+}
+
 #if default data folder exists do not change it
 if [ ! -d ./db ]; then
   echo "/opt/opendj/data" >/opt/opendj/instance.loc && \
@@ -60,8 +126,7 @@
   else
     echo "Upgrade failed, this container will not report itself healthy"
   fi
-  exec ./bin/start-ds --nodetach
-  exit
+  start_server
 fi
 
 # If we are here, opendj is not installed & we need to run setup
@@ -92,7 +157,9 @@
 # started again below with exec, so that the server is PID 1 on the first start just as
 # on a restart: a shell as PID 1 without a SIGTERM handler never receives the signal, and
 # the container would then be killed at the end of the stop timeout instead of stopping
-# the server. It is stopped before the marker below is written, so that the health check
+# the server. Left running, it would also keep the certificate it was set up with rather
+# than the one on the secret volume, which start_server copies in before it starts the
+# server. It is stopped before the marker below is written, so that the health check
 # never reports the server of the bootstrap healthy just before it goes down. stop-ds
 # exits 0 when the server is not running. When it fails the server may still be stopping,
 # so the start below is tried anyway: it either runs the server or fails on the lock of
@@ -102,21 +169,11 @@
   echo "Could not stop the server started by the bootstrap, starting OpenDJ may fail"
 fi
 
-# Check if keystores are mounted as a volume, and if so
-# Copy any keystores over
-SECRET_VOLUME=${SECRET_VOLUME:-/var/secrets/opendj}
-
-if [ -d "${SECRET_VOLUME}" ]; then
-  echo "Secret volume is present. Will copy any keystores and truststore"
-  # We send errors to /dev/null in case no data exists.
-  cp -f ${SECRET_VOLUME}/key* ${SECRET_VOLUME}/trust* ./data/config 2>/dev/null
-fi
-
 # Everything the instance was asked to be set up with - its backend, its base entry, its
 # replication - is in place from here on, so the health check may start probing the server
 if [ "$BOOTSTRAPPED" = true ]; then
   touch "$BOOTSTRAP_COMPLETE"
+  echo "The instance is bootstrapped, the health check may probe it"
 fi
 
-echo "Starting OpenDJ"
-exec ./bin/start-ds --nodetach
+start_server

--
Gitblit v1.10.0