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