mirror of
https://github.com/Rudd-O/ansible-qubes.git
synced 2025-03-01 14:22:33 +01:00
added sample Ansible playbooks and documentation
This commit is contained in:
parent
138dfadccf
commit
5dd5ea0e69
18
README.md
18
README.md
@ -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
8
examples/README.md
Normal 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
175
examples/ansible/README.md
Normal 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!
|
9
examples/ansible/ansible.cfg
Normal file
9
examples/ansible/ansible.cfg
Normal 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
|
9
examples/ansible/editors.yml
Normal file
9
examples/ansible/editors.yml
Normal file
@ -0,0 +1,9 @@
|
||||
- hosts: templatevms
|
||||
sudo: True
|
||||
tasks:
|
||||
- name: deploy some editors
|
||||
dnf: pkg={{ item }} state=present
|
||||
with_items:
|
||||
- emacs
|
||||
- nano
|
||||
- vim
|
@ -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
29
examples/ansible/hosts
Normal 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
|
13
examples/ansible/qubes-service.yml
Normal file
13
examples/ansible/qubes-service.yml
Normal 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
|
8
examples/ansible/tasks/dumpenv.yml
Normal file
8
examples/ansible/tasks/dumpenv.yml
Normal 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 }}
|
6
examples/ansible/test-facts.yml
Normal file
6
examples/ansible/test-facts.yml
Normal 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
|
5
examples/ansible/test-nofacts.yml
Normal file
5
examples/ansible/test-nofacts.yml
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
- hosts: all:!nonqubes
|
||||
gather_facts: False
|
||||
tasks:
|
||||
- include: tasks/dumpenv.yml
|
Loading…
x
Reference in New Issue
Block a user