This commit is contained in:
Chris Kruining 2026-04-07 15:23:11 +02:00
parent 5c1e6807b6
commit cf9dcf2568
No known key found for this signature in database
GPG key ID: EB894A3560CCCAD2
12 changed files with 244 additions and 137 deletions

43
clan/flake-module.nix Normal file
View file

@ -0,0 +1,43 @@
{
lib,
inputs,
...
}: {
imports = [
./machines.nix
./tags.nix
./instances.nix
];
clan = {
meta = {
name = "arda";
domain = "arda";
description = "My personal machines at home";
};
directory = ../.;
specialArgs = {
ardaLib = {
types =
./types
|> (inputs.import-tree.withLib lib).leafs
|> lib.map (mod: {
name = mod |> lib.baseNameOf |> lib.splitString "." |> lib.head;
value = lib.types.submoduleWith {modules = [mod];};
})
|> lib.listToAttrs;
};
};
exportInterfaces =
./interfaces
|> (inputs.import-tree.withLib lib).leafs
|> lib.map (mod: {
name = mod |> lib.baseNameOf |> lib.splitString "." |> lib.head;
value = import mod;
})
|> lib.listToAttrs;
};
}

253
clan/instances.nix Normal file
View file

@ -0,0 +1,253 @@
{
self,
inputs,
...
}: let
db =
self.clan.exports
|> inputs.clan-core.lib.getExport {
serviceName = "arda/persistence";
roleName = "default";
machineName = "ulmo";
instanceName = "persistence";
}
|> (v: v.persistence.driver.${v.persistence.main});
in {
clan.inventory.instances = {
users-chris = {
module = {
name = "users";
input = "clan-core";
};
roles.default.machines.mandos.settings = {};
roles.default.machines.manwe.settings = {};
roles.default.machines.orome.settings = {};
roles.default.machines.tulkas.settings = {};
roles.default.settings = {
user = "chris";
groups = ["wheel"];
prompt = true;
share = true;
};
};
clanDns = {
module = {
name = "dm-dns";
input = "clan-core";
};
roles.default.tags = ["all"];
};
gateway = {
module = {
name = "gateway";
input = "self";
};
roles.default = {
tags = ["operational:role:gateway"];
settings = {
driver = "caddy";
hosts = {
"auth.kruining.eu" = ''
reverse_proxy h2c://[::1]:9092
'';
};
};
};
};
persistence = {
module = {
name = "persistence";
input = "self";
};
roles.default.tags = ["operational:availability:always-on" "operational:storage:large"];
};
identity = {
module = {
name = "identity";
input = "self";
};
roles.default = {
tags = ["operational:availability:always-on"];
settings = {
database = db;
organization = {
nix = {
user = {
chris = {
email = "chris@kruining.eu";
firstName = "Chris";
lastName = "Kruining";
roles = ["ORG_OWNER"];
instanceRoles = ["IAM_OWNER"];
};
kaas = {
email = "chris+kaas@kruining.eu";
firstName = "Kaas";
lastName = "Kruining";
};
};
project = {
ulmo = {
projectRoleCheck = true;
projectRoleAssertion = true;
hasProjectCheck = true;
role = {
jellyfin = {
group = "jellyfin";
};
jellyfin_admin = {
group = "jellyfin";
};
};
assign = {
chris = ["jellyfin" "jellyfin_admin"];
kaas = ["jellyfin"];
};
application = {
jellyfin = {
redirectUris = ["https://jellyfin.kruining.eu/sso/OID/redirect/zitadel"];
grantTypes = ["authorizationCode"];
responseTypes = ["code"];
};
forgejo = {
redirectUris = ["https://git.amarth.cloud/user/oauth2/zitadel/callback"];
grantTypes = ["authorizationCode"];
responseTypes = ["code"];
};
vaultwarden = {
redirectUris = ["https://vault.kruining.eu/identity/connect/oidc-signin"];
grantTypes = ["authorizationCode"];
responseTypes = ["code"];
exportMap = {
client_id = "SSO_CLIENT_ID";
client_secret = "SSO_CLIENT_SECRET";
};
};
matrix = {
redirectUris = ["https://matrix.kruining.eu/_synapse/client/oidc/callback"];
grantTypes = ["authorizationCode"];
responseTypes = ["code"];
};
mydia = {
redirectUris = ["http://localhost:2010/auth/oidc/callback"];
grantTypes = ["authorizationCode"];
responseTypes = ["code"];
};
grafana = {
redirectUris = ["http://localhost:9001/login/generic_oauth"];
grantTypes = ["authorizationCode"];
responseTypes = ["code"];
};
};
};
convex = {
projectRoleCheck = true;
projectRoleAssertion = true;
hasProjectCheck = true;
application = {
scry = {
redirectUris = ["https://nautical-salamander-320.eu-west-1.convex.cloud/api/auth/callback/zitadel"];
grantTypes = ["authorizationCode"];
responseTypes = ["code"];
};
};
};
};
action = {
flattenRoles = {
script = ''
(ctx, api) => {
if (ctx.v1.user.grants == undefined || ctx.v1.user.grants.count == 0) {
return;
}
const roles = ctx.v1.user.grants.grants.flatMap(({ roles, projectId }) => roles.map(role => projectId + ':' + role));
api.v1.claims.setClaim('nix:zitadel:custom', JSON.stringify({ roles }));
};
'';
};
};
triggers = [
{
flowType = "customiseToken";
triggerType = "preUserinfoCreation";
actions = ["flattenRoles"];
}
{
flowType = "customiseToken";
triggerType = "preAccessTokenCreation";
actions = ["flattenRoles"];
}
];
};
};
};
};
};
servarr = {
module = {
name = "servarr";
input = "self";
};
roles.default = {
tags = ["operational:availability:always-on"];
settings = {
enable = true;
database = db;
services = {
sonarr = {
rootFolders = [
"/var/media/series"
];
};
radarr = {
rootFolders = [
"/var/media/movies"
];
};
lidarr = {
rootFolders = [
"/var/media/music"
];
};
prowlarr = {};
};
};
};
};
};
}

View file

@ -0,0 +1,54 @@
{lib, ...}: let
inherit (lib) mkOption types;
in {
options = {
services = mkOption {
type = types.attrsOf (types.submodule ({name, ...}: {
options = {
name = mkOption {
type = types.str;
default = name;
};
endpoint = mkOption {
type = types.submoduleWith {
modules = [../types/endpoint.nix];
};
default = name;
};
# protocol = mkOption {
# type = types.str;
# default = "http";
# };
# host = mkOption {
# type = types.str;
# default = "[::1]";
# };
# port = mkOption {
# type = types.port;
# };
};
}));
default = {};
};
functions = mkOption {
type = types.attrsOf (types.submodule ({name, ...}: {
options = {
name = mkOption {
type = types.str;
default = name;
};
body = mkOption {
type = types.str;
};
};
}));
default = {};
};
};
}

View file

@ -0,0 +1,24 @@
{lib, ...}: let
inherit (lib) mkOption types;
in {
options = {
main = mkOption {
type = types.nullOr types.str;
default = null;
};
driver = mkOption {
type = types.attrsOf (types.submoduleWith {
modules = [
../types/endpoint.nix
];
});
default = {};
};
databases = mkOption {
type = types.listOf types.str;
default = [];
};
};
}

75
clan/machines.nix Normal file
View file

@ -0,0 +1,75 @@
{...}: {
clan.inventory.machines = {
aule = {
name = "aule";
description = "Planned build server.";
machineClass = "nixos";
tags = [];
};
mandos = {
name = "mandos";
description = "Living room Steam box.";
machineClass = "nixos";
tags = [
"capability:mobility:stationary"
"operational:availability:wake-on-demand"
];
};
manwe = {
name = "manwe";
description = "Main desktop.";
machineClass = "nixos";
tags = [
"capability:mobility:stationary"
"operational:availability:manual"
];
};
melkor = {
name = "melkor";
description = "Planned machine with no defined role yet.";
machineClass = "nixos";
tags = [];
};
orome = {
name = "orome";
description = "Work laptop.";
machineClass = "nixos";
tags = [
"capability:mobility:portable"
"operational:availability:manual"
];
};
tulkas = {
name = "tulkas";
description = "Steam Deck.";
machineClass = "nixos";
tags = [
"capability:mobility:portable"
"operational:availability:manual"
];
};
ulmo = {
name = "ulmo";
description = "Primary self-hosted services machine.";
machineClass = "nixos";
tags = [
"capability:mobility:stationary"
"operational:availability:always-on"
"operational:storage:large"
"operational:role:gateway"
];
};
varda = {
name = "varda";
description = "Planned machine with no defined role yet.";
machineClass = "nixos";
tags = [];
};
yavanna = {
name = "yavanna";
description = "Planned machine with no defined role yet.";
machineClass = "nixos";
tags = [];
};
};
}

12
clan/tags.nix Normal file
View file

@ -0,0 +1,12 @@
{...}: {
clan.inventory.tags = {
config,
machines,
...
}: {
# tag_name = [ "list" "of" "machines" ]
"capability:hardware:gpu" = [""];
"capability:hardware:audio" = [""];
"capability:hardware:bluetooth" = [""];
};
}

44
clan/types/endpoint.nix Normal file
View file

@ -0,0 +1,44 @@
{lib, ...}: let
inherit (lib) mkOption types;
in {
options = {
host = mkOption {
type = types.str;
default = "localhost";
};
port = mkOption {
type = types.port;
};
protocol = mkOption {
type = types.nullOr types.str;
default = null;
};
user = mkOption {
type = types.nullOr types.str;
default = null;
};
password = mkOption {
type = types.nullOr types.str;
default = null;
};
path = mkOption {
type = types.nullOr types.str;
default = null;
};
query = mkOption {
type = types.nullOr (types.attrsOf types.str);
default = null;
};
hash = mkOption {
type = types.nullOr (types.attrsOf types.str);
default = null;
};
};
}