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:
parent
5582a0a29b
commit
f00bacd8fe
|
@ -1,17 +1,43 @@
|
||||||
|
{ lib, ... }:
|
||||||
let
|
let
|
||||||
keys = import ./ssh-keys.nix;
|
inherit (lib) genAttrs;
|
||||||
in {
|
in
|
||||||
users.users.root.openssh.authorizedKeys.keys =
|
# Note: to add somefew in this list.
|
||||||
keys.users.delroth ++
|
# Ensure their SSH key is already in common/ssh-keys.nix with
|
||||||
keys.users.emilylange ++
|
# the same username for here, so that the keys is automatically added.
|
||||||
keys.users.hexchen ++
|
{
|
||||||
keys.users.jade ++
|
bagel.groups = {
|
||||||
keys.users.janik ++
|
floral-infra.members = [
|
||||||
keys.users.k900 ++
|
"delroth"
|
||||||
keys.users.lukegb ++
|
"emilylange"
|
||||||
keys.users.maxine ++
|
"hexchen"
|
||||||
keys.users.raito ++
|
"jade"
|
||||||
keys.users.thubrecht ++
|
"janik"
|
||||||
keys.users.yuka ++
|
"k900"
|
||||||
keys.users.winter;
|
"maxine"
|
||||||
|
"raito"
|
||||||
|
"thubrecht"
|
||||||
|
"winter"
|
||||||
|
"yuka"
|
||||||
|
];
|
||||||
|
|
||||||
|
lix-infra.members = [
|
||||||
|
"raito"
|
||||||
|
"hexchen"
|
||||||
|
"jade"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
bagel.users = genAttrs [
|
||||||
|
"delroth"
|
||||||
|
"emilylange"
|
||||||
|
"hexchen"
|
||||||
|
"jade"
|
||||||
|
"janik"
|
||||||
|
"k900"
|
||||||
|
"maxine"
|
||||||
|
"raito"
|
||||||
|
"thubrecht"
|
||||||
|
"winter"
|
||||||
|
"yuka"
|
||||||
|
] (name: {});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
69
common/server-acl.nix
Normal file
69
common/server-acl.nix
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
{ lib, config, ... }:
|
||||||
|
let
|
||||||
|
keys = import ./ssh-keys.nix;
|
||||||
|
inherit (lib) mkOption types length concatMap listToAttrs catAttrs attrValues;
|
||||||
|
cfgAdmins = config.bagel.admins;
|
||||||
|
cfgGroups = config.bagel.groups;
|
||||||
|
cfgUsers = config.bagel.users;
|
||||||
|
|
||||||
|
userOpts = { name, ... }: {
|
||||||
|
options = {
|
||||||
|
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 [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
groupOpts = { name, ... }: {
|
||||||
|
options = {
|
||||||
|
members = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
description = "List of users member of this group";
|
||||||
|
example = [ "raito" ];
|
||||||
|
default = [ ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# There might be duplicate in that list. We will turn it into an attribute set.
|
||||||
|
allowedMembers = listToAttrs (
|
||||||
|
map (member: {
|
||||||
|
name = member;
|
||||||
|
value = cfgUsers.${member};
|
||||||
|
}) (concatMap (allowedGroup: cfgGroups.${allowedGroup}.members) cfgAdmins.allowedGroups));
|
||||||
|
|
||||||
|
rootKeys = concatMap (catAttrs "sshKeys") (attrValues allowedMembers);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.bagel.users = mkOption {
|
||||||
|
type = types.submodule userOpts;
|
||||||
|
description = "User configuration for server ACLs";
|
||||||
|
};
|
||||||
|
|
||||||
|
options.bagel.groups = mkOption {
|
||||||
|
type = types.submodule groupOpts;
|
||||||
|
description = "Group configuration for server ACLs";
|
||||||
|
};
|
||||||
|
|
||||||
|
options.bagel.admins = mkOption {
|
||||||
|
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" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
}
|
|
@ -114,6 +114,13 @@
|
||||||
|
|
||||||
./services
|
./services
|
||||||
./common
|
./common
|
||||||
|
{
|
||||||
|
# This means that anyone with @floral-infra permissions
|
||||||
|
# can ssh on root of every machines handled here.
|
||||||
|
bagel.admins.allowedGroups = [
|
||||||
|
"floral-infra"
|
||||||
|
];
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
makeBuilder = i: lib.nameValuePair "builder-${toString i}" {
|
makeBuilder = i: lib.nameValuePair "builder-${toString i}" {
|
||||||
|
|
Loading…
Reference in a new issue