Trustix - Builder setup with Colmena (flake based)

Up until now we have talked about components in isolation, let's take a stab at a real deployment using Colmena. Once we're done we will have:

  • A Trustix instance that others can subscribe to
  • A local post build hook that publishes builds

Most of the contents in this article will be applicable to other deployment systems too with only minimal changes, the biggest difference should be how they deal with key material (secrets).

Requisites / assumptions

  • You need a recent Nix with Flakes enabled
  • We start off in an empty git repository
  • Our domain name is demo.trustix.dev

Create keys

All Trustix build logs are first and foremost identified by their key pair, which will be the first thing we have to generate.

Let's start by generating a key pair for our log:

$ mkdir secrets
$ nix run github:nix-community/trustix#trustix -- generate-key --privkey secrets/log-priv --pubkey secrets/log-pub

Additionally logs are identified not just by their key, but how that key is used. If a key is used for multiple protocols (not just Nix) those logs will have a different ID. This ID is what subscribers use to indicate what they want to subscribe to.

To find out the log ID for the key pair you just generated: $ nix run github:nix-community/trustix#trustix -- print-log-id --protocol nix --pubkey $(cat secrets/log-pub)

Create a deployment

In your flake.nix put:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";

    trustix = {
      url = "github:nix-community/trustix";
      inputs.nixpkgs.follows = "nixpkgs";
    };
  };
  outputs = { nixpkgs, flake-utils, trustix, ... }:
    let
      hostName = "demo.trustix.dev";
    in

    # Provide colmena
    (flake-utils.lib.eachDefaultSystem
      (system:
        let
          pkgs = nixpkgs.legacyPackages.${system};
        in
        {
          devShells.default = pkgs.mkShell {
            packages = [ pkgs.colmena ];
          };
        })
    ) // {

      # Our actual deployment
      colmena = {
        meta = {
          nixpkgs = import nixpkgs {
            system = "x86_64-linux";
            # Note that the overlay has to be applied manually when using Colmena
            overlays = [ trustix.overlays.default ];
          };
        };

        # Import the Trustix NixOS modules on all machines
        defaults = { pkgs, ... }: {
          imports = [
            trustix.nixosModules.trustix
          ];
        };

        "${hostName}" = {

          # Main Trustix daemon configuration
          services.trustix = {
            enable = true;

            # Signers & publishers are separate concepts as the same key
            # could potentially be used to publish multiple logs under different Trustix subprotocols.
            #
            # If you don't know what this means: While Trustix is build for Nix first, the core can be used for other ecosystems too, not just Nix.
            signers.my-signer = {
              type = "ed25519";
              ed25519.private-key-path = "/var/lib/my-trustix-key";
            };

            publishers = [
              {
                signer = "my-signer"; # Use the key configured above
                protocol = "nix"; # This publisher is using the Nix subprotocol

                # An arbitrary (string -> string) attrset with metadata about this log
                meta = {
                  upstream = "https://cache.nixos.org";
                };

                publicKey = {
                  type = "ed25519";
                  key = builtins.readFile ./secrets/log-pub;
                };
              }
            ];

          };

          # Enable the post build hook to push builds to the main Trustix daemon
          services.trustix-nix-build-hook = {
            enable = true;
            # The logID we got earlier
            publisher = "453016597475f45532e0a22a448ea7e0fb915e950d3c8930bfd23d962d73f9c1";
          };

          deployment = {
            targetHost = hostName;
            targetUser = "root";

            # We are using the Colmena secrets facility to upload the keys to the remote
            # without ending up world readable in the Nix store.
            keys = {
              my-trustix-key = {
                keyFile = ./secrets/log-priv;

                # This mode is too open for a real world deployment but we don't want to deal
                # with the complexities of secrets management here.
                permissions = "0644";
                destDir = "/var/lib";
              };
            };

          };
        };
      };
    };
}

Enter the development shell and deploy:

$ nix develop  # Pulls in Colmena via Flakes devShells
$ colmena apply  # Deploy

Spread your log

In the next chapter we will go over how to use this log from clients. The most important thing right now is to make a note of your public key and your domain name.