Packaging Salt states / formulas for use in Qubes OS

Hi everyone!

I am in the process of learning how Salt is currently (R4.1) used in Qubes OS to automate the creation and configuration of individual qubes. I’ve created a few states to that describe split-SSH, spit-GPG along with a few smaller tasks (Git, SSH and GPG config). I think the split-SSH and split-GPG would have re-use value.

I am treating the split-SSH state as a proof-of-concept and currently I see two main limitations:

  • I don’t have a good way to import them from my work qube to dom0. I believe that packaging them could help, but would love if someone could confirm or correct me, and give me some pointers to relevant docs.
  • The qubes names are currently hard-coded (ssh-vault, ssh-client for readability). I personally use work as ssh-client for example and I find reasonable to think that one could want to use multiple clients with the same vault. I believe there should be way to use Salt pillar to provide custom names, but I haven’t found the way to target qubes based on pillar data. Again, any pointers would be greatly appreciated. (I’m happy to create a separate discussion on GitHub if that helps.)
  • Some of the state applies to the template of the ssh-client. I hard-coded it to fedora32, then tried to get that information from the client grains without success. (I think using grains for this purpose is ok, but maybe I’m wrong?) Again, I have no doubt the information about any given qube template is available somewhere, I’d love if someone could point me in the right direction.

Those are a lot of questions, I’m happy to write a how-to or a tutorial for the docs (using split-SSH as an example) if I find the way to complete the loop and create / package / whatever-needs-to-be-done to make a Salt formula convenient to use in Qubes OS. :slightly_smiling_face:


See how the the guys at Freedom of the Press Foundation are doing it for the qubes-workstation project:

Specifically this part. Essentially after the initial setup all you have to do to get the code on dom0 is make clone.

I hope this helps!

1 Like

This would be pretty epic. One thing that could be particularly useful (I think) would be a boilerplate salt config with some examples. (If this exists already, please let me know!). But a nicely documented tutorial could be nice as well

Thanks @deeplow!

I only took a quick look, but that reference sure helps! It still requires to copy from a qube to dom0, but it builds an RPM package on the fly and that is something I’ll definitely look into!

I’ll also take a better look to how the RPM is used once in dom0. I’ve a gut feeling that importing it into dom0 from a package repository (vs copying it via a tarball) may allow for additional confidence that is what it pretends to be -I know there is a two-step process to update packages- but I haven’t looked enough into how updates work yet to be sure and I might well be wrong. This is a great first step, thank you for the pointer!

Also your link lead me to a way of tagging qubes for targetting by qubectl! :bulb::tada: That’s awesome, thanks again!

1 Like

Glad it helped! :slight_smile:

I’m in the process of posting my salt formulae to GitHub.
Building packages is simple, and I have an example of how to do this
for a Kali template.
I’ll add spec files for the other formulae too, and host some packages
on - too late to do it now, so maybe tomorrow.


Thanks for the examples @unman. I’ve done some progress and have a proof-of-concept for building a package out of the Salt state (using Tito).

I think I’ve got a good understanding of what it would take to publish the RPM (and it seems relatively straightforward).

I’ll look further into checking integrity of the sources and signing the resulting RPM packages, and once the loop is complete I’ll look into turning the Salt state into a formula.

1 Like

Today I learned: split-GPG and RPM packaging play nice together in general. :bulb:
I took note of the corresponding RPM configuration because it seems generic enough.

From there, signing and verifying packages can be performed “the usual way”:

# sign both source package and regular package:
rpm --resign example-1.0.0-1.f32.src.rpm
rpm --resign example-1.0.0-1.fc32.noarch.rpm

# verify them:
rpm -K example-1.0.0-1.fc32.src.rpm
rpm -K example-1.0.0-1.fc32.noarch.rpm

Cross-referencing @unman’s examples:

1 Like

I’ll call this done for now. If anyone is interested in setting up a personal YUM/DNF repository for RPM packages, here is a starting point:

1 Like

I’ve merged that pull request, and got the verify / build / verify / sign loop complete. Things can certainly be refined, but I think the essential elements are there and I installed qubes-mgmt-salt-user-split-ssh-0.1.0-1.fc32.noarch.rpm in my dom0 :slightly_smiling_face: :tada:

Next step I believe is turning the Salt state into a formula (corresponding issue in GitHub).

If anyone want to join me figuring that out, please chime in, you’d be welcome!


Quick update: this is coming along nicely. As of qubes-mgmt-salt-user-split-ssh-0.2.2-1.fc32.noarch.rpm the Salt formula is behaving the way I expect, and I am satisfied with its structure.

For reference, the configuration file looks like this (and persists between updates):

# /srv/user_pillar/split-ssh/config.yaml
  - name: ssh-vault
    template: fedora-32
    label: black
    mem: 400
    vcpus: 2
    autostart: True
  - name: work
    template: fedora-32
    label: blue
    mem: 400
    vcpus: 2
    autostart: False
  - name: another-ssh-client
    template: fedora-32
    label: blue
    mem: 400
    vcpus: 2
    autostsart: True

Beyond a few limitations (e.g. I haven’t looked into supporting other templates than fedora-based ones though it is certainly possible; I don’t personally need more than one vault and left support for multiple vaults incomplete) the formula covers what I believe are the most common uses cases.

There are a couple of things that I’d like to refine in the way the RPM packages / installation behave (e.g. the package currently includes a workaround for this issue that is not very elegant) but I think at this point the next step is writing some documentation.

If you’re able to follow along the code (Salt formula, RPM packaging, or RPM publishing, linked in earlier updates) and have thoughts on what would be most valuable to explain, please let me know here! :slightly_smiling_face:

1 Like

Referencing a similar thread about packaging Salt config as Debian packages from the mailing list. (I can’t perform the cross reference there from the forum.)

Documentation update:

I’ve also set up some context and outlined the missing sections before I take on the next guide.

Of course, feedback (well-intended and actionable) is welcome! I think the qubes-packages’ discussions are a good place for that.


Documentation update:


@deeplow if you’ve got time to skim through the tutorial linked above, I’d love to hear your thoughts! :slightly_smiling_face:

I’m thinking of structuring the generalization as a collection of how-to guides / code snippets based on the tutorial steps: how to create/ensure a qube exists, how to set up qube preferences, how to ensure packages are available in a qube, how to ensure presence of persistent files in a qube, how to ensure presence of non-persistent files in a qube, and so on.

That’s what I think would match more closely your suggestion of boilerplate config with examples:

One thing that could be particularly useful (I think) would be a boilerplate salt config with some examples.

1 Like


Thank you very much for this work.
Kind of busy right now, but I was looking and I think I will finally learn the basics of Salt (from the docs you linked). It seems not too difficult and incredibly useful.
Just want to say, I think this is a good path.
Note: I am a intermediate level user, not too technical, not excessively comfortable with the cmd line.



Not a lot at the moment. I’ll see what I can but. But I welcome the contribution very much and extend the offer for other people to provide feedback on it.

Sounds nice! I must also say that your “read-the-docs” looks much nicer than the default markdown files of the community documentation. But have you considered making your contributions there?

Or if you prefer to do on your website, maybe after you’re done you could open a pull request to add a link to that under “external documentation” over on the official docs.

I considered submitting this to the community docs, but at the moment I don’t have the bandwidth to write and manage the back and forth that publishing on third-party docs requires. I am very much figuring out the format as I go, and self-publishing gives me the room to iterate quickly.

I’ll take on your suggestion, though, and open a pull request to add a link or two under the “external documentation” section of the official docs when I’m done writing the how-tos. :slightly_smiling_face: