Password Protection for Non-Java Applications
This section describes an alternative mechanism that non-Java applications can use to access the key and trust store passwords.
- Passwords needed to access the PKCS#12 key and trust stores
- Private keys that are encrypted with a key store password
maprkeycreds.conf
and trust store passwords in
maprtrustcreds.conf
in ${MAPR_HOME}/conf
.
${MAPR_HOME}/conf
is created by the ${MAPR_HOME}/conf/configure.sh
-genkeys
script.maprkeycreds.conf
and
maprtrustcreds.conf
file is is shown
below.<password property>=ENC:<code>:<checksum>:<Base64 encrypted password>
Key | Description |
---|---|
password property |
The password property in ssl-client.xml or
ssl-server.xml . For example:
ssl.server.keystore.password
|
ENC |
Indication that the password is encrypted. |
code |
Encryption code to denote the type of algorithm used for encryption. For
release 7.0.0, the code is always 1 to denote AES-256-CTR using
PBKDF2 with 20000 iterations. The password used to derive the encryption key is
obtained in an identical way from the Hadoop Credential Provider API (it is obtained
from the value of the environment variable
HADOOP_CREDSTORE_PASSWORD and defaults to none
if HADOOP_CREDSTORE_PASSWORD is not set). |
checksum |
The SHA-256 checksum used to verify that the password is correctly decrypted. Upon decryption, the application should compute the SHA-256 checksum on the decrypted password and verify that it matches this checksum. |
Base-64 encrypted password |
The encrypted password in Base-64 encoding. |
pwd
/opt/mapr/conf
cat maprkeycreds.conf
ssl.server.keystore.password=ENC:1:b8f9933aa5af6d9d2c0706fec5156fba5233546ac3bce8213524353b5c70c42f:U2FsdGVkX1+OYGv5p/2c3nYXw3u2EYax2N9Y7GpfQKeifFkskdDYA17XEqUkinAf7Q==
ssl.server.keystore.keypassword=ENC:1:b8f9933aa5af6d9d2c0706fec5156fba5233546ac3bce8213524353b5c70c42f:U2FsdGVkX18LDAUdN66mdVxmt8k8xQo2vAnQJ5xw7V/enAOq3fQ1NVXOPpi1J027Bg==
ssl.server.truststore.password=ENC:1:e7a15c233a1252a17e6a8a07c2cb397017ecd939224593d2327d381cbb56ab54:U2FsdGVkX1+sPmXLhP26sPWC3mi2MD6yRYeVnFOauBEnPVd69+rGuPE2qoxFcXoJ9A==
openssl
command to decrypt the password. In the
following example, replace the default decryption key of none
with the actual
decryption key, which is either the value of the environment variable
HADOOP_CREDSTORE_PASSWORD
or the default value none
. For
example: echo
"U2FsdGVkX18Qbi4OXoFrPDjQhVtJAzzP+fsyHmAgXKcz5OanmpaQZIOfpNENlZPwIw==" | openssl enc -aes-256-ctr -iter 20000 -pass pass:none -base64 -md sha256 -A -d
8M2HdpkZxjb1QLVHG2lx_Dtg_bg870gS
openssl dgst
command to obtain the SHA-256 signature of the decrypted password. Then verify that it
matches the value configured in the checksum field in maprkeycreds.conf
or
maprtrustcreds.conf
. For example:
echo "8M2HdpkZxjb1QLVHG2lx_Dtg_bg870gS" | \
openssl dgst -sha256 | awk '{print $2}'
b8f9933aa5af6d9d2c0706fec5156fba5233546ac3bce8213524353b5c70c42f
common-ecosystem.sh
, which is already used by most MEP/EEP components, now
includes a routine that implements the above steps. Its interface looks like the
following:getStorePw() {
# routine expects 2 or 3 inputs
# key to lookup - like ssl.server.keystore.password
# file to look in - like /opt/mapr/conf/maprkeycreds.conf
# optional password, if not provided, $HADOOP_CREDSTORE_PASSWORD is used if set,
# otherwise none
#
# returns pw on success otherwise error messages
# rc=0 on success - 1 otherwise
#
# called like:
# pw=$(getStorePw ssl.server.keystore.password /opt/mapr/conf/maprkeycreds.conf)
# if [ $? -ne 0 ]; then
# echo "got an error: $pw"
# ...
# fi
configure.sh
(or supporting script) must deal with both
environments. Example usage would look like the following (assume
maprKeyCredsConf
is set to
$MAPR_HOME/conf/maprkeycreds.conf
):keystorePass="$(grep -F -A 1 ssl.server.keystore.password $sslServerConf | tail -1 | sed 's/ *<value>//;s/<\/value>//')"
if [ "$keystorePass" = "__##CREDENTIALS_STORE##__" ] || [ -z "$keystorePass" ] && [ -e "$maprKeyCredsConf" ]; then
keystorePass=$(getStorePw ssl.server.keystore.password $maprKeyCredsConf
rc=$?
if [ $rc -ne 0 ]; then
echo "Failed to extract keystore password: $keystorePass"
fi
fi
Similar code is expected to be done for the trust store password.
In addition, if a non-Java EEP component requires a private key in PEM format, additional work is required to protect the unencrypted private key or the password for the encrypted private key.
For a component that requires an unencrypted private key pem file, the requirement is that its init/start script must generate the pem key, start the process, and then remove the key after the process is up and running. This assumes that the service does not negatively react to the change in the key file (from containing the key to empty).
Using Grafana, which needs an unencrypted private key, as an example, you can generate an
empty key PEM file during configure.sh
stage. After Warden starts Grafana,
the Grafana init/start script extracts the keystore password, and uses that to decrypt the
encrypted pem key. Then it puts the unencrypted private key into the key.pem
file that Grafana requires right before it is started. Additional code is added to the
init/start script to detect when the service is fully up and has read the pem key, before
zeroing out the file. On an unsuccessful start, the pem key file is also zeroed out.
Similarly, for a service that can use an encrypted private key, but reasonably requires the password for the key in a config file, the password in the config file should only be there during startup. The init/start script must then aquire the required password, edit the config file to fill it in, start the process, and then remove it from the config file. (This only works for processes that do not monitor changes in the config file and restart.)