More of a design question than anything. I have gateway scripts, some of which involve emailing our companies clients. On occasion, I’ve had coworkers unknowingly backup the gateway to a development machine with an old database copy, and then all of a sudden our clients are getting emails with outdated information that they already received. Not great.
Currently I’ve been telling people to not export/import gateway scripts, but there are other scripts that don’t involve emails that are essential to the functioning of the application. What would be the best/most modular way to make it so I/my coworkers can export a copy of my production gateway to a development VM or my own localhost, and not have to worry about accidentally running gateway scripts?
Consider placing a JSON encoded file in your production gateway’s filesystem containing configuration values for environment-dependent items. Place an alternate version in each development server. Load it in the top level of a project script at the root of your inheritance tree, so that it can be accessed trivially where needed, something like myGlobalScript.myConfigJson.someItem. Anything that should only run in Production, or do something specific differently, would check that JSON object for the decision.
The chosen filesystem location must be outside any source-control scope.
Ok I think this is sort of what I saw in a Flask tutorial, so I think I understand what you’re saying, correct me if I’m wrong. I’d have a script in a module myConfigJson
def runOnGateway():
"""
Determines if a script should run on the gateway.
"""
import OS
try:
# Some code here to grab the json object from the file
return json[someItem]
except OSError:
# For when the file does not exist
return False
Then in my gateway scripts
import myConfigJson
if myConfigJson.runOnGateway():
# rest of my script here
Where my json file would be something like
config = {
runOnGateway = True,
}
I did see some other project someone did using IP’s but I really dislike hardcoding IP addresses into code. I like your idea of a config file.
You could also rely on environment variables that you access via System.getenv(). It’s the same idea as the JSON config file and the same way many web applications are deployed - certain configuration details are pulled from the environment rather than from code or configuration files that are part of the application.
Ah ok, how would I get access to this through scripting? Also, I see there’s no setEnv - how would I set the environment variable? I can’t tell from the documentation. Also, how would I actually use this via scripting?
import java.lang.System as System
prod = System.getenv().get("IGNITION_PROD")
print str(prod)
on both my development designer and my production designer consoles, prod is None in both instances. I do see there are other options in getenv() I can probably use though, but what is “IGNITION_PROD” supposed to represent? It seems odd its None on my unlicensed development designer and my licensed/activated production designer.
That’s an environment variable name that I made up for the purpose of this example. It could be whatever you want it to be. You have to set it in your actual production environment if you want it to be available (which, again, is the point).
If you are going the environment variable route, you might find python’s os.environ dictionary to be most convenient.
In module:
import os
runOnGateway = bool(os.environ['SOME_ENV_VARIABLE'])
In other scripts:
if myGlobalScript.runOnGateway:
# do something on production gateway
else:
# fake it on a dev gateway
Note that environment variables are really bad places to put anything private. If you need different credentials for production versus dev, use the JSON file approach.
Putting secrets in environment variables is a generally accepted practice because usually your application is running on a server where users can't arbitrarily run scripts or read from the env.
But... Ignition is not such an application. Anybody with designer access can read the env variables. And fwiw, anybody with designer access can read your JSON file too, so it's only marginally more secure via obscurity.
Even when Microsoft is recommending storing secrets in environment variables instead of in an app's code itself, they have a big fat warning, and then describe how to use their JSON infrastructure instead:
I am trying to get better at understanding the security aspect of Ignition so someone please correct me if im wrong -
To summarize, if someone has designer access, they’d easily be able to see my environment variables with the system.getEnv() script right? But unless they had access to the server itself they could not change that.
Where as the config.json method, they would have to search my scripts to find it. But if they could find it, would they be able to edit it via designer? Couldn’t they open it up, read it, edit it, and resave it with a script?
If they crack Ignition itself, or otherwise gain access as the Ignition service user, yes. They’d be able to read that file. As another user, no, you can set the security on the file to prevent other users access. Similar to what is done to protect SSL private keys.
If they gain root access, all bets are off. Labeling files for SELinux can help even that case, though.
You could prevent even Ignition from writing back to the JSON file by letting root own it, and set its group to something that only Ignition belongs to, and let the group have read-only access.
As for manipulating environment variables, at least in java memory, you might enjoy all the hacks in this StackOverflow post:
Hey, just wanted to give an update, it seems while running the script to get environment variables on a designer running on the gateway works, trying to run the
import java.lang.System as System
prod = System.getenv().get("IGNITION_PROD")
print str(prod)
on a gateway script always gives me a None even though there is an environment variable.
Where are you setting this environment variable? In modern Linux, systemd units are started with sanitized environments. You have to define additional variables there. In windows, services will see only system environment variable, IIRC.
{Not that I’m suggesting this… I still think @Kevin.Herron is wrong… (: }
I take it back. I accidentally added to the variables for Administrator at the top
instead of System Variables at the bottom. Works fine now. Was just developer induced error.