Skip to content

Commit 492d7aa

Browse files
Fix healthcheck for self-signed certs
1 parent f4a17bf commit 492d7aa

7 files changed

Lines changed: 95 additions & 2 deletions

File tree

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
charts/*/charts/
55
charts/*/*.tgz
66
charts/*/Chart.lock
7-
test.yaml
7+
test.yaml
8+
9+
.env

charts/ontoserver/README.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,31 @@ The readiness probe calls `/healthcheck.sh` with the flag set in `ontoserver.hea
280280

281281
**`-f` (default)** prevents traffic reaching a pod whose startup preload has definitively failed, without blocking readiness while a preload is still in progress. Use **`-s`** if you want the pod held out of rotation until its startup preload has finished successfully — useful when serving requests against a partially-loaded terminology is undesirable.
282282

283+
### Healthcheck and HTTPS mode (`ONTOSERVER_INSECURE: "false"`)
284+
285+
All three probes (startup, liveness, readiness) call `/healthcheck.sh` inside the container. On first run, the script checks the Spring Boot actuator health endpoint (`http://localhost:18080`) and, if Ontoserver has not yet been initialised (`initialized: false`), triggers initialization by calling the FHIR metadata endpoint on the main server port.
286+
287+
When `ONTOSERVER_INSECURE: "false"`, the main server port is HTTPS on 8443. The script constructs the URL as `https://localhost:8443/fhir/metadata` and fetches it with `wget` — but `wget` inside the container rejects the bundled self-signed certificate, causing the initialization call to fail and the probe to exit non-zero. The pod then restarts in a loop and never becomes healthy.
288+
289+
The workaround is a `postStart` lifecycle hook that patches the `wget` call inside the script to add `--no-check-certificate` before any probe fires. The hook runs before `startupProbe.initialDelaySeconds` elapses, so the patched script is in place when Kubernetes issues the first probe:
290+
291+
```yaml
292+
ontoserver:
293+
deployment:
294+
containerPort: 8443
295+
lifecycle:
296+
postStart:
297+
exec:
298+
command:
299+
- /bin/sh
300+
- -c
301+
- sed -i 's|wget -o /dev/null -q -O /dev/null|wget --no-check-certificate -o /dev/null -q -O /dev/null|' /healthcheck.sh
302+
config:
303+
ONTOSERVER_INSECURE: "false"
304+
```
305+
306+
This is exactly the configuration used by the `traefik-https-backend` integration test fixture.
307+
283308
## Amazon EKS
284309

285310
The chart works on EKS with the following configuration differences from the defaults (which are AKS/Azure-oriented).
@@ -492,6 +517,7 @@ The ArgoCD examples use multi-source Applications with both the `ontoserver` and
492517
| `ontoserver.deployment.image` | Container image for OntoServer | `quay.io/aehrc/ontoserver:ctsa-6` |
493518
| `ontoserver.deployment.imagePullPolicy` | Image pull policy | `IfNotPresent` |
494519
| `ontoserver.deployment.containerPort` | Container port Ontoserver listens on. Use 8080 for HTTP (ONTOSERVER_INSECURE=true) or 8443 for HTTPS (ONTOSERVER_INSECURE=false). | `8080` |
520+
| `ontoserver.deployment.lifecycle` | Container lifecycle hooks (postStart / preStop). Passed through as-is to the container spec. | `{}` |
495521
| `ontoserver.deployment.imagePullSecrets` | Additional pre-created image pull secrets to attach to the pod (merged with the chart-managed pull secret when imageCredentials are set) | `[]` |
496522
| `ontoserver.deployment.isReadOnly` | Ontoserver in read‑only mode - keep it true for scaled | `true` |
497523
| `ontoserver.deployment.replicas` | Number of replicas - min 2 for scaled deployment - can be set to 0 | `1` |
@@ -845,12 +871,21 @@ For HTTP backends with Traefik, the standard `ontoserver.ingress` is sufficient.
845871

846872
By default (`ONTOSERVER_INSECURE: "true"`) Ontoserver serves plain HTTP on port 8080. Setting `ONTOSERVER_INSECURE: "false"` restores Ontoserver's out-of-box behaviour: HTTPS on port **8443** using its bundled self-signed keystore. You must also set `ontoserver.deployment.containerPort: 8443` so the Kubernetes Service routes traffic to the correct container port.
847873

848-
The client-to-Traefik leg remains plain HTTP via the `web` entrypoint; TLS is only on the Traefik-to-Ontoserver backend leg:
874+
The client-to-Traefik leg remains plain HTTP via the `web` entrypoint; TLS is only on the Traefik-to-Ontoserver backend leg.
875+
876+
> **Important — probe patch required:** When `ONTOSERVER_INSECURE: "false"`, the container's `/healthcheck.sh` uses `wget` to trigger FHIR initialization via `https://localhost:8443`. Because the certificate is self-signed, `wget` rejects it and the startup probe fails permanently. A `postStart` lifecycle hook is required to patch the script before the first probe fires. See [Healthcheck and HTTPS mode](#healthcheck-and-https-mode-ontoserver_insecure-false) for the full explanation.
849877

850878
```yaml
851879
ontoserver:
852880
deployment:
853881
containerPort: 8443 # Ontoserver's HTTPS port
882+
lifecycle:
883+
postStart:
884+
exec:
885+
command:
886+
- /bin/sh
887+
- -c
888+
- sed -i 's|wget -o /dev/null -q -O /dev/null|wget --no-check-certificate -o /dev/null -q -O /dev/null|' /healthcheck.sh
854889
config:
855890
ONTOSERVER_INSECURE: "false"
856891

charts/ontoserver/templates/deployment.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ spec:
125125
limits:
126126
cpu: {{ required "ontoserver.resources.ontoserver.limits.cpu is required" .Values.ontoserver.resources.ontoserver.limits.cpu }}
127127
memory: {{ required "ontoserver.resources.ontoserver.limits.memory is required" .Values.ontoserver.resources.ontoserver.limits.memory }}
128+
{{- with .Values.ontoserver.deployment.lifecycle }}
129+
lifecycle:
130+
{{- toYaml . | nindent 12 }}
131+
{{- end }}
128132
startupProbe:
129133
exec:
130134
command:

charts/ontoserver/templates/statefulset.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ spec:
122122
limits:
123123
cpu: {{ required "ontoserver.resources.ontoserver.limits.cpu is required" .Values.ontoserver.resources.ontoserver.limits.cpu }}
124124
memory: {{ required "ontoserver.resources.ontoserver.limits.memory is required" .Values.ontoserver.resources.ontoserver.limits.memory }}
125+
{{- with .Values.ontoserver.deployment.lifecycle }}
126+
lifecycle:
127+
{{- toYaml . | nindent 12 }}
128+
{{- end }}
125129
startupProbe:
126130
exec:
127131
command:

charts/ontoserver/tests/fixtures/traefik-https-backend-values.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ ontoserver:
1111
serverName: ontoserver.traefik-test.local
1212
deployment:
1313
containerPort: 8443
14+
# healthcheck.sh uses plain `wget` which rejects self-signed TLS certs.
15+
# Patch the initialization wget call to skip certificate verification before
16+
# any probe fires (postStart runs before startupProbe's initialDelaySeconds).
17+
lifecycle:
18+
postStart:
19+
exec:
20+
command:
21+
- /bin/sh
22+
- -c
23+
- sed -i 's|wget -o /dev/null -q -O /dev/null|wget --no-check-certificate -o /dev/null -q -O /dev/null|' /healthcheck.sh
1424
config:
1525
# ONTOSERVER_INSECURE=true disables Ontoserver's inbound TLS listener (serves plain HTTP).
1626
# The chart default is "true" for convenience in cluster-internal deployments.

charts/ontoserver/values.schema.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@
160160
"unhealthyPodEvictionPolicy": { "type": "string", "default": null }
161161
}
162162
},
163+
"containerPort": { "type": "integer", "minimum": 1, "maximum": 65535 },
164+
"lifecycle": { "type": "object" },
163165
"db": {
164166
"type": "object",
165167
"properties": {
@@ -448,6 +450,40 @@
448450
}
449451
}
450452
},
453+
"traefik": {
454+
"type": "object",
455+
"properties": {
456+
"ingressRoute": {
457+
"type": "object",
458+
"properties": {
459+
"enabled": { "type": "boolean" },
460+
"annotations": { "type": "object" },
461+
"entryPoints": {
462+
"type": "array",
463+
"items": { "type": "string" }
464+
},
465+
"backendPort": { "type": ["integer","string"] },
466+
"backendScheme": { "type": "string" },
467+
"backendServiceNameOverride": { "type": "string" },
468+
"serversTransport": {
469+
"type": "object",
470+
"properties": {
471+
"enabled": { "type": "boolean" },
472+
"insecureSkipVerify": { "type": "boolean" },
473+
"rootCAsSecrets": {
474+
"type": "array",
475+
"items": { "type": "string" }
476+
},
477+
"certificatesSecrets": {
478+
"type": "array",
479+
"items": { "type": "string" }
480+
}
481+
}
482+
}
483+
}
484+
}
485+
}
486+
},
451487
"nginx-ingress": {
452488
"type": "object",
453489
"properties": {

charts/ontoserver/values.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ ontoserver:
1818
imagePullPolicy: IfNotPresent
1919
## @param ontoserver.deployment.containerPort Container port Ontoserver listens on. Use 8080 for HTTP (ONTOSERVER_INSECURE=true) or 8443 for HTTPS (ONTOSERVER_INSECURE=false).
2020
containerPort: 8080
21+
## @param ontoserver.deployment.lifecycle Container lifecycle hooks (postStart / preStop). Passed through as-is to the container spec.
22+
lifecycle: {}
2123
## @param ontoserver.deployment.imagePullSecrets Additional pre-created image pull secrets to attach to the pod (merged with the chart-managed pull secret when imageCredentials are set)
2224
imagePullSecrets: []
2325
## @param ontoserver.deployment.isReadOnly Ontoserver in read‑only mode - keep it true for scaled

0 commit comments

Comments
 (0)