Secure Arguments
Overview Copied
Secure Arguments (also known as secure args) is a mechanism in Opsview that enhances the security of plugins, notification scripts, and event handlers by passing their arguments through standard input (stdin) instead of the command line.
When Opsview calls plugins, notification scripts, and event handlers, it requires providing arguments to the script. Traditionally, these executable files accept parameters via command line arguments and in some cases, environment variables. This provides flexibility and interoperability between different platforms and compatibility with Nagios plugins. However, these traditional command line argument scripts can be a potential security risk as these are visible to all local operating system users on the collectors.
To address this, Opsview supports secure args scripts to protect sensitive information in arguments. When secure args are used, the arguments will not be visible in the process list on the collectors and cannot be intercepted by local users on the same host where they are executed. This enhances security while providing a simple and flexible execution pattern for plugins, notification scripts, and event handlers.
Note
Not all of Opsview’s built-in plugins support secure args. Custom plugins, notification scripts, and event handlers will need to be modified and re-imported.
To determine how plugins or scripts are executed, Opsview tracks an execution style for each. Uploaded plugins or scripts can be executed in the following ways:
- Command Line Args (default)
- Secure Args
The Execution Style column on the Configuration > Monitoring Plugins page lists the value for each plugin. The execution style of built-in plugins or scripts cannot be modified and is controlled by the system (displayed as Auto).
Use secure args scripts Copied
For a script to accept secure args, it must read a line from stdin, decode it as a JSON dictionary, and extract the array of strings from the cmd
key within that dictionary. This array of strings can then replace the command line arguments in the existing argv
variable. The script can then continue its execution as normal.
To test a script, you can manually pass the JSON string via stdin after constructing the argv
array:
echo '{"cmd": ["arg1", "arg2", "arg3", "-a", "arg4", "--example", "arg5"]}' | ./my_secure_args_script.py
Alternatively, you can use the following helper script on an Opsview system when running commands manually, which accepts command line arguments without any need for further changes.
./my_secure_args_script.py <<< $(/opt/opsview/monitoringscripts/commands/ov_cmd_split arg1 arg2 arg3 -a arg4 --example arg5)
The /opt/opsview/monitoringscripts/commands/ov_cmd_split
script is available for the opsview
user with the ov_cmd_split
alias.
Import secure args scripts Copied
For plugins, you can import the secure args scripts using the UI.
- Go to the Configuration > Monitoring Plugins and click Import.
- Select the Compatible with Secure Args execution style checkbox.
For more details, see User Interface.
Note
Import Monitoring Plugins functionality is disabled by default on new installations. For more information, see documentation on Active Checks and Monitoring plugins.
Note
To import a notification script or event handler, please contact ITRS Support for assistance.
Import an Opspack with secure args plugins Copied
To upload plugins in an Opspack, the config.json
file allows an optional section of the following format:
"plugin_execution_style": {
"<plugin name>": "<COMMAND_LINE_ARGS|STDIN_ARGS>"
}
This will be used to set the execution style on a per-plugin basis. For example, the following config.json
sets the check_mssql_database.py
plugin to use secure args instead of command line args.
{
"plugin_execution_style": {
"check_mssql_database.py": "STDIN_ARGS"
},
...
}
If plugin_execution_style
is not specified, the default style is COMMAND_LINE_ARGS
. This can be imported as a normal Opspack on the Configuration > Host Templates page.
Note
Import Opspack functionality is disabled by default on new installations. For more information, see documentation on Importing Opspacks.
Code samples Copied
The following code examples show how to implement secure args scripts in several common programming languages.
Python with plugnpy Copied
Using the Opsview plugnpy Python library (included with /opt/opsview/python3/bin/python
on Opsview systems):
#!/opt/opsview/python3/bin/python
import sys
from plugnpy import Parser as PnPParser, ExecutionStyle, Check
def get_args():
parser = PnPParser(
execution_style=ExecutionStyle.STDIN_ARGS, # switches PnP parser to use STDIN-only for args
)
# Add arguments here:
# e.g.
parser.add_argument('-a', '--arg1', help="An example argument")
return parser.parse_args(sys.argv[1:])
def main():
args = get_args()
check = Check()
# Implement check logic and add metrics here
# e.g.
check.add_metric(
name="metric_name",
value=0,
unit="",
warning_threshold=0,
critical_threshold=0,
display_format=None,
display_in_perf=True,
display_in_summary=True,
display_name=None,
convert_metric=None,
si_bytes_conversion=False,
summary_precision=2,
perf_data_precision=2,
message="All OK",
)
check.final()
if __name__ == "__main__":
main()
Python without plugnpy Copied
#!/opt/opsview/python3/bin/python
import sys
import argparse
import json
import select
def get_args():
no_stdin = True
data = select.select([sys.stdin], [], [], 0.0)[0]
if data:
data = data[0].readlines()
if data:
first_line = data[0].strip()
if first_line:
try:
args = json.loads(first_line)['cmd']
no_stdin = False
except (json.JSONDecodeError, KeyError):
print(
f"ERROR: Failed to parse secure args JSON from STDIN and extract 'cmd' key"
)
sys.exit(3)
if no_stdin:
args = sys.argv[1:]
if len(args) > 0 and not '--help' in args and not '-h' in args:
print(
"WARNING: This script supports secure args passing via STDIN. "
"You have passed arguments on the command line. "
"Please update your configuration to pass secure args via STDIN."
)
parser = argparse.ArgumentParser()
# Add arguments here:
# e.g.
parser.add_argument('-a', '--arg1', help="An example argument")
return parser.parse_args(args=args)
def main():
args = get_args()
# Implement check logic and add metrics here
# e.g.
status = 0
return status
if __name__ == "__main__":
sys.exit(main())
Perl Copied
#!/bin/perl
use warnings;
use strict;
use IO::Select;
use JSON qw( decode_json );
# Support for optional arguments over STDIN
my $no_stdin = 1;
my $select = IO::Select->new();
$select->add( \*STDIN );
my $json = "";
if ( $select->can_read(0) ) {
$json = <STDIN>;
if ( defined $json && $json ne "" ) {
my $args_hash;
eval {
$args_hash = decode_json( $json );
1;
} or do {
print "ERROR: Failed to decode JSON from STDIN.\n";
exit 3;
};
if ( exists $args_hash->{cmd} ) {
my $argv = $args_hash->{cmd};
if ( ref($argv) eq "ARRAY" ) {
@ARGV = @$argv;
$no_stdin = 0;
}
} else {
print "ERROR: Missing 'cmd' key in JSON from STDIN.\n";
exit 3;
}
}
}
if ( $no_stdin ) {
if ( $#ARGV >= 0 && !grep( /^--help$/, @ARGV ) && !grep( /^-h$/, @ARGV ) ) {
print "WARNING: This script supports secure args passing via STDIN. ",
"You have passed arguments on the command line. ",
"Please update your configuration to pass secure args via STDIN.\n";
}
}
# Implement script using @ARGV as normal
print "Args: @ARGV\n";
exit 0;
BASH Copied
#!/bin/bash
# Requires jq and bash 4
if [ $# -eq 0 ]; then
read -r json;
readarray -t args < <(echo $json | jq -rc '.cmd[]')
else
args=("$@")
if [[ " ${args[*]} " =~ [[:space:]]--help[[:space:]] || " ${args[*]} " =~ [[:space:]]-h[[:space:]] ]]; then
echo "Usage: help text goes here..."
else
echo "WARNING: This script supports secure args passing via STDIN."
echo "You have passed arguments on the command line."
echo "Please update your configuration to pass secure args via STDIN."
fi
fi
set -- "${args[@]}"
# Implement script as usual using $@
echo "Args: $@"
exit 0