Ideas for a Python tool for automating configuration of VMs

Hi. I want to have a tool for automating configuration of VMs. But I don’t know

  1. Is this a reinvention of the wheel?
  2. Is this safe?
  3. Can qrexec do this safely?
  4. Is there a simpler way?
  5. Is auditing the tool difficult?

So I want to know what you think about this.

Thanks.


What?

  • I want a meta-tool that helps me write a Python library for automating configurations, connection, and validation of VMs.

Why?

  • Automation speeds up configurations such as recreating compromised Qubes or adding lots of ip to Qube firewall.
  • A Python library approach to automation is far more reusable, readable, testable, and documentable than a bunch of scripts and configuration files.
  • The meta-tool can encourage validation of configurations and secure transmission of configuration commands from dom0 to the VMs.

Minimal Goals

Meta-tool

  • Enable the user’s Library to issue commands to dom0 and VMs
  • Enforce secure transmission of commands to VMs
  • Enable execution of commands in VMs
  • Enforce secure receipt of success/failure of the commands

User’s Library

  • Create VMs with dom0 commands
  • Execute commands within VM

Stretch Goals

Meta-tool

  • Encourage validation of steps in the workflow by combining implementation and validation of the step into a ‘state’.
  • Wrap shell commands and ssh keys into Python function / class
  • Enable dry running a workflow
  • Plot a workflow

Command and Response

Chain of command

  • Dom0 → Management VM → Minion VM.

User’s Library and Script

  • Trust the user’s library and script
  • The library and script have no hard-coded secrets (such as ssh keys).

Command

  • Each command consists of pickled python function and pickled arguments
  • Dom0 signs each command

Response

  • Each response is a number that indicates success / failure and a text that explains the reason.
  • If the text has more than X characters, the meta-tool truncates the text.
  • Minion VM signs each response
  • The response is not a python pickle because of pickle bomb

Dom0

  • Import user’s library
  • Sign user’s library
  • Distribute the signed user’s library from Dom0 to the Management VM
  • Run user’s script, which sends commands to Management VM
  • Receive responses from Management VM

Management VM

  • This is a Disposable VM
  • Receive user’s library from dom0
  • Send user’s library to Minion VM
  • Relay commands from Dom0 to Minion VM
  • Relay response of the commands from Minion VM to Dom0

Minion VM

  • Receive user’s library from dom0
  • Import user’s library
  • Receive command from the Management VM
  • Execute the commands
  • Sign response of the commands
  • Send response to the Management VM
1 Like

If Salt is newbie friendly, I would use salt. But here is my experience …

I put my impression of Salt into another thread because that is another matter.

.

Did you look for other orchestration software? Maybe Ansible or some other already existing solution will suit you more?

I think designing the API before making sure the engine is safe and sound might waste time. But here is what I have in mind now:

import automaton.qube as qube
import automaton.dom0 as dom0
from automation.tag import minion
from automaton.exception import noraise


@minion
def install_packages(packages):
    # Raise exception if we call this function directly
    # dom0 cannot execute a minion command
    qube.minion.install(packages)


def main():
    # = install template
    dom0.install("fedora-34-minimal")
    dom0.install(["fedora-35-minimal", "debian-11-minimal"])
    
    # = Create a qube with dom0 commands =
    config = {
        'name': "my_new_qube",
        'template': "fedora-34-minimal",
        'max_mem': "200MB",
    }
    # A dom0 command can return a Python object
    q = qube.make(config=config)

    # = Install packages
    #     This command can only return a status object
    #     because it is a minion command.
    q.install(["xfce4-terminal"])

    # Same, except don't raise an exception if fail
    with noraise():
        status = q.install(["xfce4-terminal"])
        if not status.sucess:
            print("Ops. Reason:", status.reason)

    # Run custom python function within a qube
    q.run(install_packages)(["xfce4-terminal"])

    # Open a bash process in the qube 
    with q.shell() as shell:
        shell.run(
            """
            cd ~/
            export HAS_COOKIES=True
            """
        )
        # close the shell

    # Create a disposable qube
    q2 = qube.make_disp()
    print("Created disposable qube:", q2.name)

    # Copy a file from a qube to another qube
    q.path('~/.vimrc').copy_to(
        q2.path('~/.vimrc')
    )


main()

You might find this note useful.

That is a nice blog post. I used to use bash scripts in dom0 to setup windows 10 qubes.

https://dev.qubes-os.org/projects/core-admin-client/en/latest/qubesadmin.html#module-qubesadmin

I’m also be interested in this.

I’ve written my own automation script before learning about the qubesadmin module, so it’s not as advanced but gets the job done. In about 3000 lines it’s able to configure everything, from minimal templates to the final appvms (all at once, by category, or one-by-one with parser).

In short, I have a bash_run(cmd) function which starts a bash subprocess with the given command and a qvm_run(vm, vm_cmd) which passes qvm-run -p -u root "{vm_cmd}" {vm} to bash_run(cmd). Then a myriad of other functions, but these two get the bases covered.

Also using plain bash scripts. To run some commands in a qube:

run_rpc -u user -q myqube <<-SHELL
	apt install -y firefox
	firefox
SHELL

To write/append a file:

to_file_rpc -u user -q myqube /home/user/foo <<-SHELL
	my appended content
	Hello world
SHELL
1 Like