Sekred a password helper for puppet.

Puppet is a nice tool but it has a significant problem with passwords:

  • it is recommended to store puppet manifests (*.pp) and related files in a VCS (i.e. git)
  • it is not recommended to store password in a VCS

This lead to complex situation and various workaround that more or less work:

  • serve password in a separate file/DB or do an extlookup on the master (pre-set passwords)
  • store password on the server and get them through a generate function (random password but on the master)

Most of these workarounds are complex, don't allow you to share the password you have set easily and most of the time are stored in another place than the target node.

So I have decided to create my own solution: sekred (LGPL-2.1).

The idea of sekred is to generate the password on the target node and made it available to the user that needs it. Then the user just have to ssh into the host and get the password.

Pro:

  • the password is generated and stored on the node
  • no VCS commit of your password
  • no DB storage of your password beside the local filesystem of the host
  • no need to use a common pre-set password for all you host, the password is randomly generated for only one host
  • to steal the password you need to crack the host first but if you have root access on the host, accessing a random generated password is pointless

Cons:

  • the password is stored in clear text
  • the password is only protected by the filesystem ACL

Let see some concrete examples.

Setting mysql root password

This is a very simple problem. When you first install mysql on Debian Squeeze, the root password is not set. That's bad. Let set it using sekred and puppet.

node "mysqlserver" {

  package {
    ["mysql-server",
     "mysql-client",
     "sekred"]:
      ensure => installed;
  }

  service {
    "mysqld":
      name => "mysql",
      ensure => running,
      hasrestart => true,
      hasstatus => true;
  }

  exec {
    "mysql-set-root-password":
      command => "mysqladmin -u root password $(sekred get root@mysql)",
      onlyif => "mysql -u root",  # Trigger only if password-less root account.
      require => [Service["mysqld"], Package["mysql-client", "sekred"]];
  }
}

And to get the root password for mysql, just login into the node "mysqlserver":

$> sekred get root@mysql
Cie8ieza

Setting password for SSH-only user

This example is quite typical of the broken fully automated scenario with passwords: - you setup a remote host only accessible through SSH - you create a user and set its SSH public key to authorize access - your user cannot access its account because SSH prevent password-less account login!

In other word, you need to login into the node, set a password for the user and mail him back.... That defeats a little bit the "automation" provided by puppet.

Here is what I do with sekred:

define user::template () {
  user {
    $name:
      ensure => present,
      membership => minimum,
      shell => "/bin/bash",
      ....
  }
  include "ssh_keys::$name"

  # Check password less account and set one, if required.
  $user_passwd="$(sekred get --uid $name $name@login)"
  exec {
    "user-set-default-password-$name":
      command => "echo $name:$user_passwd | chpasswd",
      onlyif => "test \"$(getent shadow $name | cut -f2 -d:)\" = \"!\"",
      require => [User[$name], Package["sekred"]];
  }
}

So the command "test \"$(getent shadow $name | cut -f2 -d:)\" = \"!\"" test for a password-less account. If this is the case, it creates a password using sekred get --uid $name $name@login and set it through chpasswd.

Note that $user_passwd use a shell expansion that will be evaluated when running the command only, on the host. The --uid flag of sekred assign the ownership of the password to the given user id.

So now the user (foo) can login into the node and retrieve its password using sekred get foo@login.

Try it!

Sekred was a very short project but I am pretty happy with it. It solves a long standing problem and helps to cover an extra mile of automation when setting up new nodes.

The homepage is here and you can download it here. Feel free to send patches, bugs and feature requests (here, login required).

Comments

1. On Friday, April 5 2013, 18:16 by Np237

At work we use a different scheme: we push a GnuPG public key, the password is generated on the target node, encrypted with that key, and pushed to a FTP server.

You can extract the password at the time you actually need it (which is, not often).

2. On Friday, April 5 2013, 23:26 by gildor

Np237:

The GnuPG idea is nice. Sekred is aiming 2-tech levels below that (i.e. no encryption and no FTP push). I think your solution is more secure but needs more stuff to configure...

Your solution has another problem, with regard to one of the example: setting a password for root@mysql. I use the generated root password to create other user and DB. If you encrypt the password for a GPG key, I suppose you cannot read it back on the target node?

3. On Sunday, April 7 2013, 05:22 by choonming

I'm not sure whether you are aware of this but Puppetlabs have integrated hiera with the latest Puppet 3 codebase.

It is very similar to what you are trying to achieve here but only better since its already built in with Puppet. Furthermore you can secure the hiera data directories with hiera backends like hiera-gpg.

Just my 2 cents

4. On Wednesday, April 10 2013, 13:51 by gildor

+choonming:

Following your advice, I had a look at Hiera. It seems to indeed cover part of what sekred do. It miss the "generate only on the host" and you'll have to inject the password at some point in the DB (although you can probably create a dedicated backend for that). 

Although, I mainly target Debian and puppet 3.X is only part of experimental (not even unstable). So hiera is at least 1 or 2 year away from my day to day usage.

Anyway, thanks for the valuable pointer.

They posted on the same topic

Trackback URL : http://sylvain.le-gall.net/blog/index.php?trackback/79

This post's comments feed