added sample Ansible playbooks and documentation

This commit is contained in:
Manuel Amador (Rudd-O) 2015-12-21 01:45:20 +00:00
parent 138dfadccf
commit 5dd5ea0e69
11 changed files with 289 additions and 2 deletions

View File

@ -1,8 +1,13 @@
Qubes OS DevOps automation toolkit
==================================
This is a kit of several tools to help you automate your Qubes OS
operations:
This software helps you automate development operations on Qubes OS through
industry-standard configuration management solutions.
**Do you learn better by example?** Then jump to the directory
[examples/ansible/](examples/ansible/) to get started right away.
The software in this kit includes the following:
1. A computer program `bombshell-client` that can run in dom0 or
in any domU, which uses the `qubes.VMShell` Qubes RPC service
@ -71,6 +76,15 @@ The rsync manpage documents the use of a special form of rsh to connect
to remote hosts -- this option can be used with `bombshell-client`
to run rsync against other VMs as if they were normal SSH hosts.
Enabling bombshell-client access to dom0
----------------------------------------
`dom0` needs its `qubes.VMShell` service activated. As `root` in `dom0`,
create a file `/etc/qubes-rpc/qubes.VMshell` with mode `0644` and make
sure its contents say `/bin/bash`.
That's it -- `bombshell-client` should work against dom0 now.
How to use this with automation tools like Ansible and SaltStack
----------------------------------------------------------------

8
examples/README.md Normal file
View File

@ -0,0 +1,8 @@
Qubes OS DevOps automation toolkit: examples
============================================
This is the examples directory. Each example within this directory has a
`README.md` file that explains it further. Feel free to use these examples
as templates to get your own automation started.
* [ansible/](ansible/) contains an example Ansible setup.

175
examples/ansible/README.md Normal file
View File

@ -0,0 +1,175 @@
Qubes OS DevOps automation toolkit: Ansible example
==================================================
This is an example of Ansible automation that leverages this toolkit to
let you manage Qubes VMs. These instructions assume that you have already:
1. cloned this entire project into directory `/home/user/ansible-qubes`
2. installed Ansible (`yum install ansible`) in the TemplateVM of that AppVM
3. opened a terminal window and changed to the directory containing this file
They also assume a bit of familiarity with Ansible as well. If you would like
to get an introduction on Ansible concepts, this examples directory is ripe
for a compare-and-contrast exercise with the
[Ansible introduction](https://docs.ansible.com/ansible/intro_getting_started.html).
Now, let's do a quick walkthrough of these files.
Ansible configuration
---------------------
The starting point is the file `ansible.cfg`. This file tells Ansible where
to find the requisite components to make the Qubes automation work. As
you can see, it's composed mostly of paths, and it points you to the `hosts`
file.
Importantly, because Ansible will look for the `ansible.cfg` file
on your current directory first, that means you will be running your
Ansible commands on the directory containing `ansible.cfg`. Later, you can
deploy aliases, symlinks or helpers to help you work around that.
Inventory
---------
The `hosts` file is your machine inventory -- the VMs (and also physical
machines) that you own, and how they group together. The included inventory
is almost certainly guaranteed not to match the machines you have, nor how
you've grouped them conceptually, so feel free to edit it how you see fit. To
learn more about managing the inventory, check out [the relevant Ansible
documentation](https://docs.ansible.com/ansible/intro_inventory.html).
Two key things to note about the inventory:
1. You denote which machines are Qubes VMs by setting the `ansible_connection`
property to `qubes` on the configuration line specifying the inventory
entry. Instead of a host name, you use the VM name to refer to the
machine.
2. You can (of course, if the VM holding these files has network
connectivity) mix and match hosts you can manage via SSH into your
inventory.
How Ansible knows to connect to your Qubes VMs
----------------------------------------------
Importantly, nothing about this is magic. `qubes` in the `ansible_connection`
parameter merely tells Ansible to use the `ansible/connection_plugins/qubes.py`
as pointed to by the `ansible.cfg` file. That file automatically enlists
the `bombshell-client` technology to connect you to your VMs via Ansible.
When `bombshell-client` starts, it attempts to connect to the target VM's
`qubes.VMShell` service. This is a small Qubes RPC stub that allows a calling
VM to execute any command on the target VM. Of course, all of this is
always subject to the Qubes authorization mechanism, so it's secure.
Time to test drive it!
----------------------
Add some of your VMs to your inventory now. Let's assume you've added your
`work` VM to the inventory, and that you are running this from a `manager`
VM you've created for the purpose.
Ready?
OK, let's try the following. On the terminal window, type:
ansible work -m shell -a whoami
Qubes OS will ask you for permission to run several shell commands from the
`manager` VM to the `work` VM. Accept those prompts, and you'll see
something like this:
[user@manager ansible]$ ansible work -m shell -a whoami
work | success | rc=0 >>
user
That's your `work` VM responding with `I am logged in as user`, which
happens to be the user that Ansible logged into your VM as. The above
command line makes the `shell` module (specified in the command line as
`-m shell`) execute its arguments (specified with `-a`). Ansible has a ton
of execution modules, and they are all documented here:
* [Intro to modules](https://docs.ansible.com/ansible/modules.html)
* [Module index](https://docs.ansible.com/ansible/modules_by_category.html)
Connecting to dom0
------------------
If you're running a bit ahead of these instructions, you may have noticed
that running `ansible dom0 -m shell whoami` actually results in an error.
This is by design from the Qubes team -- the `qubes.VMShell` service does
not ship in the `dom0` VM at all. If you'd lik to be able to manage `dom0`
from your configuration management system, all you need to do is deploy
the necessary configuration to `dom0`.
See the heading *Enabling bombshell-client access to dom0* in the top-level
`README.md` file of this toolkit for instructions on how to do that.
Running modules as root
-----------------------
You can, however, demand to execute commands as `root` wih the parameter `-s`:
[user@manager ansible]$ ansible work -s -m shell -a whoami
work | success | rc=0 >>
root
`-s` makes the `shell` module execute its arguments as root. In fact, it
makes any Ansible module run as root. Ansible has a ton of execution modules, and they
are all documented here:
* [Intro to modules](https://docs.ansible.com/ansible/modules.html)
* [Module index](https://docs.ansible.com/ansible/modules_by_category.html)
Note that running as root may require the `sudo` package to be installed
first. If you encounter problems getting to root, then please install
the `sudo` package on the VM you're targeting (or, more appropriately,
in its template, if it is a template-based VM).
Targeting multiple machines
---------------------------
So far, we've targeted only the `work` VM, but technically you can target any
machine or group of machines in your inventory. Based on the (entirely
fictional) inventory shipped in this example:
* `ansible work:netvm ...` targets two VMs
* `ansible appvms ...` targets all VMs in a group `appvms`.
* `ansible 'all:!nonqubes' ...` targets all inventory machines minus the
non-Qubes ones.
Playbooks
---------
Everything you've seen so far applies to simple `ansible` runs. But the real
worth of Ansible is the possiblity to weave repeatable, idempotent scripts
that involve multiple machines, so you're not constantly repeating yourself.
Enter [`ansible-playbook`](https://docs.ansible.com/ansible/playbooks.html),
generously documented there, and exemplified here.
For a quick primer on how to run playbooks, here are the essentials:
ansible-playbook -v <playbook YML file> [-l <only these hosts>]
This would tell `ansible-playbook` to run every step of the playbook file
in order, on all the hosts it targets on each `hosts` stanza. Should you
want to limit your run to a subset of the hosts, you can use the `-l` argument
and pass those hosts, which are in the exact same format as the one
taken by the `ansible` command on its hosts specification list.
We ship several different sample playbooks:
* `test-nofacts.yml`: logs into the specified machines and retrieves
variables, but without the fact gathering process, leaving the collected
environment in a `/tmp/` directory.
* `test-facts.yml`: does the same thing, but collects facts about the targeted
hosts before dumping the variables.
* `editors.yml`: deploys some text editors on your template VMs (assumed
to be Fedora).
* `qubes-service.yml`: deploys a Qubes service to your template VM, which
can later be turned on via the Services tab of the properties window of
VMs based on the template. In the example, the service is named
`qubes-helloworld`, so that would be the name of the service to
add and enable on the Services tab.
More will come as time goes by. For now, that's all. Happy hacking!

View File

@ -0,0 +1,9 @@
[defaults]
connection_plugins = ../../ansible/connection_plugins
callback_plugins = ./callback_plugins
action_plugins = ./action_plugins
hostfile = ./hosts
hash_behaviour = merge
[ssh_connection]
pipelining = True

View File

@ -0,0 +1,9 @@
- hosts: templatevms
sudo: True
tasks:
- name: deploy some editors
dnf: pkg={{ item }} state=present
with_items:
- emacs
- nano
- vim

View File

@ -0,0 +1,11 @@
[Unit]
Description={{ description }}
ConditionPathExists=/var/run/qubes-service/qubes-{{ name }}
After=qubes-gui-agent.service
[Service]
ExecStart=/bin/echo Hello world
StandardOutput=syslog
[Install]
WantedBy=multi-user.target

29
examples/ansible/hosts Normal file
View File

@ -0,0 +1,29 @@
# Here is where you define your VMs.
fedora-23 ansible_connection=qubes
netvm ansible_connection=qubes
firewallvm ansible_connection=qubes
work ansible_connection=qubes
# Playbooks involving dom0 will fail unless you set up shell access for it.
# See the README.md file for instructions on how to do that.
dom0 ansible_connection=qubes
# Provided the VM where you are running Ansible has network connectivity,
# you could mix SSH hosts in here just as well.
pluto ansible_host=example.com ansible_user=root
[appvms]
work
[servicevms]
netvm
firewallvm
[templatevms]
fedora-23
[dom0s]
dom0
[nonqubes]
pluto

View File

@ -0,0 +1,13 @@
- hosts: templatevms
sudo: True
vars:
description: Qubes hello world
name: helloworld
tasks:
- name: deploy service file
template:
src: files/qubes-service/qubes-service.service.j2
dest: /etc/systemd/system/qubes-{{ name }}.service
register: unitfile
- name: enable service file
service: name=qubes-{{ name }}.service enabled=true

View File

@ -0,0 +1,8 @@
---
- name: Remove previous directory
local_action: file dest=/tmp/dump state=absent
- name: Create directory
local_action: shell mkdir -p /tmp/dump || true
- name: Dump all vars
local_action: template src=files/dumpenv/dumpenv.j2 dest=/tmp/dump/{{ inventory_hostname }}

View File

@ -0,0 +1,6 @@
---
- hosts: all:!nonqubes
tasks:
- name: cat the contents of file /etc/passwd
shell: head /etc/passwd
- include: tasks/dumpenv.yml

View File

@ -0,0 +1,5 @@
---
- hosts: all:!nonqubes
gather_facts: False
tasks:
- include: tasks/dumpenv.yml