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
|
Qubes OS DevOps automation toolkit
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
This is a kit of several tools to help you automate your Qubes OS
|
This software helps you automate development operations on Qubes OS through
|
||||||
operations:
|
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
|
1. A computer program `bombshell-client` that can run in dom0 or
|
||||||
in any domU, which uses the `qubes.VMShell` Qubes RPC service
|
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 remote hosts -- this option can be used with `bombshell-client`
|
||||||
to run rsync against other VMs as if they were normal SSH hosts.
|
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
|
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