Details
-
Bug
-
Status: Resolved
-
Major
-
Resolution: Fixed
-
2.2.1
Description
To provide some background, we are setting up a VCL system for several institutions, using multiple, physically distributed management nodes (each located at different institutions). Each management node will control its own VMware infrastructure of one or more hosts while all accessing the central vcl database.
As you know, each VMhost draws its configuration information from the `vmprofile` table, including information for accessing that VMhost infrastructure. For vSphere-based systems, the management node extracts login credentials from the `username` and `password` fields. The other API modules do not require the password field. The problem, however, is that the passwords are stored in cleartext.
Yes, cleartext.
This means that if the VCL is using the vSphere API, anyone from institution X who has access to the VCL database could easily access the login credentials for the VM Host(s) at institution Y. The other issue is that these passwords are being transferred in cleartext between database and management nodes, so anyone listening in on the wire could also, potentially, gain access to the VMware infrastructure. Furthermore, while the passwords are masked in the web UI behind 'password' fields, the ajax call that populates those fields can easily be inspected in order to get the actual text. I can see how this isn't such an issue if a VCL system is running within a single institution inside a single network, but in our case, that is not the situation.
A compounding issue is that the web UI allows admins to enter the passwords for VMhost profiles, which means that there would need to be a mechanism for making sure that the password for the VMprofile at institution X isn't encrypted using the same key as the password for the corresponding profile at institution Y.
To solve this, I have written some code that performs asymmetric key encryption so that the passwords are stored in a more secure format. Attached are the relevant patch files.
Effectively, what I have done is add three fields to the `vmprofile` table:
rsa_pub: a string containing a public key
rsa_key: the location of the corresponding private key (i.e. "/etc/vcl/vmhost01.key")
encrypted_passwd: the RSA-encrypted password. (There isn't a strong reason to have this be a separate field from the existing password field, but separating the two made it easier to test.)
Next, I added additional input fields in the VMProfile UI for accepting rsa_pub and rsa_key. I have also updated the javascript code to support this. If an RSA public key is supplied, the vm.php file will encrypt the incoming password using the openssl_* functions that come with most distributions of PHP. The encrypted password is stored in the `encrypted_passwd` field and the `password` field is set to NULL. This causes the web UI not to show the masked passwords, which is a behavior that I preferred to have, though others may prefer something different. The encryption function was put in utils.php and called encryptDataAsymmetric($data, $public_key) – it more or less follows the style of the existing encryptData($data) function.
Finally, vcld needs to be able to decrypt the data, so I added some code to VCL::utils. First, I expanded the vmhost/vmprofile SQL statement to include the new rsa_key and encrypted_passwd fields. Then, vcld will check whether a key exists in the location specified, and if so, it will use that key to decrypt the password. The decrypted password is then put into the data structure in the expected location: vmprofile.password
The perl code relies on one additional library: Crypt::OpenSSL::RSA, which has its own set of dependencies, but these are all available on the EPEL repository or CPAN. I would add that the Crypt::OpenSSL::RSA library is quite mature and well maintained.
I wrote this code so that it is entirely optional to encrypt passwords. If an RSA public key is not attached, then no encryption is performed: the password is stored, as before, in cleartext in vmprofile.password. If the private keyfile does not exist on a management node, then no decryption is performed, and the existing value of vmprofile.password is used. I should also add that the encrypted passwords are stored in hexadecimal format, since that is easier to deal with when it comes to storing them in a database.
In order to use this code, one will need to generate RSA keys ahead of time like so:
$ openssl genrsa -out vmhost.key 1024
$ openssl rsa -in vmhost.key -pubout > vmhost.key.pub
(One can generate a larger key, if desired, by specifying a larger bit size in the first command.)
It is a good idea to control access to the private key:
$ chown root.root vmhost.key
$ chmod 600 vmhost.key
An admin will also need the contents of the public key to enter into the web UI:
$ cat vmhost.key.pub
Attachments
Attachments
Issue Links
- relates to
-
VCL-647 Warning generated if vmprofile.rsakey is not defined
- Resolved