This is a text-only version of the following page on https://raymii.org: --- Title : OpenStack nova get-password, set-password and post encrypted password to metadata service Author : Remy van Elst Date : 25-03-2018 URL : https://raymii.org/s/tutorials/OpenStack_nova_get_-_password_set_-_password_and_post_encrypted_password_to_metadata_service.html Format : Markdown/HTML --- When you create images for an OpenStack Cloud you want to use 'cloud' features. Fancy term for automatic resizing of your instance disk, adding an SSH key, (re)setting passwords and executing scripts on first boot to configure your instance further. OpenStack provides the metadata service for instances, which supplies information for the instance, like its public IP, SSH public key that was provided and vendor or user provided data like scripts or information. The OpenStack metadata service allows an instance to post data to an endpoint wich can be retreived with the `nova get-password` command. It is meant to be an encrypted password (with the public SSH key) but it can be any plain text as well and it doesn't have to be the root password. In this guide I'll go over the scripts I use inside linux images to post a password to the metadata service and the `nova` commands such as `set-password` and `get-password`. That includes decrypting a password with an SSH key that is password-protected (Horizon and nova don't support that) and the `nova set-password` command, which sets the root password inside an instance when it has the `qemu-guest-agent` installed and running.

Recently I removed all Google Ads from this site due to their invasive tracking, as well as Google Analytics. Please, if you found this content useful, consider a small donation using any of the options below:

I'm developing an open source monitoring app called Leaf Node Monitoring, for windows, linux & android. Go check it out!

Consider sponsoring me on Github. It means the world to me if you show your appreciation and you'll help pay the server costs.

You can also sponsor me by getting a Digital Ocean VPS. With this referral link you'll get $100 credit for 60 days.

The first section of the guide goes over the `nova get-password`, `nova set- password` and the manual decryption of the password. The second part of the article shows the script I use to set the password inside cloud instances. ### nova get-password The `nova` command line client supports the `get-password` command. This command only works when a password has been posted to the metadata service (by the instance). $ nova help get-password usage: nova get-password [] Get the admin password for a server. Positional arguments: Name or ID of server. Private key (used locally to decrypt password) (Optional). When specified, the command displays the clear (decrypted) VM password. When not specified, the ciphered VM password is displayed. Using it on a server that has a password set in the metadata service: $ nova get-password $instance_uuid Output: bPLUcppp+MXbiO4kFMsIZ1zj4VbS/1kfafWTvqPBKr3B5Rk9z0eLotwVNDGCJkXYGmDmKca0q4hWdAt03N7QZ58DbgF24cvumgQIHddT5D14M98n85oiI3yPd0DCrEhvZQb5jwmYIWBBhqDCuyl+savwFNmVEn2cxdPleCZqvIN7BHs2HRVY7esHDcPiY1+Xdq5SMa92lcsJyn8LJRUUUuq0o0k75+4TTtEWEtClXiMyURIRDgDOpVDXBl2kgeU22a/e1rRKKOKg6CasVu7g0V9fmmLC/zXRmgTqfMwZlm0wDdq0X4jRUYzRNpxLarj6AXGYoSQT6moKx9ttcNL6JQ== To decrypt it, supply the SSH private key with the command. It's a client side decryption: $ nova get-password $instance_uuid ~/.ssh/cloud_nopass.priv Output: example_password If your private key has a password, decrypting only works if you have `ssh- agent` running: $ nova get-password $instance_uuid ~/.ssh/cloud_pass.priv Output: Enter pass phrase for ~/.ssh/cloud_pass.priv: example_password This way you can even use this feature if your SSH private key is stored on a hardware token like [a NitroKey HSM][2] (smartcard), OpenPGP token like the [NitroKey Start][3] or a YubiKey. Using the Horizon dashboard you can also decrypt the password. This is also a client side operation and doesn't work if your private key is password protected. ![password][4] #### Manual decryption Using the `openssl` command line tools we can decrypt the encrypted password. It's base64 encoded so there is an extra step to decode the base64. $ echo " bPLUcppp+MXbiO4kFMsIZ1zj4VbS/1kfafWTvqPBKr3B5Rk9z0eLotwVNDGCJkXYGmDmKca0q4hWdAt03N7QZ58DbgF24cvumgQIHddT5D14M98n85oiI3yPd0DCrEhvZQb5jwmYIWBBhqDCuyl+savwFNmVEn2cxdPleCZqvIN7BHs2HRVY7esHDcPiY1+Xdq5SMa92lcsJyn8LJRUUUuq0o0k75+4TTtEWEtClXiMyURIRDgDOpVDXBl2kgeU22a/e1rRKKOKg6CasVu7g0V9fmmLC/zXRmgTqfMwZlm0wDdq0X4jRUYzRNpxLarj6AXGYoSQT6moKx9ttcNL6JQ==" \ | openssl base64 -d \ | openssl rsautl -decrypt -inkey ~/.ssh/cloud_pass.priv -keyform PEM Output: Enter pass phrase for ~/.ssh/cloud_pass.priv: example_password ### nova set-password The `nova set-password` command allows you to change the password in a server. But, only if the [qemu-guest-agent][5] is installed. $ nova help set-password usage: nova set-password Change the admin password for a server. Positional arguments: Name or ID of server. This can only be done by the owner of the instance or an OpenStack admin. It then allows you to login to the console for example. By default there is no command line output if successfull. The `set-password` command fails when a password is already set. Looking at the source code of the [metadata api][6] there is no command to remove a stored password. There is a [nova API][7] command but that is admin-only by default. $ nova set-password $instance_uuid Output: New password: Again: ERROR (Conflict): Failed to set admin password on $instance_uuid because error setting admin password (HTTP 409) (Request-ID: req-f3f6feed-4171-45d1-ab16-28a6875688d8) Following the [nova][8] [source code][9] we can see that in the case of Libvirt (KVM/QEMU) it calls [virDomainSetUserPassword][10]. So it technically would be possible to (re)set the password again but currently it's not supported. ### Post encrypted passwords to the metadata service The metadata service allows posting a password. Technically this can be any sort of (unencrypted) data that will be made visible in Horizon or the `nova get- password` command. It is recommended to encrypt this password with the users provided public key. Why? Because any code running inside the guest can access the password via the metadata service. Any web application can request the API URL and get the data: $ curl http://169.254.169.254/openstack/latest/password Output: bPLUcppp+MXbiO4kFMsIZ1zj4VbS/1kfafWTvqPBKr3B5Rk9z0eLotwVNDGCJkXYGmDmKca0q4hWdAt03N7QZ58DbgF24cvumgQIHddT5D14M98n85oiI3yPd0DCrEhvZQb5jwmYIWBBhqDCuyl+savwFNmVEn2cxdPleCZqvIN7BHs2HRVY7esHDcPiY1+Xdq5SMa92lcsJyn8LJRUUUuq0o0k75+4TTtEWEtClXiMyURIRDgDOpVDXBl2kgeU22a/e1rRKKOKg6CasVu7g0V9fmmLC/zXRmgTqfMwZlm0wDdq0X4jRUYzRNpxLarj6AXGYoSQT6moKx9ttcNL6JQ== The password is also stored on the config_drive but that requires root privileges to mount. If I post unencrypted data to that endpoint: DATA="this_is_an_example_raymii.org" curl -s -X POST http://169.254.169.254/openstack/latest/password -d $DATA Horizon (and the API) happily show that: ![][11] So that's why you want to encrypt it. What we're doing in the script is the following: * Check if password was already set, and if so, exit * Get public SSH key from metadata service. * Convert the public key to a format usable with OpenSSL * Generate random root password * Set root password (and any other user like `admin` in the case of DirectAdmin) * Encrypt the root password with the SSL keyfile * Post the encrypted password to the metadata service. There is almost no error handling, and a weary catch all in the curl (`|| true`), since this script is meant to run via `/etc/rc.local` (or via cloud- init) and a non exit 0 in rc.local can result in bootup failure. #!/bin/bash # Copyright (C) 2018 Remy van Elst. # Author: Remy van Elst for https://www.cloudvps.com # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # This script sets the root password # to a random password generated on the instance # and posts that if possible to the openstack # metadata service for nova get-password. logger "[CLOUDVPS] Started set root password and post to metadata service" if [[ -f "/var/lib/cloud/instance/rootpassword-random" ]]; then # script already ran on this instance. # /var/lib/cloud/instance/ is a symlink to /var/lib/cloud/instances/$instance_uuid # if user creates an image and deploys image, this must run again, that file will not exist exit 0 fi # Centos 6 doens't support ssh-keygen's pcks8 option. # it has OpenSSH < 5.6 if [[ -f "/etc/redhat-release" ]]; then NAME="$(awk '{ print $1 }' /etc/redhat-release)" VERSION="$(grep -Eo "[0-9]\.[0-9]" /etc/redhat-release | cut -d . -f 1)" fi # Two tmp files for the SSH and SSL pubkey SSH_KEYFILE=$(mktemp) SSL_KEYFILE=$(mktemp) # get the ssh public key from the metadata server. curl -s -f http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key > $SSH_KEYFILE if [[ $? != 0 ]]; then logger "[CLOUDVPS] Instance public SSH key not found on metadata service. Unable to set password" exit 0 fi # generate a random password # our images have haveged installed so should have enough entropy at boot. RANDOM_PASSWORD="$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -c 30)" if [[ -z ${RANDOM_PASSWORD} ]]; then logger "[CLOUDVPS] unable to generate random password." exit 0 fi # set the root password to this random password # add any other password changes like admin for DirectAdmin. echo "root:${RANDOM_PASSWORD}" | chpasswd if [[ -s "$SSH_KEYFILE" ]]; then # convert the ssh pubkey to an SSL keyfile so that we can use it to encrypt with OpenSSL if [[ ${VERSION} -eq 6 && ${NAME} == "CentOS" ]]; then logger "centos 6 doesnt support PKCS8 in ssh-keygen so we have a workaround." # our centos6 image has this file. # otherwise, https://gist.github.com/RaymiiOrg/7cd92ec7b9711fd4b9f6a1178c1bf04f python2 /etc/cloudvps/sshpub-to-rsa.py $SSH_KEYFILE > $SSL_KEYFILE else ssh-keygen -e -f $SSH_KEYFILE -m PKCS8 > $SSL_KEYFILE fi ENCRYPTED=$(echo "$RANDOM_PASSWORD" | openssl rsautl -encrypt -pubin -inkey $SSL_KEYFILE -keyform PEM | openssl base64 -e -A) # post encrypted blob to metadata service. Must return true otherwise instance might fail to boot. curl -s -X POST http://169.254.169.254/openstack/2013-04-04/password -d $ENCRYPTED 2>&1 > /dev/null || true fi # housekeeping rm -rf $SSH_KEYFILE $SSL_KEYFILE touch /var/lib/cloud/instance/rootpassword-random exit 0 #### Running the script at first boot This script can be ran at first boot of an instance using the good old trusty `/etc/rc.local` file. If you use a newer distribution with `systemd`, you can create [a unit file][12] to run this at boot. You can also leverage `cloud-init` by creating a config file: vim /etc/cloud/cloud.cfg.d/00-cloudvps-rootpasswd.cfg Add the contents: runcmd: - /bin/bash /etc/cloudvps/rootpassword-to-metadata.sh In my case the script is injected in the image on that location. You could also add a `curl` command if you use `cloud-config` (you do not control the cloud- init config but use `user-data`). [1]: https://www.digitalocean.com/?refcode=7435ae6b8212 [2]: https://raymii.org/s/articles/Get_Started_With_The_Nitrokey_HSM.html [3]: https://raymii.org/s/articles/Nitrokey_Start_Getting_started_guide.html [4]: https://raymii.org/s/inc/img/retreive_password.png [5]: https://wiki.qemu.org/Features/GuestAgent [6]: https://web.archive.org/web/20180105005659/https://github.com/openstack/nova/blob/master/nova/api/metadata/password.py#L65 [7]: https://web.archive.org/web/20180323094911/https://developer.openstack.org/api-ref/compute/#clear-admin-password [8]: https://github.com/openstack/nova/blob/master/nova/virt/libvirt/driver.py#L2072 [9]: https://github.com/openstack/nova/blob/master/nova/virt/libvirt/guest.py#L506 [10]: https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainSetUserPassword [11]: https://raymii.org/s/inc/img/get_plaintext_password.png [12]: https://raymii.org/s/tutorials/rc.local_support_on_Arch_Linux_and_systemd.html --- License: All the text on this website is free as in freedom unless stated otherwise. This means you can use it in any way you want, you can copy it, change it the way you like and republish it, as long as you release the (modified) content under the same license to give others the same freedoms you've got and place my name and a link to this site with the article as source. This site uses Google Analytics for statistics and Google Adwords for advertisements. You are tracked and Google knows everything about you. Use an adblocker like ublock-origin if you don't want it. All the code on this website is licensed under the GNU GPL v3 license unless already licensed under a license which does not allows this form of licensing or if another license is stated on that page / in that software: This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Just to be clear, the information on this website is for meant for educational purposes and you use it at your own risk. I do not take responsibility if you screw something up. Use common sense, do not 'rm -rf /' as root for example. If you have any questions then do not hesitate to contact me. See https://raymii.org/s/static/About.html for details.