Secure Properties is a new feature that was introduced in ACLI 11.0.0 with the intent of helping to better secure the credentials required to access the products and systems on which ACLI actions operate.
π€ Problem
ACLI loads the necessary system credentials it needs to do its work from configuration found in acli.properties
. These credentials have historically been stored either directly in this file as plain text, or indirectly provided to the configuration by environment variable references. While indirection via the environment can help protect credentials, better solutions exist.
Despite the fact that ACLI sets restrictive file permissions on the acli.properties
configuration file (since version 10.6.0), some customers want a higher level of credential security than this can provide since escape of the configuration file could result in direct compromise of the credentials it contains.
π± Solution
ACLI 11.0.0 introduces a new feature known as Secure Properties that provides a key-store-based credential storage solution using password based encryption (PBE). The specific key store format utilized is the Bouncy Castle provided UBER format. The use of secure properties is optional!
The intent of the secure properties key store is to protect sensitive credentials from being stored as plain text on disk, but it can store any values you wish.
Creating a key store
A new key store is created when the action setSecureProperty
is run for the first time. For example:
$ acli system setSecureProperty --name my.secret --secret - Enter secure value: <secret value prompt> Secure properties file does not yet exist. Creating... Enter new secure properties password: <new password prompt> Confirm secure properties password: <new password prompt> Remember your password, it cannot be recovered! Secure properties file created. Value for key 'foo' set in secure properties file.
The value for the --secret
parameter in this example is provided as -
which indicates that the value should be obtain via an interactive prompt (or read from stdin
if not connected to a tty). We strongly recommend providing sensitive values this way so that they are not accidentally recorded in your shell history, where they would end up existing in plain text anyway!
Breaking this down, you can see that first ACLI will prompt for the value of the secret to be stored, and then it will prompt for the new key store file password (with confirmation).
The key store requires a non-blank password. Once created, do not forget the password!
Key store passwords cannot be recovered by ACLI support.
If your password is ever compromised, you should consider the contents of the key store to also be compromised and rotate any secrets it contains accordingly.
Once created, the key store file (named .acli.keystore
) can be found in your home directory. Each ACLI user on a given system has their own such file (because of other ACLI limitations, it is still necessary on a multi-user system for each user to maintain their own ACLI installation). The key store file path can be overridden to point to an alternative location through the use of the environment variable ACLI_SECURE_PROPERTIES
. This can be useful if you need to work with multiple key stores or multiple installations of ACLI, but typically should not be needed.
Referencing secrets in acli.properties
When in use, the key store file can be used to provide values to acli.properties
by way of substitution variables similar to the current method of referring to environment variables or other properties (i.e., using ${my.variable}
syntax). In ACLI 11.0.0, the default syntax for referring to key store values is with a variation of that syntax of the form ${secret:my.secret}
(note the addition of the secret:
prefix).
Because the key store is password-protected, we require the secret:
prefix in order to consult the key store only when necessary. This requirement can be disabled by setting the environment variable ACLI_SECURE_PROPERTIES_SAFE_MODE=false
. When disabled, the key store will be consulted for any variable names not found in acli.properties
itself or the environment, but this may result in an interactive prompt to supply a password!
Unlocking the key store
When a secret variable needs to be resolved during configuration loading, they key store must be unlocked to proceed. Normally, this means that ACLI will prompt you interactively for your key store password before it continues (or read it from stdin
when not connected to a tty). At your discretion, you may optionally short-circuit this prompting behavior by setting the environment variable ACLI_SECURE_PROPERTIES_PASSWORD
with your password as a variable.
Setting your key store password as an environment variable may or may not be appropriate, depending on your risk tolerance. Doing so is a convenience, but one that comes at a cost of reduced security. You still have the advantage that if your key store file escapes your system it is strongly encrypted, but the storage of your key store password as an environment variable may make it easier to compromise your key store in a sophisticated attack.
Whether you decide this is an acceptable risk is entirely at your discretion, and depends on the threat modeling under consideration by you and your organization. Use this method at your own risk.
Actions
ACLI actions can be used to create, update, read, and delete key-value pairs stored in the secure properties key store. These actions are all part of the ACLI system
client:
setSecureProperty
This action sets or overwrites a secure property in the key store. If a property name already exists, you will be prompted to confirm that you wish to overwrite the value. Use --replace
to skip the confirmation prompt.
getSecureProperty
This action will get a secure property from the key store. By default it will only report whether or not the property was found in the key store. To also return the value, use --outputFormat 2
.
removeSecureProperty
This action will remove a secure property from the key store. In order to ensure that a value is not easily removed by mistake, you will be prompted for confirmation unless you also add the --force
parameter. If the key store is empty after this operation, it is automatically removed.
getSecurePropertyList
This action returns all secure properties from the key store. By default it will only report the existing property names. To also return their values, use --outputFormat 2
.
clearSecureProperties
This action clears the entire secure properties key store file. In order to ensure you donβt casually destroy the file, you will be prompted for confirmation unless you also add the --force
parameter.
You may be prompted for the key store password to complete this action. If you have forgotten the password and wish to start fresh, you must manually delete the key store file (see above for location information).
importSecureProperties
This action allows you to import secure properties from another key store file to your default key store. You will need the password for both the source and destination key stores. To avoid being asked to confirm overwriting properties during import, use the --replace
parameter. You may also use the --include
and --exclude
parameters to filter the properties being imported β each of these take a regular expression value that is evaluated against the list of keys in the source key store.
This can be useful for sharing select secure properties, just be sure to not store or transmit the password with the data!
exportSecureProperties
This action allows you to export secure properties from your default key store to another key store file. You will need the password for both the source and destination key stores. To avoid being asked to confirm overwriting properties during import, use the --replace
parameter. You may also use the --include
and --exclude
parameters to filter the properties being imported β each of these take a regular expression value that is evaluated against the list of keys in the source key store.
Examples
Set a secure property
$ acli system -a setSecureProperty --name my-jira.token --secret - Enter secure properties password: <password prompt> Value for key 'my-jira.token' set in secure properties file.
Get a secure property
$ acli system -a getSecureProperty --name my-jira.token Enter secure properties password: <password prompt> Secure property 'foo' exists in the secure properties file.
Get a secure property with value
$ acli system -a getSecureProperty --name foo --outputFormat 2 Enter secure properties password: <password prompt> Value of secure property 'my-jira.token': <your token value>
Get secure property list with values
$ acli system -a getSecurePropertyList --outputFormat 2 Enter secure properties password: 2 secure properties in list "Name","Value" "buz","qux" "foo","foo"
Use a secure property in acli.properties
my-jira = jiracloud -s https://myjira.atlassian.net -u me@example.com -t ${secret:my-jira.token}
Remove a secure property
$ acli system -a removeSecureProperty --name my-jira.token Enter secure properties password: <password prompt> Enter CONFIRM to permanently remove the secure property 'my-jira.token': CONFIRM Removed value for key 'my-jira.token' from secure properties file. Deleted empty keystore file.
Clear all secure properties
$ acli system -a clearSecureProperties Enter secure properties password: <password prompt> Enter CONFIRM to permanently clear all secure properties (CANNOT be undone): CONFIRM Secure properties cleared.
Import secure properties
$ acli system -a importSecureProperties -f import.keystore Enter secure properties password: <destination password prompt> Enter inbound secure properties password: <source password prompt> Imported 0 secure properties. Ignored: buz,foo. Use --replace to overwrite existing values.
Import select secure properties (via inclusion) with overwrite
$ acli system -a importSecureProperties -f import.keystore --include '(?i)^F' --replace Enter secure properties password: <destination password prompt> Enter inbound secure properties password: <source password prompt> Imported 1 secure property: foo.
Export select secure properties (via exclusion) with overwrite
$ acli system -a exportSecureProperties -f export.keystore --exclude '(?i)^F' --replace Enter secure properties password: <source password prompt> Enter outbound secure properties password: <destination password prompt> Exported 1 secure property: buz.