Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,20 @@ r4.3:mgmt-host:
- r4.3:build:vm-fc42
variables:
VM_IMAGE: qubes_4.3_64bit_stable.qcow2

pages:
stage: build
image: python:3
tags:
- docker
artifacts:
paths:
- public
script:
- mkdir public
- pip3 install sphinx sphinx-ansible-theme antsibull-docs ansible
- git submodule update --init --recursive
- mkdir build/
- antsibull-docs sphinx-init qubesos.* --use-current --dest-dir build/
- ANSIBLE_COLLECTIONS_PATH=$(pwd) ./build/build.sh
- mv build/build/html/* public/
43 changes: 22 additions & 21 deletions EXAMPLES.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
# Example tasks

The **qubesos** module is under active development, and its syntax and available options may evolve.
Refer to the examples below to learn more about managing Qubes OS qubes.

## Creating an inventory file for Ansible

To set up an inventory file, create a file with content similar to the following:
Expand All @@ -20,13 +17,13 @@ admin-demo
project-demo

[appvms:vars]
ansible_connection=qubes
ansible_connection=qubesos.core.qubes

[templatevms]
fedora-demo

[templatevms:vars]
ansible_connection=qubes
ansible_connection=qubesos.core.qubes
```

Once the inventory file is created, you can execute Ansible playbooks using:
Expand All @@ -38,7 +35,7 @@ ansible-playbook -i inventory my_playbook.yaml
To create an inventory file that automatically includes all Qubes, run the following command:

```bash
ansible localhost -m qubesos -a 'command=createinventory'
ansible localhost -m qubesos.core.command -a 'command=createinventory'
```

> Warning: This command **overwrites** the existing inventory file in the local directory.
Expand All @@ -55,56 +52,60 @@ This is the preferred method to create a new qube if it is not already present.
connection: local
tasks:
- name: Create a test qube
qubesos:
guest: testqube
label: blue
qubesos.core.qube:
name: testqube
state: present
template: "debian-12-xfce"
```

> Remark: Only the *guest* parameter is mandatory. By default, the module uses the system default TemplateVM and NetVM, and the default label color is **red**.
> Remark: Only `name` and `state` parameter are mandatory. By default,
> the module uses the system default TemplateVM and NetVM, and the default
> label color is **red**.

## Creating multiple qubes with custom properties and tags

The following example demonstrates creating multiple qubes with specific labels, templates, properties, and a policy file for inter-qube communication.
The following example demonstrates creating multiple qubes with specific labels,
templates, properties, and a policy file for inter-qube communication.

```yaml
---
- hosts: local
connection: local
tasks:
- name: Create vault-demo with custom properties
qubesos:
guest: vault-demo
label: black
qubesos.core.qube:
name: vault-demo
state: present
label: black
template: "fedora-41-xfce"
properties:
memory: 600
maxmem: 800
netvm: ""

- name: Create work-demo qube using a template
qubesos:
guest: work-demo
label: blue
qubesos.core.qube:
name: work-demo
state: present
label: blue
template: "fedora-41-xfce"

- name: Create project-demo qube using a template
qubesos:
guest: project-demo
label: orange
qubesos.core.qube:
name: project-demo
state: present
label: orange
template: "fedora-41-xfce"

- name: Create policy file for qube communications
copy:
ansible.builtin.copy:
dest: /etc/qubes/policy.d/10-demo.policy
content: |
qubes.Gpg * work-demo vault-demo allow
project.Service1 * work-demo @default allow target=project-demo
mode: '0755'
owner: root
group: qubes
```

### Available properties
Expand Down
23 changes: 19 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
VERSION := $(shell cat version)
QUBE_COLLECTION_DIR := $(DESTDIR)/usr/share/ansible/collections/ansible_collections/qubesos

install-common:
mkdir -p $(QUBE_COLLECTION_DIR)/core/plugins/connection
mkdir -p $(QUBE_COLLECTION_DIR)/core/plugins/modules
mkdir -p $(QUBE_COLLECTION_DIR)/core/plugins/module_utils
install -m 644 ansible_collections/qubesos/core/plugins/connection/qubes.py $(QUBE_COLLECTION_DIR)/core/plugins/connection/qubes.py
install -m 644 ansible_collections/qubesos/core/plugins/module_utils/*.py $(QUBE_COLLECTION_DIR)/core/plugins/module_utils/
install -m 644 ansible_collections/qubesos/core/plugins/modules/*.py $(QUBE_COLLECTION_DIR)/core/plugins/modules/

# Legacy files
mkdir -p $(DESTDIR)/usr/share/ansible/plugins/connection
mkdir -p $(DESTDIR)/usr/share/ansible/plugins/modules
cp -P plugins/connection/qubes.py $(DESTDIR)/usr/share/ansible/plugins/connection/qubes.py
install -m 644 plugins/modules/qubesos.py $(DESTDIR)/usr/share/ansible/plugins/modules/qubesos.py
install -m 644 plugins/connection/qubes.py $(DESTDIR)/usr/share/ansible/plugins/connection/qubes.py


install-dom0:
mkdir -p $(DESTDIR)/usr/lib/qubes/
mkdir -p $(QUBE_COLLECTION_DIR)/security/plugins/callback
mkdir -p $(QUBE_COLLECTION_DIR)/security/plugins/strategy
install -m 644 ansible_collections/qubesos/security/plugins/callback/qubesos_strategy_guard.py $(QUBE_COLLECTION_DIR)/security/plugins/callback/qubesos_strategy_guard.py
install -m 644 ansible_collections/qubesos/security/plugins/strategy/qubes_proxy.py $(QUBE_COLLECTION_DIR)/security/plugins/strategy/qubes_proxy.py
install -m 755 update-ansible-default-strategy $(DESTDIR)/usr/lib/qubes/update-ansible-default-strategy

mkdir -p $(DESTDIR)/usr/share/ansible/plugins/callback
mkdir -p $(DESTDIR)/usr/share/ansible/plugins/strategy
install -m 644 plugins/callback/qubesos_strategy_guard.py $(DESTDIR)/usr/share/ansible/plugins/callback/qubesos_strategy_guard.py
install -m 644 plugins/strategy/qubes_proxy.py $(DESTDIR)/usr/share/ansible/plugins/strategy/qubes_proxy.py
install -m 755 update-ansible-default-strategy $(DESTDIR)/usr/lib/qubes/update-ansible-default-strategy
cp -P plugins/callback/qubesos_strategy_guard.py $(DESTDIR)/usr/share/ansible/plugins/callback/qubesos_strategy_guard.py
cp -P plugins/strategy/qubes_proxy.py $(DESTDIR)/usr/share/ansible/plugins/strategy/qubes_proxy.py

install-tests:
mkdir -p $(DESTDIR)/usr/share/ansible/tests/qubes
Expand Down
94 changes: 79 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
# Ansible plugins for QubesOS

This project provides Ansible plugins to interact and manage your [Qubes OS](https://qubes-os.org) virtual machines (called `qubes`).
Those plugins are under active development, so the syntax and keywords may change in future releases. Contributions and feedback are welcome!
This project provides Ansible plugins to interact and manage your
[Qubes OS](https://qubes-os.org) system.

## Plugins description
Those plugins are under active development, so the syntax and keywords may
change in future releases. Contributions and feedback are welcome!

### ``qubesos`` module
## Online documentation

This module may be used to interact with the QubesOS API to manage the state
of your qubes. You can use it to create, update, remove, restart your qubes as
well as change their properties.
The documentation is generated automatically and [is available in the Gitlab
pages of this project](https://qubesos.gitlab.io/qubes-ansible).

### ``qubes`` connection plugin
## Collections and plugins

This connection plugin allows Ansible to connect to your qubes using the
[QubesOS qrexec framework](https://www.qubes-os.org/doc/qrexec/).
This project provides **QubesOS** Ansible plugins under 2 collections:
* `qubesos.core`: Everything related to **QubesOS** management (management
modules, the connection plugin...).
* `qubesos.security`: Ansible plugins related to **dom0** and **ManagementVM**
protection while executing management modules.

### ``qubes_proxy`` strategy plugin

This strategy plugin must be used when Ansible is running on dom0 to prevent any
### Modules

* `qubesos.core.qube`: Use this module for all tasks related to qubes management (create, destroy, start, set volumes, features, labels...)
* `qubesos.core.command`: Non-idempotent commands, used for legacy compatibility, inventory generation...
* `host_devices_facts`: Use this module to gather facts about available devices on the host. You likely want
to use this module to get a list of devices to assign to a VM with the `qubes.core.qube` module.

### ``qubesos.core.qubes`` connection plugin

Given the QubesOS architecture, using SSH to connect to your qubes for management is not relevant.
Instead, the Ansible connection plugin `qubesos.core.qube` allows to execute all Ansible stuff on
your target hosts using the [QubesOS qrexec framework](https://www.qubes-os.org/doc/qrexec/).

As you would do with the command `qvm_run`, Ansible will execute modules codes through the RPCs `qubes.VMShell` and
`qubes.VMRootShell`.

### ``qubesos.secrurity.qubes_proxy`` strategy plugin

This strategy plugin must be used when Ansible is running on dom0 or ManagementVM to prevent any
security issue. The plugin acts as a router which will proxify play execution for a
given qube into its management disposable VM.

Expand All @@ -44,7 +64,7 @@ on templates used by your qubes management DVM (``default-mgmt-dvm`` by default)

## Usage

``qubes`` and ``qubes_proxy`` plugins work out of the box when installed using
``qubes.core.qubes`` and ``qubesos.security.qubes_proxy`` plugins work out of the box when installed using
RPM. The strategy plugin will read the value of the ``hosts`` field
in your playbooks and:
- run the play locally when ``localhost`` is present in the list (dom0 management / ``qubesos`` module usage)
Expand All @@ -60,7 +80,7 @@ strategy=qubes_proxy

You can also put this line in your Play declaration:
```
strategy: qubes_proxy
strategy: qubesos.security.qubes_proxy
```

If extra files need to be present on the disposable VM to execute the playbook, you will need
Expand All @@ -87,12 +107,14 @@ ansible
└── file_to_copy_to_work.txt
```

__Note__: you can use symlink here if multiple roles need the same file. The qubes proxy will dereference
the symlink before building the archive.

See the [examples](EXAMPLES.md) for sample playbooks and role tasks demonstrating common usage scenarios.

## Limitations

The proxy plugin may modify the behaviour of your playbooks. Please notice the following indications and
The proxy plugin may modify the behavior of your playbooks. Please notice the following indications and
limitations:
* **Access to facts and variables from other hosts is not possible**: the proxy strategy builds a single
host vars file containing a merged view of the target's host variables (i.e., variables issued from command line, group vars, host vars, inventory...).
Expand Down Expand Up @@ -132,6 +154,48 @@ admin.vm.Create.TemplateVM * mgmtvm dom0 allow
admin.vm.Remove * mgmtvm @tag:created-by-mgmtvm allow target=dom0
```

## Legacy module `qubesos`

In previous versions of qubes-ansible, a single `qubesos` module were provided
which has been split into the following 3 modules to improve reliability and
maintenance:
* `qubesos.core.qube`
* `qubesos.core.command`
* `qubesos.core.host_devices_facts`

To prevent breaking changes, this module is still present in newer versions of
**qubes-ansible** but is considered deprecated and may be removed in a future
release.

The module takes the same options and will try to translate to calls to the new
modules with the appropriate options.

**Note**: to prevent unexpected behaviors in your playbooks, the option `wait`
has no more effect. The module will always wait for the actions (qube start, stop...)
to finish before starting a new task.

## Legacy plugins

Plugins from previous **qubes-ansible** versions were deployed in
`/usr/share/ansible/plugins`. Now these plugins are packaged in an Ansible collection
in `/usr/share/ansible/collections/ansible_collections/qubesos`.

If you look into `/usr/share/ansible/plugins`, you will still find symlinks to
the new plugins (those in the collections directory) making you able to write
your playbooks with any of those syntaxes:

```
- hosts: appvms
connection: qubesos.core.qubes
strategy: qubesos.security.qubes_proxy
...

- hosts: appvms
connection: qubes
strategy: qubes_proxy
...
```

## License

This project is licensed under the GPLv3+ license. Please see the [LICENSE](LICENSE) file for the full license text.
75 changes: 75 additions & 0 deletions ansible_collections/qubesos/core/galaxy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#SPDX-License-Identifier: GPL-3.0-or-later
### REQUIRED
# The namespace of the collection. This can be a company/brand/organization or product namespace under which all
# content lives. May only contain alphanumeric lowercase characters and underscores. Namespaces cannot start with
# underscores or numbers and cannot contain consecutive underscores
namespace: qubesos

# The name of the collection. Has the same character restrictions as 'namespace'
name: core

# The version of the collection. Must be compatible with semantic versioning
version: 1.0.0

# The path to the Markdown (.md) readme file. This path is relative to the root of the collection
readme: README.md

# A list of the collection's content authors. Can be just the name or in the format 'Full Name <email> (url)
# @nicks:irc/im.site#channel'
authors:
- Guillaume Chinal <guiiix@invisiblethingslab.com>
- Frédéric Pierret <fepitre@invisiblethingslab.com>
- Kushal Das


### OPTIONAL but strongly recommended
# A short summary description of the collection
description: Everything related to QubesOS management

# Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only
# accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file'
license:
- GPL-3.0-or-later

# The path to the license file for the collection. This path is relative to the root of the collection. This key is
# mutually exclusive with 'license'
license_file: ''

# A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character
# requirements as 'namespace' and 'name'
tags:
- QubesOS
- VM
- management

# Collections that this collection requires to be installed for it to be usable. The key of the dict is the
# collection label 'namespace.name'. The value is a version range
# L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version
# range specifiers can be set and are separated by ','
dependencies: {}

# The URL of the originating SCM repository
repository: https://github.com/QubesOS/qubes-ansible

# The URL to any online docs
documentation: https://github.com/QubesOS/qubes-ansible

# The URL to the homepage of the collection/project
homepage: https://github.com/QubesOS/qubes-ansible

# The URL to the collection issue tracker
issues: https://github.com/QubesOS/qubes-issues

# A list of file glob-like patterns used to filter any files or directories that should not be included in the build
# artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This
# uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry',
# and '.git' are always filtered. Mutually exclusive with 'manifest'
build_ignore: []

# A dict controlling use of manifest directives used in building the collection artifact. The key 'directives' is a
# list of MANIFEST.in style
# L(directives,https://packaging.python.org/en/latest/guides/using-manifest-in/#manifest-in-commands). The key
# 'omit_default_directives' is a boolean that controls whether the default directives are used. Mutually exclusive
# with 'build_ignore'
# manifest: null

Loading