-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
3 changed files
with
244 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
# Salt | ||
|
||
Qusal SaltStack development guide. | ||
|
||
## Table of Contents | ||
|
||
* [What this guide is](#what-this-guide-is) | ||
* [Resources](#resources) | ||
* [Minion Configuration](#minion-configuration) | ||
* [Jinja](#jinja) | ||
* [Targetting Minions](#targetting-minions) | ||
* [Idempotence](#idempotence) | ||
* [Examples](#examples) | ||
|
||
## What this guide is | ||
|
||
This guide is an introduction to the use of SaltStack in Qusal. It is in no | ||
way anything other than that, it is not a beginner's instructional guide to | ||
the use of Salt in Qubes OS or any other project, although it may share some | ||
similarities. It is not meant to substitute our other guidelines, | ||
[contribution](CONTRIBUTING.md) and [design](DESIGN.md) rules still apply. | ||
|
||
If you just want to understand SaltStack, upstream provides an | ||
[excellent tutorial](https://docs.saltproject.io/en/getstarted/system/index.html), | ||
don't worry if you don't understand everything, Qubes OS SaltStack integration | ||
abstracts the client to server communication, only remaining to you to [learn | ||
how to write states](https://docs.saltproject.io/en/getstarted/config/index.html) | ||
and [how to correctly apply them](https://docs.saltproject.io/en/latest/topics/targeting/index.html), | ||
in Qubes OS case, install of running salt-call directly, use | ||
[qubesctl](https://www.qubes-os.org/doc/salt/#salt-configuration-qubesos-layout). | ||
|
||
## Resources | ||
|
||
We follow all of the rules dictated by [Salt Best Practices](https://docs.saltproject.io/en/latest/topics/best_practices.html) | ||
documentation. We must not write the code to only be read by the code authors, | ||
but to anyone that understands Salt. Bugs are common in code that is obscure | ||
and takes effort to read, aim for clarity and modularity, use a `files` | ||
directory to place files that are going to be applied to the minions. All | ||
other rules also apply. | ||
|
||
A list of Salt's [Execution Modules](https://docs.saltproject.io/en/latest/ref/modules/all/) | ||
and [State Modules](https://docs.saltproject.io/en/latest/ref/states/all/) are | ||
good indexes to find the desired module, but you may not recognize the module | ||
that you need this way, you may need to find examples in our code or available | ||
in the internet. | ||
|
||
Qubes OS provides [qvm State Modules](https://github.com/QubesOS/qubes-mgmt-salt-dom0-qvm/blob/main/README.rst), | ||
we are using it to manage qubes properties. | ||
|
||
## Minion Configuration | ||
|
||
We chose to set [some minion configuration](../minion.d/), such as | ||
[file_roots](https://docs.saltproject.io/en/latest/ref/configuration/minion.html#file-roots) | ||
for us to own the directory, in other words, we expect only our project files | ||
to be deployed in the configured minion root directory, we can clean it on an | ||
update without worrying of deleting user settings. | ||
|
||
Note that on Qubes OS, every qube is a minion, including dom0. | ||
|
||
## Jinja | ||
|
||
[Jinja](https://jinja.palletsprojects.com/) is the [default templating language](https://docs.saltproject.io/en/latest/topics/jinja/index.html#include-and-import) | ||
in SLS files. | ||
|
||
We use [Jinja includes and imports](../salt/debian-minimal/template.jinja) and | ||
[Jinja macros](../salt/utils/macros) to share reusable state | ||
configuration, thus avoiding code duplication, allowing us to apply a state | ||
always the same way between files in the same or different projects. | ||
|
||
## Targetting Minions | ||
|
||
You can target minions in two ways, with a [top file](https://docs.saltproject.io/en/latest/ref/states/top.html) | ||
or specifying the states on the command-line. | ||
|
||
We use [top files](../salt/sys-git/init.top) to be able to execute a state in | ||
multiple qubes in a single call, with the powers of advanced minion | ||
targetting, we can [match properties of a qube](../salt/debian/install.top) to | ||
apply the state depending on its name, its type and many other settings, by | ||
specifying the minion minion IDs in a list, globbing per name, PCRE matching | ||
a minion ID and many other match types. | ||
|
||
## Idempotence | ||
|
||
We always use Salt modules when possible, even for simple tasks such as | ||
[creating a directory](../salt/sys-git/install.sls). Not all systems supports | ||
the same `mkdir` options, we delegate this task to the Salt module | ||
[file.directory](https://docs.saltproject.io/en/latest/ref/states/all/salt.states.file.html#salt.states.file.directory), | ||
it them becomes responsible to find out how to apply the desired state to the | ||
wanted directory. | ||
|
||
Specific modules are preferred over the [cmd | ||
module](https://docs.saltproject.io/en/latest/ref/states/all/salt.states.cmd.html) | ||
as they only apply the changes that are necessary, skipping what is already in | ||
the desired state and provide a human and machine-readable output of what has | ||
been done, changed or not. | ||
|
||
The `cmd` state might still be needed in some circumstances: | ||
|
||
- When Qubes OS does not provide a module; | ||
- When SaltStack does provide a module; and | ||
- When SaltStack module does not meet all requirements. | ||
|
||
## Examples | ||
|
||
If you have followed along until now, you are ready to start experimenting. | ||
|
||
Let's create a qube to hold our private keys and passwords. Create the | ||
following SLS files. The contents can be copied from the below example. Please | ||
make sure to install Qusal before, it is required to create the base | ||
templates, do Jinja imports and run Jinja macros. | ||
|
||
`create-keys.sls`: | ||
```salt | ||
{# Use Qubes OS Jinja Template to create qubes using 'qvm.vm' #} | ||
{% from "qvm/template.jinja" import load %} | ||
{# From our Jinja template clone-template, import 'clone_template' macro #} | ||
{% from 'utils/macros/clone-template.sls' import clone_template -%} | ||
{# Run the 'clone_template' macro to clone 'debian-minimal' to 'tpl-keys' #} | ||
{{ clone_template('debian-minimal', 'keys') }} | ||
{# Load the following block as an YAML to the 'defaults' variable #} | ||
{% load_yaml as defaults -%} | ||
name: keys | ||
{# Enforce qube settings #} | ||
force: True | ||
{# Only run this state if the requirements are executed succesfully #} | ||
require: | ||
{# Ensure succesfull 'qvm.clone' run to create 'tpl-keys-clone' | ||
This module was executed in the 'clone_template' macro #} | ||
- qvm: tpl-keys-clone | ||
{# If qube does not exist, create it with the specified settings #} | ||
present: | ||
{# Set it to an updated Debian version #} | ||
- template: tpl-keys | ||
{# We must assign a high trust to this qube, it holds important data #} | ||
- label: black | ||
{# Set qube preferences after it was created with the 'present' state #} | ||
prefs: | ||
{# Enforce qube template after it was created #} | ||
- template: tpl-keys | ||
{# Enforce qube label after it was created #} | ||
- label: black | ||
{# Audio is not necessary for a keys qube, remove it #} | ||
- audiovm: "" | ||
{# Networking is not necessary for a keys qube, remove it #} | ||
- netvm: "" | ||
{# We want it backed up by default #} | ||
- include_in_backups: True | ||
{# Set qube features after it was created with the 'present' state #} | ||
features: | ||
{# Disable unwanted features #} | ||
- disable: | ||
{# Printing is not necessary for a keys qube, remove it #} | ||
- service.cups | ||
{# Set feature values, useful for string values #} | ||
- set: | ||
{# Help GUI users find useful applications for this qube #} | ||
- menu-items: "org.keepassxc.KeepPassXC.desktop qubes-open-file-manager.desktop qubes-run-terminal.desktop qubes-start.desktop" | ||
{# Stop loading to the 'defaults' variable #} | ||
{% endload %} | ||
{# Run the 'load' macro of 'qvm/template.jinja' with the value 'defaults' #} | ||
{{ load(defaults) }} | ||
``` | ||
|
||
`install-keys.sls`: | ||
```salt | ||
{# Avoid applying the state by mistake to dom0 #} | ||
{% if grains['nodename'] != 'dom0' %} | ||
{# Always update the package list before trying to install any package #} | ||
keys-updated: | ||
pkg.uptodate: | ||
- refresh: True | ||
{# Install packages using Salt's pkg.installed module #} | ||
keys-installed: | ||
pkg.installed: | ||
- refresh: True | ||
{# Enforce that we don't want to install recommended packages #} | ||
- install_recommends: False | ||
{# Enforce that we don't want to install suggested packages #} | ||
- skip_suggestions: True | ||
{# List of packages to be installed #} | ||
- pkgs: | ||
{# Wait, some package names do not match on different distributions #} | ||
- keepassxc | ||
- gnupg2 | ||
{# The package name can be specified for different OSes depending on grains #} | ||
{% set pkg = { | ||
'Debian': { | ||
'pkg': ['sq', 'openssh-client'], | ||
}, | ||
'RedHat': { | ||
'pkg': ['sequoia-sq', 'openssh-clients'], | ||
}, | ||
}.get(grains.os_family) %} | ||
{# Install the packages specific to the OS that this state is being applied #} | ||
keys-installed-os-specific: | ||
pkg.installed: | ||
- refresh: True | ||
- install_recommends: False | ||
- skip_suggestions: True | ||
{# Get the Jinja variable 'pkg.pkg' and convert it to an YAML list #} | ||
- pkgs: {{ pkg.pkg|sequence|yaml }} | ||
{# End our 'if' statement created above #} | ||
{% endif %} | ||
``` | ||
|
||
`appmenus-keys.sls`: | ||
```salt | ||
{# From our Jinja template sync-appmenus, import 'sync_appmenus' macro #} | ||
{% from 'utils/macros/sync-appmenus.sls' import sync_appmenus %} | ||
{# Run the 'sync_appmenus' macro to synchronize the application list #} | ||
{{ sync_appmenus('tpl-keys') }} | ||
``` | ||
|
||
After you have created the states above, copy them to Dom0 in `/srv/salt`. | ||
|
||
Create the qube: | ||
```sh | ||
qubesctl state.apply create-keys | ||
``` | ||
|
||
Install packages in the qube template: | ||
```sh | ||
qubesctl --skip-dom0 --targets=tpl-keys state.apply install-keys | ||
``` | ||
|
||
Make the application menus appear after the requirements are installed: | ||
```sh | ||
qubesctl state.apply appmenus-keys | ||
``` | ||
|
||
Congratulations, you have applied you first desired state with the benefit of | ||
Qusal macros. The above examples are based on our [vault formula](../salt/vault). |