infra/flake.nix
Raito Bezarius 1a5e5a6adb feat(systems): inject systemd-openbao project
This brings the openbao agent, a Go proxy to make the link between
systemd's LoadCredential and the openbao agent.

All that remains is to configure authentication on every system we need
to use OpenBao and then the templates for every secret we care about.

Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
2025-01-01 03:43:13 +01:00

334 lines
12 KiB
Nix

{
description = "Bagel cooking infrastructure";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
terranix.url = "github:terranix/terranix";
terranix.inputs.nixpkgs.follows = "nixpkgs";
agenix.url = "github:ryantm/agenix";
agenix.inputs.nixpkgs.follows = "nixpkgs";
colmena.url = "github:zhaofengli/colmena";
colmena.inputs = {
nixpkgs.follows = "nixpkgs";
flake-compat.follows = "flake-compat";
};
hydra.url = "git+https://git.lix.systems/lix-project/hydra.git";
hydra.inputs = {
nixpkgs.follows = "nixpkgs";
lix.inputs.flake-compat.follows = "flake-compat";
};
nix-gerrit.url = "git+https://git.lix.systems/the-distro/nix-gerrit.git";
nix-gerrit.inputs.nixpkgs.follows = "nixpkgs";
nix-forgejo.url = "git+https://git.lix.systems/the-distro/nix-forgejo.git";
nix-forgejo.flake = false;
ofborg.url = "git+https://git.lix.systems/the-distro/ofborg.git?ref=refs/heads/vcs-generalization";
ofborg.flake = false;
gerrit-dashboard.url = "git+https://git.lix.systems/the-distro/gerrit-monitoring.git";
gerrit-dashboard.flake = false;
buildbot-nix.url = "git+https://git.lix.systems/lix-project/buildbot-nix.git?ref=refs/heads/forkos";
buildbot-nix.inputs.nixpkgs.follows = "nixpkgs";
channel-scripts.url = "git+https://git.lix.systems/the-distro/channel-scripts.git";
channel-scripts.inputs.nixpkgs.follows = "nixpkgs";
channel-scripts.inputs.crane.inputs.attic.inputs.flake-compat.follows = "flake-compat";
systemd-openbao.url = "git+https://git.lix.systems/the-distro/systemd-openbao.git";
systemd-openbao.flake = false;
stateless-uptime-kuma.url = "git+https://git.dgnum.eu/DGNum/stateless-uptime-kuma.git";
stateless-uptime-kuma.flake = false;
flake-compat = {
url = "git+https://git.lix.systems/lix-project/flake-compat";
flake = false;
};
lix.follows = "hydra/lix";
grapevine = {
type = "gitlab";
host = "gitlab.computer.surgery";
owner = "matrix";
repo = "grapevine-fork";
inputs = {
nixpkgs.follows = "nixpkgs";
flake-compat.follows = "flake-compat";
attic.inputs.flake-compat.follows = "flake-compat";
};
};
};
outputs = { self, nixpkgs, terranix, colmena, ofborg, ... } @ inputs:
let
supportedSystems = [ "x86_64-linux" "aarch64-linux" ];
forEachSystem = f: builtins.listToAttrs (map (system: {
name = system;
value = f system;
}) supportedSystems);
systemBits = forEachSystem (system: rec {
inherit system;
pkgs = import nixpkgs {
localSystem = system;
overlays = [
inputs.hydra.overlays.default
inputs.lix.overlays.default
inputs.nix-gerrit.overlays.default
inputs.channel-scripts.overlays.default
(import inputs.ofborg {
pkgs = import nixpkgs { localSystem = system; };
}).overlay
(import "${inputs.stateless-uptime-kuma}/overlay.nix")
(self: super: {
openbao = super.callPackage ./services/vault/package.nix { };
})
];
};
terraform = pkgs.opentofu;
terraformCfg = terranix.lib.terranixConfiguration {
inherit system;
extraArgs = {
inherit (self) nixosConfigurations;
};
modules = [
./terraform
{
bagel.dnsimple.enable = true;
bagel.hydra.enable = true;
}
];
};
});
forEachSystem' = f: forEachSystem (system: (f systemBits.${system}));
inherit (nixpkgs) lib;
# ForkOS' library functions.
flib = import ./lib { inherit (nixpkgs) lib; };
inherit (flib) singleton;
in
{
apps = forEachSystem' ({ system, pkgs, terraformCfg, terraform, ... }: {
tf = {
type = "app";
program = toString (pkgs.writers.writeBash "tf" ''
set -eo pipefail
ln -snf ${terraformCfg} config.tf.json
exec ${lib.getExe terraform} "$@"
'');
};
default = self.apps.${system}.tf;
});
devShells = forEachSystem' ({ system, pkgs, ... }: {
default = pkgs.mkShell {
packages = [
inputs.agenix.packages.${system}.agenix
pkgs.opentofu
pkgs.openbao
(pkgs.callPackage ./lib/colmena-wrapper.nix { })
];
BAO_ADDR = "https://vault.forkos.org";
};
});
nixosConfigurations = (colmena.lib.makeHive self.outputs.colmena).nodes;
terraformConfiguration = forEachSystem' ({ terraformCfg, ... }: terraformCfg);
colmena = let
systemd-openbao = import inputs.systemd-openbao { };
commonModules = [
inputs.agenix.nixosModules.default
inputs.hydra.nixosModules.hydra
systemd-openbao.nixosModules.openbaoAgent
systemd-openbao.nixosModules.systemdOpenBaod
systemd-openbao.nixosModules.openbaoSecrets
inputs.buildbot-nix.nixosModules.buildbot-coordinator
inputs.buildbot-nix.nixosModules.buildbot-worker
./services
./common
];
floralInfraModules = commonModules ++ [
({ config, lib, ... }: {
# This means that anyone with @floral-infra permissions
# can ssh on root of every machines handled here.
bagel.admins.allowedGroups = [
"floral-infra"
];
# Tag all machines which have local boot as local bootables.
deployment.tags = lib.mkMerge [
[ "floral" ]
# All nodes that can be local booted, including baremetal nodes.
(lib.mkIf (config.bagel.baremetal.enable -> !config.bagel.baremetal.netboot)
[ "localboot" ]
)
# Only baremetal nodes that can be local booted.
(lib.mkIf (config.bagel.baremetal.enable && !config.bagel.baremetal.netboot)
[ "bm-localboot" ]
)
];
bagel.monitoring.grafana-agent.tenant = "floral";
bagel.secrets.tenant = "floral";
bagel.builders.extra-build-capacity.provider.tenant = "floral";
bagel.services.buildbot.tenant = "floral";
})
];
# These are Floral baremetal builders.
makeColoBaremetal = i:
let
enableNetboot = i >= 6;
in
# bm for baremetal.
lib.nameValuePair "bm-${toString i}" {
imports = floralInfraModules;
bagel.baremetal = { enable = true; num = i; netboot = enableNetboot; };
};
# Given the data of:
# - a selector function to filter NixOS nodes
# - a module factory function to extend a NixOS configuration
# this will return a function that will take a set of nodes and project it to the filtered
# nodes augmented with the module factory function.
# Composing twice the projector should have no effect.
# `mkSystem :: { renumberedIndex: int, node: NixOS configuration } → NixOS configuration`
mkProjector = { selector, mkSystem }: nodes:
let
# Select all the nodes using the selector.
selectedNodes = lib.filterAttrs (_: node: selector node.bagel.baremetal.num) nodes;
in
# Re-map selected nodes and renumber them in some iteration order
# and apply the module extension function.
flib.renumber
# Indexing function
(node: node.bagel.baremetal.num)
# Renumbering function
(renumberedIndex: node: mkSystem { inherit renumberedIndex node; })
selectedNodes;
# Current map:
# builders: [4, 10].
# storage: [5]
# build-coord: [11].
# Set of projectors that will take a generic baremetal node
# and reconfigure it for a specific role.
projectors = {
storage = {
# Selectors are just fancy functions that can filter based on the index information.
# It is possible to construct a range filter to express a collection of intervals,
# e.g. select 0→4 & 6→8 & 12→15.
# For now, we will only use pointwise as we have very few machines.
selector = flib.mkPointwiseFilter [ 5 ];
mkSystem = { renumberedIndex, node }:
{
imports = [ node ];
bagel.baremetal.storage = {
enable = true;
num = renumberedIndex;
};
};
};
builders = {
selector = flib.mkPointwiseFilter [ 4 10 ];
mkSystem = { renumberedIndex, node }: {
imports = [ node ];
bagel.baremetal.builders = {
enable = true;
num = renumberedIndex;
};
};
};
};
project = role: mkProjector projectors.${role};
lixInfraModules = commonModules ++ [
{
# This means that anyone with @lix-infra permissions
# can ssh on root of every machines handled here.
bagel.admins.allowedGroups = [
"lix-infra"
];
# Tag all machines which have local boot as local bootables.
# Lix has no netbootable machine.
deployment.tags = [ "localboot" "lix" ];
bagel.monitoring.grafana-agent.tenant = "lix";
bagel.secrets.tenant = "lix";
bagel.builders.extra-build-capacity.provider = {
tenant = "lix";
buildfarmPublicKeys = [
# buildbot.lix.systems SSH key
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDu4cEqZzAI/1vZjSQkTJ4ijIg9nuloOuSKUrnkJIOFn"
];
};
bagel.services.buildbot.tenant = "lix";
}
];
baremetalNodes =
let
# We consider all possible baremetal systems and we filter out a subset that is activated.
# To configure the set of used machines, configure the `setXYZ` role setter selectors.
allNodes = lib.listToAttrs (lib.genList makeColoBaremetal 11);
perRoles = {
# Project in the sense of linear algebra projectors.
# We are projecting allNodes on the set of storage nodes.
# (remember, a projector is a linear function such that p^2 = p).
storageNodes = project "storage" allNodes;
builderNodes = project "builders" allNodes;
# buildCoordinatorNodes = setBuildCoordinators allNodes;
};
in
# TODO: compute what are the offender nodes and their simultaneous roles.
assert (lib.assertMsg (flib.isValidPartition perRoles) "A baremetal node is simultaneously storage, builder and build coordinator, please review the ranges.");
# Merge all roles together into one big attribute set of nodes.
flib.chainAttrs perRoles;
in {
meta.nixpkgs = systemBits.x86_64-linux.pkgs;
# Add any non-x86_64 native systems here.
# Cross compilation is not supported yet.
meta.nodeNixpkgs =
let
aarch64-systems = systems: lib.genAttrs systems (system: systemBits.aarch64-linux.pkgs);
in
aarch64-systems [
"build01-aarch64-lix"
];
meta.specialArgs.inputs = inputs;
bagel-box.imports = floralInfraModules ++ [ ./hosts/bagel-box ];
meta01.imports = floralInfraModules ++ [ ./hosts/meta01 ];
gerrit01.imports = floralInfraModules ++ [ ./hosts/gerrit01 ];
fodwatch.imports = floralInfraModules ++ [ ./hosts/fodwatch ];
git.imports = floralInfraModules ++ [ ./hosts/git ];
wob-vpn-gw.imports = floralInfraModules ++ [ ./hosts/wob-vpn-gw ];
buildbot.imports = floralInfraModules ++ [ ./hosts/buildbot ];
public01.imports = floralInfraModules ++ [ ./hosts/public01 ];
build-coord.imports = floralInfraModules ++ [ ./hosts/build-coord ];
build01-aarch64-lix.imports = lixInfraModules ++ [ ./hosts/build01-aarch64-lix ];
buildbot-lix.imports = lixInfraModules ++ [ ./hosts/buildbot-lix ];
} // baremetalNodes;
hydraJobs = builtins.mapAttrs (n: v: v.config.system.build.netbootDir or v.config.system.build.toplevel) self.nixosConfigurations;
buildbotJobs = builtins.mapAttrs (_: v: v.config.system.build.toplevel) self.nixosConfigurations;
};
}