feat: finer-grained ACLs for server accesses

In the process of adding multi-tenant infrastructure, it seems relevant
to add finer-grained ACLs.

Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
This commit is contained in:
raito 2024-08-01 23:41:05 +02:00
parent 1cbf286f18
commit 130faa2836
4 changed files with 79 additions and 15 deletions

View file

@ -1,16 +1,21 @@
{ lib, ... }:
let let
keys = import ./ssh-keys.nix; inherit (lib) genAttrs;
in { buildInfraMembers = [
users.users.root.openssh.authorizedKeys.keys = "delroth"
keys.users.delroth ++ "emilylange"
keys.users.emilylange ++ "hexchen"
keys.users.hexchen ++ "jade"
keys.users.jade ++ "janik"
keys.users.janik ++ "k900"
keys.users.k900 ++ "maxine"
keys.users.lukegb ++ "raito"
keys.users.maxine ++ "thubrecht"
keys.users.raito ++ "yuka"
keys.users.thubrecht ++ ];
keys.users.yuka; in
} {
bagel.admins.users = genAttrs buildInfraMembers (username: {
groups = [ "build-infra" ];
});
}

View file

@ -1,6 +1,7 @@
{ {
imports = [ imports = [
./admins.nix ./admins.nix
./server-acl.nix
./base-server.nix ./base-server.nix
./hardening.nix ./hardening.nix
./nix.nix ./nix.nix

51
common/server-acl.nix Normal file
View file

@ -0,0 +1,51 @@
{ lib, config, ... }:
let
keys = import ./ssh-keys.nix;
inherit (lib) mkOption types length filterAttrs any catAttrs concatLists attrValues;
cfg = config.bagel.admins;
userOpts = { name, ... }: {
options = {
groups = mkOption {
type = types.listOf types.str;
description = "List of groups this user is part of";
example = [ "build-infra" ];
default = [ ];
};
sshKeys = mkOption {
type = types.listOf types.str;
description = "List of SSH keys associated to this user, defaults to `ssh-keys.nix` entries.";
default = keys.users.${name} or [ ];
};
};
};
isAllowedGroup = group: any (allowedGroup: group == allowedGroup) cfg.allowedGroups;
rootKeys = concatLists (catAttrs "sshKeys" (attrValues (filterAttrs (username: { groups, ... }: any isAllowedGroup groups) cfg.users)));
in
{
options.bagel.admins = {
allowedGroups = mkOption {
type = types.listOf types.str;
default = [ "catch-all" ];
description = "List of groups which are allowed to admin this machine.";
example = [ "lix" "build-infra" ];
};
users = mkOption {
type = types.attrsOf (types.submodule userOpts);
description = "Attribute set of admins with their groups and credentials, the username is the key of the attrset";
};
};
config = {
assertions = [
{ assertion = length config.users.users.root.openssh.authorizedKeys.keys > 0;
# TODO: you can add printing of `concatStringsSep ", " cfg.allowedGroups` to diagnose
# which are the allowed groups and existing admins.
message = "root@${config.networking.fqdnOrHostName} has no SSH key attached, this machine will lose its access if you deploy it successfully! Set a valid `bagel.admins.allowedGroups` or ensure you have at least one administrator of the relevant group registered";
}
];
users.users.root.openssh.authorizedKeys.keys = rootKeys;
};
}

View file

@ -92,6 +92,13 @@
./services ./services
./common ./common
{
# This means that anyone with @build-infra permissions
# can ssh on root of every machines handled here.
bagel.admins.allowedGroups = [
"build-infra"
];
}
]; ];
makeBuilder = i: lib.nameValuePair "builder-${toString i}" { makeBuilder = i: lib.nameValuePair "builder-${toString i}" {