Salt: preseed keys on virtual machines

Publié le lun. 27 janvier 2014 par Feth Arezki

Introduction

How about provisionning a new virtual machine and never ever touch it but through Salt? That should be easy, but we have a problem: every salt minion has its own ssh and salt private and public keys, and we need that somehow

  1. a key pair be generated,
  2. the private key be only on the minion,
  3. the master to know the public key,
  4. automagically, every time.

Having read the tutorial on preseeding keys I came up with a snippet that fits in our bootstrap script for Autonomie −after that, we just assign some salt role and… lift up! So, this is pretty much inspired from the aforementioned tutorial, I just added the missing link; it may require some polish, please be careful at what you do.

This is a step-by-step explanation of a bash script. It does not cover all the cases, but hopefully it is understandable; I think it is small enough.

Requirements

This is possible thanks to the excellent libvirt, Qemu-KVM and libguestfs-tools.

We make use of two variables:

  • my VM is named $NAME -hostname, minion_id and virtual machine name,
  • my virtual disk is named $DISK, this is the place where your qcow2 (virtual disk) file lies. If you have several qcow files per machine, you will need to adapt your workflow.

Now put your coverall

Optional: work on the physical host, in a tmpfs

Generating the keys this way is optional, perhaps you don't agree. In this case, jump to the key generation. My point is that my best random source (still doubtful, but well), is my hardware, not my virtual machines. And as it is better not to write private keys on a hard drive where I don't want them to stay, I only write them in memory (still, that's not a perfect security measure, especially since the virtual disks are likely to be stored… on the same physical disk -at least I feel better for writing them only once).

Preparation:

# Let the script fail if something exits != 0
set -e
# Also if a variable is not defined
set -u

MEM_KEY_SPACE=20M
TMPFSDIR=`mktemp -d`

This function is called whenever the script exits (unless you pull the cord, but then the memory should _normally_ be erased as well).

function cleanup {
    set +e
    set +u
    # we're going to mount that tmpfs dir later
    umount $TMPFSDIR
    rm -fr $TMPFSDIR
}

This function is called upon error, we also delete the qcow image, why should we keep it?

function abort {
    set +e
    set +u
    rm -f ${DEST}
    cleanup
}

Now let's setup the cleanup and abort callbacks.

trap cleanup EXIT
trap abort SIGHUP SIGINT SIGTERM

Mount a tmpfs:

mount -t tmpfs -o size=${MEM_KEY_SPACE} tmpfs $TMPFSDIR

And let's jump in it safely, in a subshell (enclosed in parens -don't forget the closing one after the key generation and copy).

(
cd $TMPFSDIR

Safe (?) generation of the keys

That part is fast and covered in the original tutorial.

Salt key:

salt-key --gen-keys=minion

This conveniently produced a minion.pub and a minion.pem files.

Let's register the public salt key (we're working on the master) :

cp minion.pub /etc/salt/pki/master/minions/$NAME

SSH keys:

ssh-keygen -q -N "" -t dsa -f ssh_host_dsa_key
ssh-keygen -q -N "" -t rsa -f ssh_host_rsa_key
ssh-keygen -q -N "" -t ecdsa -f ssh_host_ecdsa_key

Copy of the keys

This is also very fast, thanks to guestfish. This covers virtual machines specifically.

guestfish -a ${DEST} --rw -i <<_EOF_
copy-in minion.pub minion.pem /etc/salt/pki/minion/
copy-in ssh_host_dsa_key ssh_host_rsa_key ssh_host_ecdsa_key /etc/ssh
_EOF_

Get out of the subshell

That's only if you did the optional gym that provides you with slightly better security.

)

:-)

Yeah, it works

We'll start the VM and sleep for a few seconds to see how it goes.

SLEEPSECS=10
virsh start ${NAME}
sleep $SLEEPSECS
salt ${NAME} test.ping

Now, just assign some roles to this minion, run the highstate and clap along if you feel happiness because your job is done!

Here is a full bash script; you want to fix and adapt it to your needs: