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).













