Transmission/Engine module: where to find keystore

Hi all,
we are working on an Ignition (8.1.48) implementation on OpenShift (Kubernetes) with the integration of the 4.0.29 modules. We base the implementation on the icc2023-ignition-k8s project.

For the implementation we want to automatically insert the certificates into the ignition keystores, the question therefore remains: which keystores do these modules use?

  • CirrusLink MQTT Distributor 4.0.29 : the Ignition web UI keystore ssl.pfx
  • CirrusLink MQTT Transmission 4.0.29 : location unknown
  • CirrusLink MQTT Engine 4.0.29 : location unknown

Based on existing topic ‘Cirrus MQTT Engine to Cirrus Chariot Server - Configuring TLS/SSL’ and documentation ‘Setting up Client based authentication with Client Certificates’ the keystore of the Chariot broker is available, but these of the Ignition modules are not defined.

Many thanks in advance, Mateo.

These certificates are not stored in a keystore. They are stored inside of Ignition’s internal database as part of a persistent record. However, we don’t recommend or support accessing this DB directly. We do offer Python scripting APIs that allow you to create, update, and delete persistent records (which is what the Ignition Web UI does behind the scenes). Take a look at these two docs regarding the scripting APIs for Engine and Transmission:

Specifically, look at the Cert Files and Servers sections.

Hi Wes, thank you for the clarification.
The scripting API Cert Files requires the certificate to be inserted as plain text.

Is there any solution to provide this certificate using a configMap or secret instead of including it directly in the onstart script?
A possible way of doing this would be by inserting the certificate into a fixed place in the volume and using the scripting options to extract the certificate back from the volume location.
Would this be a recommended way of working?

Kind regards, Mateo

That seems like a reasonable/viable solution to me. As long as you can access the certs/keys from Ignition via a Python script you can get the record created and properly bound to a server record.

Hi all, happy to inform that the above idea worked fine. Below the (simplified) code example used.

  1. Creating the Ignition keystore for the CirrusLink distributor module, we are using cert manager to create (and manage) the keystore and certificate.
    see: Certificate resource - cert-manager Documentation
---
# Create a secret with the ignition password (ignition)
kind: Secret
apiVersion: v1
metadata:
  name: {{ignition-keystore-password-name}}
  namespace: {{namespace}}
data:
  #Base64-encoded password 'ignition' for the keystore: DO NOT CHANGE
  password: aWduaXRpb24=
type: Opaque
---
# Create the certificate chain in cert manager
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: {{cert-manager-cert-name}}
  namespace: {{namespace}}
spec:
  secretName: {{ignition-tls-secretName}}
  # add your certificate information here
  issuerRef:
  # add your certificate issuer here
  keystores:
    pkcs12:
      create: true
      passwordSecretRef:
        name: {{ignition-keystore-password-name}}
        key: password
      profile: Modern2023
  1. Create a statefull set with an initContainer that replaces the existing keystore and copies the associated certificate into the persistent volume.
    see: icc2023-ignition-k8s/base/scripts/prepare-tls-certificates.sh at main · thirdgen88/icc2023-ignition-k8s · GitHub
---
# StatefulSets
# ignition
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ignition-statefulSet-name}}
  namespace: {{namespace}}
spec:
  template:
    spec:
      # initialization containers
      initContainers:
        # Web UI + MQTT certificate loading
        - name: init-copy-cert
          image: inductiveautomation/ignition:latest
          resources:
          command:
          - /bin/sh
          - -c
          args:
          - |
            secret_name={{ignition-tls-secretName}}
            echo "Preparing Web Server TLS Certificates"

            # Replace any existing TLS keystore with the updated one from the mounted secret
            rm -v -f /data/local/ssl.pfx
            cp /run/secrets/${secret_name}/keystore.p12 /data/local/ssl.pfx
            cp /run/secrets/${secret_name}/ca.crt /data/local/ca.crt

            # Modify the TLS keystore
            # Add alias "ignition" to the ca certificate
            existing_alias=$(keytool -list -keystore /data/local/ssl.pfx -storepass ignition | grep PrivateKeyEntry | cut -d, -f 1)
            if [ "${existing_alias}" != "ignition" ]; then
              keytool -changealias -alias "${existing_alias}" -destalias ignition \
                -keystore /data/local/ssl.pfx -storepass ignition
            fi
            echo "Web Server TLS Certificates copied."
          volumeMounts:
            - name: ignition-data
              mountPath: /data
            - name: {{ignition-tls-secretName}}
              mountPath: /run/secrets/{{ignition-tls-secretName}}
              readOnly: true
      volumes:
        - name: ignition-data
          persistentVolumeClaim:
            claimName: ignition-data
        - name: {{ignition-tls-secretName}}
          secret:
            secretName: {{ignition-tls-secretName}}
  1. Finally, created a Ignition Python 2.7 script to retrieve the ca.crt file from the volume and add it to the transmission and engine module with the Cert Files API.
import os

transmissionProps = {}
transmissionProps["Id"] = system.date.now().getTime()	#unique value
transmissionProps["Name"] = certFileName
transmissionProps["Description"] = certFileDescription
transmissionProps["FileContents"] = getCertificateContent("/usr/local/bin/ignition/data/local/ca.crt")

system.cirruslink.transmission.createConfig("Cert Files", transmissionProps)
	
def getCertificateContent(cert_path):
	# Check if the file exists and read it
	if os.path.exists(cert_path):
	    with open(cert_path, "r") as cert_file:
	        return cert_file.read()
	else:
	    return None

Hopefully this can help someone else in the future as well. Note that the above code examples are simplified and reduced to the bare minimum and I recommend adding your own failsafe guards, such as Id validation and usage of the certificate names instead of Id’s in the Servers API.

Kind regards, Mateo Duren