Skip to content

NixOS Modules

GIVC exposes NixOS modules, which are primarily aimed to be used with the Ghaf Framework.

If you are using the Ghaf Framework as a library, the default functionality should be available without further modification. However, to include it into your project, define your flake input as follows

givc = {
url = "github:tiiuae/ghaf-givc";
inputs = {
nixpkgs.follows = "nixpkgs"; # optional
flake-utils.follows = "flake-utils"; # optional
devshell.follows = "devshell"; # optional
treefmt-nix.follows = "treefmt-nix"; # optional
};
};

To use the givc flake overlay, overlay your nixpkgs with the givc overlay:

nixpkgs.overlays = [ inputs.givc.overlays.default ];

You can import the givc modules individually, or create an internal module importing all givc modules at once and enable the respective module where needed.

To import a givc module, simply add the respective module to your imports statement in the relevant VM or host.

Example: Import admin module to admin-vm

imports = [
inputs.givc.nixosModules.admin
];

This allows you to import a modules where needed, and applies analogously to all VMs and host.

You can alternatively create an internal module, and import this module anywhere a givc module is needed. It can then be enabled and configured in the config section. Here an example how to create such a module with flake-parts:

{ inputs, ... }:
{
flake.nixosModules = {
givc.imports = [
inputs.givc.nixosModules.admin
inputs.givc.nixosModules.host
inputs.givc.nixosModules.tls
inputs.givc.nixosModules.dbus
inputs.givc.nixosModules.sysvm
inputs.givc.nixosModules.appvm
];
};
}

The givc module of your project is then exported, and can typically be referenced internally as

inputs.self.nixosModules.givc

IMPORTANT Please refer to the developer documentation for detailed documentation of the NixOS modules; and examine the configurations of the automated tests or the Ghaf project as reference.

Once you have imported a givc module, you need to configure it. Module configuration should be straightforward; generally, all modules requires at least:

  • enabling the module
  • configuring its network paramters
  • configuring TLS paths (if different from defaults)

In addition, agents typically require:

  • configuring the admin service network parameters (where to reach it)
  • configuring systemd units, services, and/or applications that it administers
  • enabling additional agent modules (such as dbus or locale services)

As an example, we configure the systems host module. Compared to the sysvm module, it has additional functionality to control VM services (microvm@<vm-name>.service), and TLS credential generation. Only one host module should be present at a time.

A sample host module configuration could look like this:

# Configure givc host module
givc.host = {
# Enable module
enable = true;
# Define modules' server configuration
transport = {
name = "my-host";
addr = "192.168.1.2";
port = "9000";
};
# Provide list of services to whitelist for the module
services = [
"a-host-service.service"
"poweroff.target"
"reboot.target"
];
# Provide a list of system and app VMs
systemVms = map (vmName: "microvm@${vmName}.service") [ "admin-vm" "net-vm" ];
appVms = map (vmName: "microvm@${vmName}.service") [ "app-vm" ];
# Provide TLS configuration files
tls = {
caCertPath = "/etc/ssl/certs/ca-certificates.crt";
certPath = "/etc/givc/ghaf-host-cert.pem";
keyPath = "/etc/givc/ghaf-host-key.pem";
};
# Provide admin service information
admin = {
name = "admin-vm";
addr = "192.168.1.3";
port = "9001";
};
# Provide a TLS generator configuration
givc.tls = {
enable = true;
agents = lib.attrsets.mapAttrsToList (n: v: {
name = n;
addr = v;
}) {
net-vm = "192.168.1.1";
my-host = "192.168.1.2";
admin-vm = "192.168.1.3";
app-vm = "192.168.1.4";
};
generatorHostName = "my-host";
storagePath = "/vm-storage/givc";
};
};

The system VM module (sysvm) is used and configured the similar as the host module, and only differs by type and subsequent parent process (VM) information.

The admin module is configured similar to the host module. Services defined with the admin module are expected to be givc agent modules that report to the admin VM as part of the system startup.

The appvm module runs as user service in an active user session, not as a system service. The implementation allows to specify and run multiple applications.

To use the agent as application controller, include the appvm module as follows:

# Configure appvm module
givc.appvm = {
# Enable module
enable = true;
# UID of user to determine session bus
uid = 1000;
# Define modules' server configuration
transport = {
name = "app-vm";
addr = "192.168.1.123";
port = "9000";
};
# Specify applications by name, command, and argument types accepted
applications = [
{
name = "foot";
command = "${pkgs.foot}/bin/foot";
args = [ "flag" ];
}
];
# Provide TLS configuration files
tls = {
caCertPath = "/etc/ssl/certs/ca-certificates.crt";
certPath = "/etc/givc/ghaf-host-cert.pem";
keyPath = "/etc/givc/ghaf-host-key.pem";
};
# Provide admin service information
admin = {
name = "admin-vm";
addr = "192.168.1.3";
port = "9001";
};
};

Note that a user session must be active for the systemd service to run. Depending on your system’s user configuration, you can use loginctl enable-linger $USER, the users.users.<name>.linger NixOS option, or

systemd.tmpfiles.rules = [
"f /var/lib/systemd/linger/${my-user}"
];

to keep the user session running without requiring additional login and keep the user service agent running.