You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.7 KiB

title subtitle author theme
Host a DevOps exam using NixOS \footnotesize Deploy a Bastion host and a KVM virtual machine per student in order for them to deploy a website which will be auto-validated. Yvan SRAKA, Ryan LAHFA default

Host a DevOps exam using NixOS

  • DevOps students have to test their skills in a real-world exam, whats better than scripting it using NixOps in order to reuse it?

  • They will be provided with their own user account on the Bastion and access to a jump user account, WireGuard will be auto-configured on the host to enable access to their KVM host directly.

  • The main point is controlling the KVM guests “declaratively” and giving choice to the students to choose their guest OS: Debian or NixOS.

  • We will see how we can easily generate Nix expression from a scripting language, e.g. Python, and feed it to a NixOps deployment.

Disclaimer: all this is incomplete and experimental!

This was tried during a real exam this summer, but it's very alpha-quality and had to get a lot of last-minute fixes due to external issues (e.g. disks dying…)

Git repository

The full code can be found here\footnote{https://git.newtype.fr/yvan/devops-exam-model}, it's still a bit messy...

\nix folder contains files on which will focus this talk:

  • \color{red}student-setup.nix \color{black} is generated by \color{red} generate-setup.py \color{black} (that rely on \color{red} nix-expr.py\color{black}) from students data.
  • \color{red}deploy.sh \color{black} push on our setup \color{red} exam.nix\color{black}, \color{red} student.nix\color{black}, \color{red} kvm-guests.nix \color{black} and \color{red} student-setup.nix \color{black}

deploy.sh

##!/usr/bin/env bash

echo "[+] Regenerating of the setup"
python3 generate_setup.py

echo "[+] Sending Nix files"
rsync --inplace --temp-dir=/tmp -avPz *.nix \
    yvan@bastion:/etc/nixos/

echo "[+] Rebuilding of the exam machine"
ssh -t yvan@bastion "sudo nixos-rebuild switch"

generate_setup.py (subset of)

def students(csv_filename):
    with open(csv_filename, 'r', newline='') as csvfile:
        ereader = csv.reader(csvfile, delimiter=';')
        next(ereader) # exhaust header.
        for index, student in enumerate(ereader):
            name, surname, email, username = student
            wg_pubkey, wg_privkey = wireguard_parameters()
            keys = read_keys(username)
            yield {
                "surname": surname,
                "name": name,
                "email": email,
                "username": username,
                "keys": keys,
                "wireguardPublicKey": wg_pubkey,
                "wireguardPrivateKey": wg_privkey,
            }

student-setup.nix (generated)

ltorvalds = {
    email = "torvalds@linux-foundation.org";
    guestOperatingSystem = "debian";
    index = 42;
    keys = [
      "ssh-ed25519 ... torvalds@linux-foundation.org"
    ];
    name = "Linus";
    surname = "Torvalds";
    username = "ltorvalds";
    wireguardPrivateKey = "0ECE2Js+RkxQVTyJ9BvZB0DjpEGnWMy1X5cI8R2RdHA=";
    wireguardPublicKey = "3o9Dhmrrql/5PZEhi5kS+Fob1m8rN70SXzDGy48bMR0=";
  };
rstallman = { ... }

student.nix (subset of)

mkGuest = name: student: {
  memory = "1G";
  netDevice = "tap${toString student.index}";
  vncDisplay = "localhost:${toString student.index}";
  operatingSystem = student.guestOperatingSystem;
};

services.kvmGuests = {
  enable = true;
  guests = mapAttrs mkGuest cfg.students;
};

# Create users for each student + management/jump accounts.
users.users = (mapAttrs mkBastionUser cfg.students) // ({
  jump = mkJumpUser cfg.students;
  admin = adminUser; 
});

\Huge Q/A