Excerpt: Extending the Truststore Secret
Add Certificates to the Secret containing the Java Truststore
This document describes how to add intermediate and root certificates to the Java truststore used by Smartfacts and OSLC connector installations.
Table of Contents
- 1
- 2 Add Certificates to the Secret containing the Java Truststore
- 2.1 Table of Contents
- 2.2 Overview
- 2.3 Prerequisites
- 2.4 Script
- 2.5 Usage
- 2.5.1 1. Prepare Certificate Files
- 2.5.2 2. Make Script Executable
- 2.5.3 3. Run the Script
- 2.5.4 4. What the Script Does
- 2.6 Output Files
- 2.6.1 Restoring the Truststore
- 2.7 Important Post-Installation Step
- 2.8 Troubleshooting
- 2.9 Support
Overview
The extendTruststore.sh script automates the process of adding certificates to the Java truststore in Kubernetes deployments. It creates a temporary pod with the application container image, adds the certificates to the truststore, and updates the Kubernetes secrets accordingly.
This version of the exendTruststore.sh script works for the depolyments of
Smartfacts Platform
OSLC Connectors
Smartfacts Link Index
Prerequisites
Before running the script, ensure you have:
kubectl installed and configured with access to your Kubernetes cluster
Appropriate permissions to create/delete pods and secrets in the target namespace
sudo privileges (if required for kubectl commands in your environment)
Certificate files in PEM format (.crt, .pem, etc.)
Script
Copy the following script and save it as extendTruststore.sh:
#!/bin/bash
#
# Add Certificates to Java Truststore
#
# This script automates the process of adding intermediate and root certificates
# to the Java truststore used by Smartfacts and OSLC connector installations.
# It creates a temporary pod with the sfit-platform or genoslc container
# image to access the Java environment, adds the certificates to the truststore,
# and updates the Kubernetes secrets accordingly.
#
# Prerequisites:
# - kubectl must be installed and configured
# - Access to the Kubernetes cluster with appropriate permissions
# - sudo privileges for kubectl commands (if necessary)
# - Certificate files (.crt, .pem, etc.) to be added must be present in pem format
#
# Usage:
# ./extendTruststore.sh <namespace> <cert1> [cert2] [cert3] ...
#
# Example:
# ./extendTruststore.sh smartfacts intermediate.crt root.crt
#
# Important:
# After running this script, you must disable certtool in the deployment
# configuration to prevent it from overwriting the extended truststore:
# certtool:
# enabled: false
#
set -e
TRUSTSTORE_PASSWORD="changeit"
echo "=== Add Certificates to Java Truststore ==="
echo ""
if [ "$#" -lt 2 ]; then
echo "Usage: $0 <namespace> <certificate_file1> [certificate_file2] [certificate_file3] ..."
echo ""
echo "Example: $0 smartfacts intermediate-cert.crt root-cert.crt"
exit 1
fi
NAMESPACE="$1"
shift
CERT_FILES=("$@")
echo "Certificates to add:"
for cert in "${CERT_FILES[@]}"; do
if [ ! -f "$cert" ]; then
echo "ERROR: Certificate file not found: $cert"
exit 1
fi
echo " - $cert"
done
echo ""
echo "Detecting if sudo is required for kubectl..."
KUBECTL_CMD="kubectl"
if kubectl version --client &>/dev/null; then
echo "kubectl works without sudo"
else
if sudo kubectl version --client &>/dev/null; then
KUBECTL_CMD="sudo kubectl"
echo "kubectl requires sudo"
else
echo "ERROR: kubectl is not available or not configured properly"
exit 1
fi
fi
echo ""
echo "Step 1: Detect available deployment (sfit-platform, genoslc or smartfacts-link-index)"
DEPLOYMENT_NAME=$($KUBECTL_CMD get deployment -n $NAMESPACE | grep sfit-platform | awk '{print $1}' | head -n 1)
if [ -n "$DEPLOYMENT_NAME" ]; then
DEPLOYMENT_TYPE="sfit-platform"
echo "Found sfit-platform deployment: $DEPLOYMENT_NAME"
else
DEPLOYMENT_NAME=$($KUBECTL_CMD get deployment -n $NAMESPACE | grep genoslc | awk '{print $1}' | head -n 1)
if [ -n "$DEPLOYMENT_NAME" ]; then
DEPLOYMENT_TYPE="genoslc"
echo "Found genoslc deployment: $DEPLOYMENT_NAME"
else
DEPLOYMENT_NAME=$($KUBECTL_CMD get deployment -n $NAMESPACE | grep smartfacts-link-index | awk '{print $1}' | head -n 1)
if [ -n "$DEPLOYMENT_NAME" ]; then
DEPLOYMENT_TYPE="smartfacts-link-index"
echo "Found smartfacts-link-index deployment: $DEPLOYMENT_NAME"
else
echo "ERROR: Could not find sfit-platform, genoslc or smartfacts-link-index deployment"
exit 1
fi
fi
fi
# Derive temporary pod name from deployment name
TEMP_POD_NAME="${DEPLOYMENT_NAME}-truststore-temp"
echo "Using temporary pod name: $TEMP_POD_NAME"
echo ""
echo "Step 2: Get container image from deployment"
CONTAINER_IMAGE=$($KUBECTL_CMD get deployment $DEPLOYMENT_NAME -n $NAMESPACE -o jsonpath='{.spec.template.spec.containers[0].image}')
if [ -z "$CONTAINER_IMAGE" ]; then
echo "ERROR: Could not get container image from deployment"
exit 1
fi
echo "Using image: $CONTAINER_IMAGE"
echo "Step 3: Get truststore secret name from deployment"
TRUSTSTORE_SECRET=$($KUBECTL_CMD get deployment $DEPLOYMENT_NAME -n $NAMESPACE -o jsonpath='{.spec.template.spec.volumes[?(@.name=="truststore")].secret.secretName}')
if [ -z "$TRUSTSTORE_SECRET" ]; then
echo "WARNING: No truststore volume found in deployment, using default: smartfacts-truststore"
TRUSTSTORE_SECRET="smartfacts-truststore"
else
echo "Found truststore secret: $TRUSTSTORE_SECRET"
fi
# Derive truststore password secret name from truststore secret
TRUSTSTORE_PASSWORD_SECRET="${TRUSTSTORE_SECRET}-password"
echo "Using truststore password secret: $TRUSTSTORE_PASSWORD_SECRET"
echo ""
echo "Step 4: Check if temporary pod already exists and delete it"
if $KUBECTL_CMD get pod $TEMP_POD_NAME -n $NAMESPACE &>/dev/null; then
echo "Deleting existing temporary pod..."
$KUBECTL_CMD delete pod $TEMP_POD_NAME -n $NAMESPACE --force --grace-period=0
sleep 5
fi
echo ""
echo "Step 5: Create temporary pod with overridden entrypoint"
cat <<EOF | $KUBECTL_CMD apply -f -
apiVersion: v1
kind: Pod
metadata:
name: $TEMP_POD_NAME
namespace: $NAMESPACE
spec:
containers:
- name: $DEPLOYMENT_TYPE
image: $CONTAINER_IMAGE
command: ["/bin/sh"]
args: ["-c", "sleep infinity"]
volumeMounts:
- mountPath: /opt/security
name: truststore
volumes:
- name: truststore
secret:
secretName: $TRUSTSTORE_SECRET
optional: true
restartPolicy: Never
EOF
echo "Waiting for temporary pod to be ready..."
$KUBECTL_CMD wait --for=condition=Ready pod/$TEMP_POD_NAME -n $NAMESPACE --timeout=120s
echo ""
echo "Step 6: Copy certificates to temporary pod"
for cert in "${CERT_FILES[@]}"; do
cert_basename=$(basename "$cert")
echo "Copying $cert to pod..."
if $KUBECTL_CMD cp "$cert" $TEMP_POD_NAME:/tmp/$cert_basename -n $NAMESPACE 2>/dev/null; then
echo "Copied using kubectl cp"
else
echo "kubectl cp failed (tar not available), using stdin method..."
cat "$cert" | $KUBECTL_CMD exec -i $TEMP_POD_NAME -n $NAMESPACE -- sh -c "cat > /tmp/$cert_basename"
fi
done
echo ""
echo "Step 7: Get truststore password from secret (if exists)"
if $KUBECTL_CMD get secret $TRUSTSTORE_PASSWORD_SECRET -n $NAMESPACE &>/dev/null; then
TRUSTSTORE_PASSWORD=$($KUBECTL_CMD get secret $TRUSTSTORE_PASSWORD_SECRET -n $NAMESPACE -o jsonpath='{.data.password}' | base64 -d)
echo "Using password from existing secret: $TRUSTSTORE_PASSWORD_SECRET"
else
echo "No password secret found, using default password"
fi
echo "Step 8: Prepare truststore inside pod"
$KUBECTL_CMD exec $TEMP_POD_NAME -n $NAMESPACE -- sh -c '
if [ -f /opt/security/truststore.jks ]; then
echo "Copying existing truststore from /opt/security/truststore.jks"
cp /opt/security/truststore.jks /tmp/truststore.jks
elif [ -f /etc/ssl/certs/java/cacerts ]; then
echo "Copying cacerts from /etc/ssl/certs/java/cacerts"
cp /etc/ssl/certs/java/cacerts /tmp/truststore.jks
elif [ -f /opt/java/openjdk/lib/security/cacerts ]; then
echo "Copying cacerts from /opt/java/openjdk/lib/security/cacerts"
cp /opt/java/openjdk/lib/security/cacerts /tmp/truststore.jks
else
JAVA_HOME=$(readlink -f /usr/bin/java 2>/dev/null | sed "s:bin/java::" || echo "")
if [ -n "$JAVA_HOME" ] && [ -f "${JAVA_HOME}lib/security/cacerts" ]; then
echo "Copying cacerts from Java installation"
cp ${JAVA_HOME}lib/security/cacerts /tmp/truststore.jks
else
echo "ERROR: Could not find any truststore or cacerts file"
exit 1
fi
fi
'
echo ""
echo "Step 9: Add certificates to truststore"
for cert in "${CERT_FILES[@]}"; do
cert_basename=$(basename "$cert")
cert_alias=$(basename "$cert" | sed 's/\.[^.]*$//' | tr '[:upper:]' '[:lower:]' | tr ' ' '_')
echo "Adding certificate: $cert_basename with alias: $cert_alias"
OUTPUT=$($KUBECTL_CMD exec $TEMP_POD_NAME -n $NAMESPACE -- sh -c "
cd /tmp
echo 'yes' | keytool -import -alias $cert_alias -file $cert_basename -storetype JKS -keystore truststore.jks -storepass $TRUSTSTORE_PASSWORD -noprompt 2>&1
" || true)
if echo "$OUTPUT" | grep -q "already exists"; then
echo "WARNING: Certificate with alias '$cert_alias' already exists in truststore, skipping"
elif echo "$OUTPUT" | grep -q "Certificate was added to keystore"; then
echo "Certificate added successfully"
elif [ -n "$OUTPUT" ]; then
echo "WARNING: Unexpected output: $OUTPUT"
fi
done
echo ""
echo "Step 10: Copy extended truststore back to local machine"
if $KUBECTL_CMD cp $TEMP_POD_NAME:/tmp/truststore.jks ./extended_truststore.jks -n $NAMESPACE 2>/dev/null; then
echo "Copied using kubectl cp"
else
echo "kubectl cp failed (tar not available), using stdout method..."
$KUBECTL_CMD exec $TEMP_POD_NAME -n $NAMESPACE -- cat /tmp/truststore.jks > ./extended_truststore.jks
fi
echo "Step 11: Update truststore secret"
if $KUBECTL_CMD get secret $TRUSTSTORE_SECRET -n $NAMESPACE &>/dev/null; then
$KUBECTL_CMD delete secret $TRUSTSTORE_SECRET -n $NAMESPACE
fi
$KUBECTL_CMD create secret generic $TRUSTSTORE_SECRET --from-file=truststore.jks=./extended_truststore.jks -n $NAMESPACE
echo "Step 12: Export truststore secret to YAML file"
$KUBECTL_CMD get secret $TRUSTSTORE_SECRET -n $NAMESPACE -o yaml > ${TRUSTSTORE_SECRET}.yaml
echo "Secret YAML saved to: ${TRUSTSTORE_SECRET}.yaml"
echo "Step 13: Ensure truststore password secret exists"
if ! $KUBECTL_CMD get secret $TRUSTSTORE_PASSWORD_SECRET -n $NAMESPACE &>/dev/null; then
echo "Creating truststore password secret: $TRUSTSTORE_PASSWORD_SECRET"
$KUBECTL_CMD create secret generic $TRUSTSTORE_PASSWORD_SECRET --from-literal=password=$TRUSTSTORE_PASSWORD -n $NAMESPACE
else
echo "Truststore password secret already exists: $TRUSTSTORE_PASSWORD_SECRET"
fi
echo "Step 14: Clean up temporary pod"
$KUBECTL_CMD delete pod $TEMP_POD_NAME -n $NAMESPACE
echo "Step 15: Restart application pods to use new truststore"
for pod_pattern in sfit-platform genoslc smartfacts-link-index; do
PODS=$($KUBECTL_CMD get pods -n $NAMESPACE 2>/dev/null | grep $pod_pattern | grep -v Terminating | awk '{print $1}')
for pod in $PODS; do
echo "Deleting pod: $pod"
$KUBECTL_CMD delete pod $pod -n $NAMESPACE
done
done
echo "=== Certificate installation completed successfully ==="
echo ""
echo "Files saved in current directory:"
echo " - extended_truststore.jks (truststore file)"
echo " - ${TRUSTSTORE_SECRET}.yaml (Kubernetes secret manifest)"
echo ""
echo "To restore the truststore secret, run:"
echo " kubectl apply -f ${TRUSTSTORE_SECRET}.yaml"
echo ""
echo "Certificates added:"
for cert in "${CERT_FILES[@]}"; do
cert_alias=$(basename "$cert" | sed 's/\.[^.]*$//' | tr '[:upper:]' '[:lower:]' | tr ' ' '_')
echo " - $(basename "$cert") (alias: $cert_alias)"
done
echo ""
echo "!!! IMPORTANT !!!"
echo "You must disable the certtool in the deployment to prevent it from overwriting"
echo "the extended truststore secret. Set the following in your deployment configuration:"
echo ""
echo "certtool"
echo " enabled: false"
echo ""Usage
1. Prepare Certificate Files
Ensure you have your intermediate and root certificates in PEM format (.crt or .pem files) available on your local machine.
2. Make Script Executable
chmod +x extendTruststore.sh3. Run the Script
Execute the script with the namespace and certificate files as parameters:
./extendTruststore.sh <namespace> <certificate1.crt> [certificate2.crt] ...Example:
./extendTruststore.sh smartfacts intermediate-ca.crt root-ca.crt4. What the Script Does
The script performs the following steps automatically:
Detects sudo requirement - Checks if kubectl needs sudo privileges
Finds deployment - Locates either sfit-platform or genoslc deployment
Gets container image - Retrieves the container image from the deployment
Identifies truststore secret - Finds the truststore secret name from the deployment
Creates temporary pod - Spins up a temporary pod with the application image
Copies certificates - Transfers certificate files to the pod
Prepares truststore - Copies existing truststore or creates a new one
Adds certificates - Imports certificates into the truststore using keytool
Updates secret - Creates/updates the Kubernetes secret with the extended truststore
Exports YAML - Saves the secret as a YAML file for backup
Cleans up - Removes the temporary pod
Restarts pods - Restarts application pods to use the new truststore
Output Files
After successful execution, the script creates two files in the current directory:
extended_truststore.jks- The extended Java truststore file<secret-name>.yaml- Kubernetes secret manifest (e.g.,smartfacts-truststore.yaml)
Restoring the Truststore
To restore the truststore secret from the YAML file:
kubectl apply -f <secret-name>.yamlImportant Post-Installation Step
You must disable the certtool in your deployment configuration to prevent it from overwriting the extended truststore secret.
Add the following to your deployment values:
certtool:
enabled: falseWithout this change, the certtool will regenerate the truststore and remove your custom certificates.
Troubleshooting
Script fails with "kubectl not found"
Ensure kubectl is installed and in your PATH. Install kubectl following the official documentation.
"Permission denied" errors
The script may require sudo privileges. It will automatically detect this and prompt for sudo when needed.
Certificate already exists warning
If you run the script multiple times with the same certificates, you'll see warnings that certificates already exist. This is normal and the script will skip those certificates.
Pod fails to start
Check that:
The namespace exists
You have permissions to create pods in the namespace
The deployment exists and is healthy
Certificates not working after installation
Ensure you:
Disabled certtool in the deployment (see above)
Used the correct certificate format (PEM)
Support
For issues or questions, contact cops@mid.de.