In Puppet, how would I secure a password variable (in this case a MySQL password)?

I am using Puppet to provision MySQL with a parameterised class:

class mysql::server( $password ) {

        package { 'mysql-server': ensure => installed }
        package { 'mysql': ensure => installed }

        service { 'mysqld':
                enable => true,
                ensure => running,
                require => Package['mysql-server'],
        }

        exec { 'set-mysql-password':
                unless => "mysqladmin -uroot -p$password status",
                path => ['/bin', '/usr/bin'],
                command => "mysqladmin -uroot password $password",
                require => Service['mysqld'],
        }
}

How can I protect $password? Currently, I removed the default world readable permission from the node definition file and explicitly gave puppet read permission via ACL.

I'm assuming others have come across a similar situation so perhaps there's a better practice.


Solution 1:

When working with Puppet and MySQL, I tend to put the root password in /root/.my.cnf, lock this file down, and then restrict SSH access onto the database server.

Yes, storing the root password on the db server in clear text isn't the most secure solution. However if you write the mysql root password in this file, securing the mysql root account to allow logins from localhost only will keep the password out of puppet, and also out of the process list ps table.

Additionally, if someone has root access to read the file at /root/.my.cnf, then they probably also have access to stop the local MySQL daemon and restart the daemon without the users table to gain immediate root access to the database.

Solution 2:

Someone else can likely point out some plug-in or similar that corrects me, but the general way to go about this is to store the encrypted password, not the plain text password.

However, I can tell you right now, MySQL doesn't allow you to use an encrypted password--otherwise, that WOULD be the password, and the hash would allow you to login anyways.

There are a lot of "hacks" around that allow you to use third-party utilities such as Hiera and GPG. Obviously, you can roll your own--but even Puppet's own mailing lists suggests this method.

Solution 3:

You didn't specify who you are protecting this password from. I'm going to assume it's other sysadmins or possibly developers who have access to the puppet master and/or the client boxes but don't need to know the root password.

For setting the password initially, you could use this syntax:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY PASSWORD '*6DF1FC54F0CCD999F55D59D3D88526878230C77C' WITH GRANT OPTION;

Which would allow you to store an encrypted password in your puppet configuration instead of a plaintext one.

For using mysqladmin and the mysql client on the command line, the best I can think of is to add a .my.cnf file to your puppet config that gets deployed into an appropriate user's home directory. The file both in the puppet master and on the clients should have appropriate, restrictive file permissions.

There are plenty of ways around those file permissions when you add puppet into the mix (such as writing an exec() that pulls the file from the clients) but it would seem to be an improvement over storing the password in a world readable file. This would be more difficult if you use a versioning system for your puppet config.