Skip to content

Commit

Permalink
doc: add salt documentation
Browse files Browse the repository at this point in the history
Fixes: #20
  • Loading branch information
ben-grande committed Feb 23, 2024
1 parent 6ee4baf commit 85c822c
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 3 deletions.
2 changes: 2 additions & 0 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,5 @@ pre-commit run
## Where to start

See open issues and search for the word `TODO` in the repository files.

If you want to understand how Qusal uses Salt features, read our [Salt guide](SALT.md).
6 changes: 3 additions & 3 deletions docs/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ Qusal design document.
## Goal

Provide a minimal modular isolated environment for users to complete daily
tasks in a secure manner. We should not focus on a specific Qubes OS user base
as it would narrow our reach. We scope to have a diverse user base, with
tasks in a secure manner. We should not focus on a specific Qubes OS user
base as it would narrow our reach. We scope to have a diverse user base, with
different needs and use case that could shape our project for the better.

We must not aim to be a one solution fits all by adding every new project
Expand All @@ -36,7 +36,7 @@ requirements are low, it is capped to a low limit, thus avoiding exacerbated
memory consumption on systems with low specs.

No extraneous features should be included by default besides the basic for
functionality. Extra functionalities that could weak the system can be
functionality. Extra functionalities that could weaken the system can be
provided via extra states that needs to be installed per the user discretion.

## Format
Expand Down
239 changes: 239 additions & 0 deletions docs/SALT.md
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).

0 comments on commit 85c822c

Please sign in to comment.