Skip to content

Commit 9c5a3ef

Browse files
committed
feat: add secure Java truststore for qtodo with Vault integration
- Add init container to convert CA bundle to Java JKS truststore - Add ExternalSecret for truststore password from Vault - Configure JAVA_TOOL_OPTIONS for JVM-level SSL truststore - Mount ztvp-trusted-ca ConfigMap for CA certificates - Enable truststore by default when SPIRE is enabled Signed-off-by: Min Zhang <minzhang@redhat.com>
1 parent 2055bec commit 9c5a3ef

7 files changed

Lines changed: 150 additions & 22 deletions

File tree

charts/qtodo/templates/app-config-env.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ metadata:
44
name: qtodo-config-env
55
namespace: {{ .Release.Namespace }}
66
data:
7-
{{- if eq .Values.app.oidc.enabled true }}
8-
QUARKUS_OIDC_ENABLED: "{{ .Values.app.oidc.enabled }}"
7+
{{- if eq .Values.app.spire.enabled true }}
8+
QUARKUS_OIDC_ENABLED: "true"
99
QUARKUS_OIDC_AUTH_SERVER_URL: "{{ default (printf "https://keycloak.%s/realms/ztvp" .Values.global.localClusterDomain) .Values.app.oidc.authServerUrl }}"
1010
QUARKUS_OIDC_CLIENT_ID: "{{ .Values.app.oidc.clientId }}"
1111
QUARKUS_OIDC_APPLICATION_TYPE: "{{ .Values.app.oidc.applicationType }}"

charts/qtodo/templates/app-deployment.yaml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,59 @@ spec:
2929
spec:
3030
{{- if eq .Values.app.spire.enabled true }}
3131
initContainers:
32+
- name: init-ca-truststore
33+
image: registry.redhat.io/ubi9/openjdk-17:latest
34+
imagePullPolicy: IfNotPresent
35+
command:
36+
- /bin/bash
37+
- -c
38+
- |
39+
set -e
40+
echo "Converting CA bundle to Java truststore..."
41+
42+
# Validate password is provided
43+
if [ -z "$TRUSTSTORE_PASSWORD" ]; then
44+
echo "ERROR: TRUSTSTORE_PASSWORD not set"
45+
exit 1
46+
fi
47+
48+
# Split the PEM bundle into individual certificates
49+
csplit -s -z -f /tmp/cert- /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem '/-----BEGIN CERTIFICATE-----/' '{*}'
50+
51+
# Create the truststore with each certificate
52+
TRUSTSTORE_PATH="/run/secrets/truststore/cacerts"
53+
54+
# Remove any existing truststore
55+
rm -f "$TRUSTSTORE_PATH"
56+
57+
# Import each certificate into the truststore
58+
cert_index=0
59+
for cert_file in /tmp/cert-*; do
60+
if [ -s "$cert_file" ]; then
61+
echo "Importing certificate $cert_index from $cert_file"
62+
keytool -import -noprompt \
63+
-alias "ztvp-ca-$cert_index" \
64+
-keystore "$TRUSTSTORE_PATH" \
65+
-storepass "$TRUSTSTORE_PASSWORD" \
66+
-file "$cert_file" || echo "Warning: Failed to import $cert_file"
67+
cert_index=$((cert_index + 1))
68+
fi
69+
done
70+
71+
echo "Successfully created truststore with $cert_index certificates"
72+
ls -lh "$TRUSTSTORE_PATH"
73+
env:
74+
- name: TRUSTSTORE_PASSWORD
75+
valueFrom:
76+
secretKeyRef:
77+
name: qtodo-truststore-secret
78+
key: truststore-password
79+
volumeMounts:
80+
- name: ztvp-trusted-ca
81+
mountPath: /etc/pki/ca-trust/extracted/pem
82+
readOnly: true
83+
- name: truststore
84+
mountPath: /run/secrets/truststore
3285
- name: init-spiffe-helper
3386
image: {{ template "qtodo.image" .Values.app.images.spiffeHelper }}
3487
imagePullPolicy: {{ .Values.app.images.spiffeHelper.pullPolicy }}
@@ -181,11 +234,29 @@ spec:
181234
secretKeyRef:
182235
name: oidc-client-secret
183236
key: client-secret
237+
{{- if eq .Values.app.truststore.enabled true }}
238+
# Truststore password from Vault secret
239+
- name: TRUSTSTORE_PASSWORD
240+
valueFrom:
241+
secretKeyRef:
242+
name: qtodo-truststore-secret
243+
key: truststore-password
244+
# JVM-level truststore configuration for all SSL connections
245+
- name: JAVA_TOOL_OPTIONS
246+
value: "-Djavax.net.ssl.trustStore=/run/secrets/truststore/cacerts -Djavax.net.ssl.trustStoreType=JKS -Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD)"
247+
{{- end }}
184248
{{- end }}
185249
{{- if eq .Values.app.spire.enabled true }}
186250
volumeMounts:
187251
- name: db-credentials
188252
mountPath: /run/secrets/db-credentials
253+
- name: truststore
254+
mountPath: /run/secrets/truststore
255+
readOnly: true
256+
# Mount ZTVP CA bundle for non-Java tools (curl, openssl, etc.)
257+
- name: ztvp-trusted-ca
258+
mountPath: /etc/pki/ca-trust/extracted/pem
259+
readOnly: true
189260
{{- end }}
190261
resources: {}
191262
serviceAccountName: qtodo
@@ -210,4 +281,6 @@ spec:
210281
configMap:
211282
name: ztvp-trusted-ca
212283
defaultMode: 420
284+
- name: truststore
285+
emptyDir: {}
213286
{{- end }}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{{- if .Values.app.spire.enabled }}
2+
apiVersion: "external-secrets.io/v1beta1"
3+
kind: ExternalSecret
4+
metadata:
5+
name: qtodo-truststore-secret
6+
namespace: {{ .Release.Namespace }}
7+
annotations:
8+
argocd.argoproj.io/sync-wave: '5'
9+
spec:
10+
refreshInterval: 15s
11+
secretStoreRef:
12+
name: {{ .Values.global.secretStore.name }}
13+
kind: {{ .Values.global.secretStore.kind }}
14+
target:
15+
name: qtodo-truststore-secret
16+
template:
17+
type: Opaque
18+
data:
19+
truststore-password: "{{ `{{ .truststore_password }}` }}"
20+
data:
21+
- secretKey: truststore_password
22+
remoteRef:
23+
key: {{ .Values.app.truststore.vaultPath }}
24+
property: truststore-password
25+
{{- end }}

charts/qtodo/values.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ app:
6363
enabled: true
6464
name: "oidc-client-secret"
6565
vaultPath: "secret/data/global/oidc-client-secret"
66+
67+
# Truststore configuration for Java CA certificates
68+
truststore:
69+
enabled: true
70+
vaultPath: "secret/data/global/qtodo-truststore"
6671

6772
# PostgreSQL database configuration
6873
postgresql:

charts/ztvp-certificates/templates/ca-extraction-job-initial.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ metadata:
77
namespace: {{ .Values.global.namespace }}
88
annotations:
99
argocd.argoproj.io/sync-wave: "-8"
10+
# Run as regular sync resource (after RBAC at -9, before Policy at -5)
11+
# Using Prune=false prevents OutOfSync after TTL deletes the completed Job
12+
argocd.argoproj.io/sync-options: Prune=false
1013
labels:
1114
{{- include "ztvp-certificates.labels" . | nindent 4 }}
1215
app.kubernetes.io/component: initial-extraction

values-hub.yaml

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -163,39 +163,54 @@ clusterGroup:
163163
path: charts/ztvp-certificates
164164
annotations:
165165
argocd.argoproj.io/sync-wave: "-10"
166-
# Use extraValueFiles for complex nested structures like additionalCertificates and rollout
166+
# Ignore the ACM-replicated policy in local-cluster namespace
167+
# ACM automatically creates policy replicas with name pattern: <source-ns>.<policy-name>
168+
ignoreDifferences:
169+
- group: policy.open-cluster-management.io
170+
kind: Policy
171+
name: openshift-config.ztvp-certificates-distribution
172+
namespace: local-cluster
173+
jsonPointers:
174+
- /
175+
# Use extraValueFiles for complex nested structures like additionalCertificates
167176
# The validated patterns framework only processes 'overrides' as --set parameters
168177
# Edit /overrides/values-ztvp-certificates.yaml to configure:
169178
# - Additional CA certificates (additionalCertificates array)
170179
# - Automatic rollout restart for consuming applications
171180
extraValueFiles:
172181
- /overrides/values-ztvp-certificates.yaml
173182
overrides:
174-
# Job TTL: Retention time for completed CA extraction jobs
175-
# Default: 300s (5 min). Extended for debugging/verification.
176-
- name: job.ttlSecondsAfterFinished
177-
value: "900" # 15 minutes
183+
# Disable Job TTL to prevent ArgoCD OutOfSync when Kubernetes deletes completed Jobs
184+
# The initial Job runs once during first sync; CronJob handles ongoing extraction
185+
- name: debug.keepFailedJobs
186+
value: "true"
178187

179-
# Debug settings: Enable for troubleshooting certificate extraction issues
180-
# verbose: Enables bash 'set -x' for detailed script execution logging
181-
# keepFailedJobs: Prevents failed jobs from auto-cleanup (useful for debugging)
188+
# Enable verbose logging for troubleshooting (uncomment if needed)
182189
# - name: debug.verbose
183190
# value: "true"
184-
# - name: debug.keepFailedJobs
185-
# value: "true"
186191

187-
# Primary custom CA: Use secretRef to reference an existing Kubernetes secret
188-
# containing CA certificates. Uncomment to enable:
189-
# Create secret: oc create secret generic custom-ca-bundle \
190-
# --from-file=ca.crt=/path/to/ca.crt -n openshift-config
192+
# Primary custom CA: Use secretRef to reference an existing Kubernetes secret containing CA certificates
193+
# Uncomment to add a primary custom CA:
194+
# Single cert: oc create secret generic custom-ca-bundle --from-file=ca.crt=/path/to/ca.crt -n openshift-config
195+
# Multiple certs: cat corp-root.crt intermediate.crt partner.crt > combined-ca.crt && oc create secret generic custom-ca-bundle --from-file=ca.crt=combined-ca.crt -n openshift-config
196+
# Disabled for now - using auto-detection only
191197
# - name: customCA.secretRef.enabled
192198
# value: "true"
193-
# - name: customCA.secretRef.name
194-
# value: custom-ca-bundle
195-
# - name: customCA.secretRef.namespace
196-
# value: openshift-config
197-
# - name: customCA.secretRef.key
198-
# value: ca.crt
199+
- name: customCA.secretRef.name
200+
value: custom-ca-bundle
201+
- name: customCA.secretRef.namespace
202+
value: openshift-config
203+
- name: customCA.secretRef.key
204+
value: ca.crt
205+
206+
# Automatic rollout configuration (simple overrides work fine)
207+
- name: rollout.enabled
208+
value: "true"
209+
- name: rollout.strategy
210+
value: labeled
211+
212+
# Note: additionalCertificates (complex nested array) temporarily disabled
213+
# Need to find proper way to pass complex structures in Validated Patterns
199214
acm:
200215
name: acm
201216
namespace: open-cluster-management

values-secret.yaml.template

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ secrets:
4747
- name: db-password
4848
onMissingValue: generate
4949
vaultPolicy: validatedPatternDefaultPolicy
50+
- name: qtodo-truststore
51+
vaultPrefixes:
52+
- global
53+
fields:
54+
- name: truststore-password
55+
onMissingValue: generate
56+
vaultPolicy: alphaNumericPolicy
5057
- name: keycloak-users
5158
vaultPrefixes:
5259
- global

0 commit comments

Comments
 (0)