Excerpt: Extending the Truststore Secret

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

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.sh

3. 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.crt

4. What the Script Does

The script performs the following steps automatically:

  1. Detects sudo requirement - Checks if kubectl needs sudo privileges

  2. Finds deployment - Locates either sfit-platform or genoslc deployment

  3. Gets container image - Retrieves the container image from the deployment

  4. Identifies truststore secret - Finds the truststore secret name from the deployment

  5. Creates temporary pod - Spins up a temporary pod with the application image

  6. Copies certificates - Transfers certificate files to the pod

  7. Prepares truststore - Copies existing truststore or creates a new one

  8. Adds certificates - Imports certificates into the truststore using keytool

  9. Updates secret - Creates/updates the Kubernetes secret with the extended truststore

  10. Exports YAML - Saves the secret as a YAML file for backup

  11. Cleans up - Removes the temporary pod

  12. 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>.yaml

Important 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: false

Without 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:

  1. Disabled certtool in the deployment (see above)

  2. Used the correct certificate format (PEM)

Support

For issues or questions, contact cops@mid.de.