From b010f9db842aadf92bc2a18629342a0e0f84b385 Mon Sep 17 00:00:00 2001 From: Timo Makinen Date: Fri, 10 May 2019 10:26:27 +0300 Subject: [PATCH] Initial version of playbook which creates virtual machines. --- .gitignore | 1 + playbooks/include/vm-create.yml | 111 ++++++++++++++++++++++++++++++++ scripts/genpasswd | 55 ++++++++++++++++ scripts/getpasswd | 24 +++++++ 4 files changed, 191 insertions(+) create mode 100644 .gitignore create mode 100644 playbooks/include/vm-create.yml create mode 100755 scripts/genpasswd create mode 100755 scripts/getpasswd diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..56fb762 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +facts/ diff --git a/playbooks/include/vm-create.yml b/playbooks/include/vm-create.yml new file mode 100644 index 0000000..4e98151 --- /dev/null +++ b/playbooks/include/vm-create.yml @@ -0,0 +1,111 @@ +--- +- name: Create new virtual instance + hosts: "{{myhosts}}" + gather_facts: false + + vars_files: + - "../../vars/{{ os_type }}.yml" + + vars: + vmhost_uri: "qemu+ssh://root@{{ vmhost }}/system" + root_pubkey: "{{ lookup('file', '/srv/ansible-private/ssh/id_rsa.pub') }}" + + tasks: + + - name: get vm list + virt: + uri: "{{ vmhost_uri }}" + command: list_vms + delegate_to: localhost + register: result + check_mode: false + + - name: create temp directory + tempfile: + state: directory + register: tmpdir + delegate_to: localhost + when: inventory_hostname not in result.list_vms + + - name: generate root password + shell: "/srv/ansible/scripts/genpasswd {{ inventory_hostname }}" + register: root_password + delegate_to: localhost + when: inventory_hostname not in result.list_vms + + - name: create inject file + copy: + content: | + rootpw --iscrypted {{ root_password.stdout }} + %post + umask 077 + mkdir -p /root/.ssh + echo '{{ root_pubkey }}' > /root/.ssh/authorized_keys + %end + dest: "{{ tmpdir.path }}/include.ks" + delegate_to: localhost + when: inventory_hostname not in result.list_vms + + - name: run virt-install + shell: > + virt-install --connect {{ vmhost_uri }} \ + --name {{ inventory_hostname }} \ + --graphics none --boot useserial=on --serial pty --noautoconsole \ + --controller usb,model=none --sound none --memory {{ mem_size }} \ + --vcpus {{ num_cpus }} --cpu host-passthrough \ + --disk /srv/libvirt/os/{{ inventory_hostname }}.a.img,cache=none,format=raw,size={{ dsk_size }} \ + --network bridge=br20,mac={{ mac_address }},model=virtio \ + --initrd-inject {{ tmpdir.path }}/include.ks \ + {{ virt_install_os_args }} + delegate_to: localhost + when: inventory_hostname not in result.list_vms + + - name: wait for install to finish + virt: + uri: "{{ vmhost_uri }}" + name: "{{ inventory_hostname }}" + command: status + register: vmstatus + until: vmstatus.status == "shutdown" + retries: 1000 + delay: 20 + delegate_to: localhost + when: inventory_hostname not in result.list_vms + + - name: clean tempdir + file: + path: "{{ tmpdir.path }}" + state: absent + delegate_to: localhost + when: tmpdir + + - name: start vm + virt: + uri: "{{ vmhost_uri }}" + name: "{{ inventory_hostname }}" + command: start + delegate_to: localhost + when: inventory_hostname not in result.list_vms + + - name: wait for ssh to start + wait_for: + delay: 10 + host: "{{ inventory_hostname }}" + port: 22 + state: started + timeout: 1200 + delegate_to: localhost + when: inventory_hostname not in result.list_vms + + - name: get ssh keys from new host + local_action: command ssh-keyscan {{ inventory_hostname }} + register: hostkeys + + - name: add new ssh host key to known_hosts + known_hosts: + path: /root/.ssh/known_hosts + key: "{{ item }}" + host: "{{ inventory_hostname }}" + with_items: "{{ hostkeys.stdout.splitlines() }}" + delegate_to: localhost + when: inventory_hostname not in result.list_vms diff --git a/scripts/genpasswd b/scripts/genpasswd new file mode 100755 index 0000000..9e41228 --- /dev/null +++ b/scripts/genpasswd @@ -0,0 +1,55 @@ +#!/usr/bin/env python +""" Password generator module """ + +import os +import sys +import string +from base64 import encodestring +from random import SystemRandom + +from Crypto.PublicKey import RSA +from passlib.hash import sha512_crypt + + +OUTDIR = "/srv/ansible-private/keystore" +PUBKEY = "/srv/ansible-private/ssh/id_rsa.pub" + + +class Passwd(object): + """ Generate, hash and encrypt passwords """ + + characters = string.ascii_letters + string.digits + + def __init__(self, length=20): + self.plain = "".join([SystemRandom().choice(self.characters)\ + for _ in range(length)]) + + def hash(self): + """ Return sha512 hash of password """ + return sha512_crypt.hash(self.plain, rounds=5000) + + def encrypt(self, pem): + """ Return password encrypted with given public key """ + key = RSA.importKey(open(pem, "r").read()) + # docs say encrypt second argument will be ignored + return encodestring(key.encrypt(self.plain, "x")[0]) + + +def main(): + """ Generate and store password for given host """ + if len(sys.argv) != 2: + print >>sys.stderr, "Usage: %s " % \ + os.path.basename(sys.argv[0]) + sys.exit(1) + + os.umask(077) + mypass = Passwd() + + dest = open(os.path.join(OUTDIR, sys.argv[1] + ".asc"), "w") + dest.write(mypass.encrypt(PUBKEY)) + dest.close() + + print mypass.hash() + +if __name__ == "__main__": + main() diff --git a/scripts/getpasswd b/scripts/getpasswd new file mode 100755 index 0000000..9327322 --- /dev/null +++ b/scripts/getpasswd @@ -0,0 +1,24 @@ +#!/bin/sh + +if [ $# -ne 1 ]; then + echo "Usage: $(basename "$0") " 1>&2 + exit 1 +fi + +TARGET=$1 + +ENC=/srv/ansible-private/keystore/${TARGET}.asc +KEY=/srv/ansible-private/ssh/id_rsa + +if [ ! -f "${KEY}" ]; then + echo "ERR: Cannot find encryption key file ${KEY}" 1>&2 + exit 1 +fi + +if [ ! -f "${ENC}" ]; then + echo "ERR: Cannot find password entry for ${TARGET}" 1>&2 + exit 1 +fi + +base64 -d "${ENC}" | openssl rsautl -decrypt -raw -inkey "${KEY}" +echo