Securing SSL Private Key Password

I am working on automating PFX certificate rotations for Ignition 8.1. I’ve successfully hot loaded a new cert using this approach Let's Encrypt Guide for Ignition | Inductive Automation with “ignition” as the password and alias.

However, my company’s security policy doesn’t allow passwords in plain text. When I started looking into configuring a custom password (ignition.ssl.privatekey.password), it appears it would be stored plain text in ignition.conf.

Am I missing something? Is there a way to obfuscate the password?

I don't think you're missing anything. It looks like even in Ignition 8.3, where we have introduced support for secret management / providers, the system property is still the only mechanism for supplying alternate passwords in this area.

Thanks for the reply. I was hoping I was just missing something and there’s a way to update the password without storing it in plain text.

Kevin is correct: the Ignition web server’s SSL keystore passwords are sourced from Java system properties, even in 8.3. We have a ticket in our backlog to source the keystore and/or its password(s) from the new secrets management system introduced with 8.3.

In the meantime, what you could do as a workaround is write an Ignition script which takes a plaintext password as input and then encrypts and stores the ciphertext in a file. Then you could write a Gateway startup script which loads the ciphertext from the file, decrypts the ciphertext back into the plaintext password, and then set the appropriate Java system properties to the plaintext password(s) you loaded, and then reload the Gateway’s keystore.

Project Library legacySecrets (helper functions to encrypt and decrypt secrets in 8.1):

from com.inductiveautomation.ignition.common import GatewaySec

def readFromFile(filepath):
	ciphertext = system.file.readFileAsString(filepath, "UTF-8")
	return GatewaySec.decrypt(ciphertext)

def writeToFile(filepath, plaintext):
	ciphertext = GatewaySec.encrypt(plaintext)
	system.file.writeFile(filepath, ciphertext, False, "UTF-8")

Project Library secrets (helper functions to encrypt and decrypt secrets in 8.3):

def readFromFile(filepath):
	json = system.file.readFileAsString(filepath, "UTF-8")
	ciphertext = system.util.jsonDecode(json)
	plaintext = system.secrets.decrypt(ciphertext)
	return plaintext.getSecretAsString("UTF-8")

def writeToFile(filepath, plaintext):
	ciphertext = system.secrets.encrypt(plaintext, "UTF-8")
	json = system.util.jsonEncode(ciphertext)
	system.file.writeFile(filepath, json, False, "UTF-8")

Project Library systemProperties (helper functions to get and set Java system properties programmatically):

from java.lang import System

def getSystemProperty(name):
	return System.getProperty(name)

def setSystemProperty(name, value):
	System.setProperty(name, value)

Project Library webServer (helper functions to interact with the Gateway web server’s keystore):

from com.inductiveautomation.ignition.gateway import IgnitionGateway

def refreshKeystore():
	IgnitionGateway.get().getWebResourceManager().getSslManager().refresh()

I’ll leave it up to you to piece these together and set up the appropriate startup script. Keep in mind that some of these functions (particularly those in the legacySecrets and webServer libraries) take advantage of private implementation details, meaning if you decide to use these, take care to perform regression testing before upgrading production systems to new versions of Ignition, as we may change implementation details in future versions.

4 Likes