Use keyring for all config based passwords/users

Registered by Joshua Harlow

Instead of having config files with passwords/users in them (which is bad) there should be some integration with the standard keyring providers in various operating systems, this python project @ http://pypi.python.org/pypi/keyring seems to provide some of this. It seems like openstack common should provide a little helper class to allow config to use that, for sections of config that need to be "secure", ie for a start, users and passwords should not be in clear-text (at least the passwords for stage 0).

Blueprint information

Status:
Not started
Approver:
Mark McLoughlin
Priority:
Low
Drafter:
Yahoo Openstackers!
Direction:
Approved
Assignee:
None
Definition:
Approved
Series goal:
None
Implementation:
Unknown
Milestone target:
None

Related branches

Sprints

Whiteboard

Certainly seems like a reasonable idea, but we need a much more detailed plan and proof-of-concept code to make progress here.

--

Grizzly design summit session: https://etherpad.openstack.org/grizzly-common-rootwrap-and-keyring

Conclusion was to discuss on the mailing list and prove the idea in Nova first. Once proven and other projects are keen to adopt it, we can move it into Oslo.

--

I've got a working prototype that I'm hoping to check in shortly. Here's the basic approach.

In openstack/common/cfg.py...

1. Define a 'secure_source' option (No default). If not specified, then none of the secure actions will be taken. If specified, we assume it's a keyring class that supports 'get_password'. IOW, leave this out of your nova.conf and things will behave just as they always have.
2. Add a new parameter to Opts __init__ method, 'secure' (default to False). 'secure' will also imply 'secret' to make sure it doesn't get logged.
3. In class ConfigOpts, method _do_get, before we check the config parser, if an option is defined as secure *and* we have a defined secure source, then use the secure source's get_password method to get the value. If there's no value, then it's an error. If an option is not secure or there's no secure source, then just proceed with using the config file.

In the config file:
1. Specify a secure_source E.g....
    secure_source = keyring.backend.UncryptedFileKeyring
2. Use nested variables for things like db passwords in sql_connection. E.g...
   sql_connection = mysql://nova:$db_nova_password@dbhost...:3306/nova

In the user module:
1. Define the nested password config options as secure. E.g.
    cfg.StrOpt('db_nova_password',
               secure=True,
               help='The secure password to used to connect to the '
                    'database'),
2. (Optional) Provide your own keyring extension.

Before running:
1. Install/configure keyring and populate the key file with the keys and passwords.

Following these steps, I was able to have the Nova process talk to MySQL without having the password embedded in nova.conf's sql_connection setting.

Thoughts?

I hope to have the prototype code checked in for your comments early next week.

--

I've suggested in https://review.openstack.org/18357 that we can implement this with a simple Keyring class which wraps a ConfigOpts instance:

  from openstack.common import cfg
  from openstack.common import keyring

  opts = [
      cfg.StrOpt('password',
      default=guest,
      secret=True),
  ]

  CONF.register_opts(opts, group='rabbit')
  KEYRING = keyring.Keyring(CONF)

  class Connection(object):

      def __init__(self):
          params = {
              'hostname': hostname,
              'port': port,
              'userid': CONF.rabbit.userid,
              'password': KEYRING.rabbit.password,
              'virtual_host': self.conf.rabbit_virtual_host,
         }

--

I still have a lingering concern about this. It seems like people are unlikely to use any of the stock python-keyring backends with OpenStack. Which means this is purely about allowing people to add proprietary backends. That's fine in itself, but it just means the feature will see limited real-world testing.

(?)

Work Items

This blueprint contains Public information 
Everyone can see this information.