Compare commits
No commits in common. "64bc77a73e95b74e5915021e3c2ee581652be3b8" and "59e8ca812c06bb0dae11636bb12602e69660b46e" have entirely different histories.
64bc77a73e
...
59e8ca812c
13 changed files with 188 additions and 612 deletions
|
|
@ -14,47 +14,7 @@ in {
|
||||||
type = types.submoduleWith {
|
type = types.submoduleWith {
|
||||||
modules = [../types/endpoint.nix];
|
modules = [../types/endpoint.nix];
|
||||||
};
|
};
|
||||||
default = {};
|
default = name;
|
||||||
apply = attrs:
|
|
||||||
attrs
|
|
||||||
// {
|
|
||||||
__toString = self: let
|
|
||||||
protocol =
|
|
||||||
if self.protocol != null
|
|
||||||
then "${self.protocol}://"
|
|
||||||
else "";
|
|
||||||
|
|
||||||
port =
|
|
||||||
if self.port != null
|
|
||||||
then ":${toString self.port}"
|
|
||||||
else "";
|
|
||||||
|
|
||||||
path =
|
|
||||||
if self.path != null
|
|
||||||
then "/${self.path}"
|
|
||||||
else "";
|
|
||||||
|
|
||||||
query =
|
|
||||||
if self.query != null
|
|
||||||
then "?${toString self.query
|
|
||||||
|> lib.attrsToList
|
|
||||||
|> lib.map ({
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
}: "${name}=${value}")}"
|
|
||||||
else "";
|
|
||||||
|
|
||||||
hash =
|
|
||||||
if self.hash != null
|
|
||||||
then "#${toString self.hash
|
|
||||||
|> lib.attrsToList
|
|
||||||
|> lib.map ({
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
}: "${name}=${value}")}"
|
|
||||||
else "";
|
|
||||||
in "${protocol}${self.host}${port}${path}${query}${hash}";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# protocol = mkOption {
|
# protocol = mkOption {
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,17 @@
|
||||||
inherit (lib) mkOption types;
|
inherit (lib) mkOption types;
|
||||||
in {
|
in {
|
||||||
options = {
|
options = {
|
||||||
protocol = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "http";
|
|
||||||
};
|
|
||||||
|
|
||||||
host = mkOption {
|
host = mkOption {
|
||||||
type = types.str;
|
type = types.str;
|
||||||
default = "localhost";
|
default = "localhost";
|
||||||
};
|
};
|
||||||
|
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
type = types.nullOr types.port;
|
type = types.port;
|
||||||
|
};
|
||||||
|
|
||||||
|
protocol = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
default = null;
|
default = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,12 +49,14 @@ in {
|
||||||
|> lib.concatLists
|
|> lib.concatLists
|
||||||
|> lib.map ({
|
|> lib.map ({
|
||||||
name,
|
name,
|
||||||
endpoint,
|
protocol,
|
||||||
|
host,
|
||||||
|
port,
|
||||||
}: {
|
}: {
|
||||||
name = "${name}.${machine.name}.arda";
|
name = "${name}.${machine.name}.arda";
|
||||||
value = {
|
value = {
|
||||||
extraConfig = ''
|
extraConfig = ''
|
||||||
reverse_proxy ${toString endpoint}
|
reverse_proxy ${protocol}://${host}:${toString port}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,14 @@
|
||||||
exports,
|
exports,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (builtins) toString readFile;
|
inherit (builtins) toString;
|
||||||
inherit (lib) mkMerge mkIf;
|
|
||||||
in {
|
in {
|
||||||
_class = "clan.service";
|
_class = "clan.service";
|
||||||
manifest = {
|
manifest = {
|
||||||
name = "arda/identity";
|
name = "arda/identity";
|
||||||
description = ''
|
description = ''
|
||||||
'';
|
'';
|
||||||
readme = readFile ./README.md;
|
readme = builtins.readFile ./README.md;
|
||||||
exports = {
|
exports = {
|
||||||
inputs = ["persistence"];
|
inputs = ["persistence"];
|
||||||
out = ["gateway" "persistence"];
|
out = ["gateway" "persistence"];
|
||||||
|
|
@ -32,7 +31,7 @@ in {
|
||||||
};
|
};
|
||||||
|
|
||||||
database = mkOption {
|
database = mkOption {
|
||||||
type = types.anything;
|
type = types.anything; #ardaLib.types.endpoint;
|
||||||
};
|
};
|
||||||
|
|
||||||
port = mkOption {
|
port = mkOption {
|
||||||
|
|
@ -333,15 +332,22 @@ in {
|
||||||
mkExports,
|
mkExports,
|
||||||
settings,
|
settings,
|
||||||
machine,
|
machine,
|
||||||
instanceName,
|
|
||||||
...
|
...
|
||||||
}: {
|
}: let
|
||||||
exports = mkExports (mkMerge [
|
database =
|
||||||
{
|
exports
|
||||||
gateway.services.identity = {endpoint.port = settings.port;};
|
|> clanLib.getExport {
|
||||||
|
serviceName = "arda/persistence";
|
||||||
|
roleName = "default";
|
||||||
|
machineName = machine.name;
|
||||||
|
instanceName = settings.persistence_instance;
|
||||||
}
|
}
|
||||||
(mkIf (settings.driver == "zitadel") {
|
|> (v: v.persistence.driver.postgresql);
|
||||||
gateway.functions.auth = {
|
in {
|
||||||
|
exports = mkExports {
|
||||||
|
gateway = {
|
||||||
|
services.identity = {endpoint.port = settings.port;};
|
||||||
|
functions.auth = {
|
||||||
body = ''
|
body = ''
|
||||||
forward_auth h2c://[::1]:${toString settings.port} {
|
forward_auth h2c://[::1]:${toString settings.port} {
|
||||||
uri /api/authz/forward-auth
|
uri /api/authz/forward-auth
|
||||||
|
|
@ -349,26 +355,21 @@ in {
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
persistence.databases = ["zitadel"];
|
persistence.databases = ["zitadel"];
|
||||||
})
|
};
|
||||||
]);
|
|
||||||
|
|
||||||
nixosModule = args@{
|
nixosModule = {
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
config,
|
config,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
vars = config.clan.core.vars.generators.zitadel.files;
|
inherit (lib) mkMerge mkIf;
|
||||||
users = config.clan.core.vars.generators.zitadel_users.files.users.path;
|
|
||||||
email_password = config.clan.core.vars.generators.zitadel_email_password.files.password.path;
|
|
||||||
|
|
||||||
ardaLib = import ../../lib/strings.nix args;
|
|
||||||
zLib = import ./lib.nix (args // {inherit settings ardaLib;});
|
|
||||||
in {
|
in {
|
||||||
config = mkMerge [
|
config = mkMerge [
|
||||||
(mkIf (settings.driver == "zitadel") ({
|
(lib.mkIf (settings.driver == "zitadel") {
|
||||||
clan.core.vars.generators.zitadel = {
|
clan.core.vars.generators.zitadel = {
|
||||||
dependencies = ["persistence"];
|
dependencies = ["persistence"];
|
||||||
|
|
||||||
|
|
@ -386,29 +387,12 @@ in {
|
||||||
group = "zitadel";
|
group = "zitadel";
|
||||||
restartUnits = ["zitadel.service"];
|
restartUnits = ["zitadel.service"];
|
||||||
};
|
};
|
||||||
|
|
||||||
infraPrivateKey = {
|
|
||||||
deploy = true;
|
|
||||||
owner = "zitadel";
|
|
||||||
group = "zitadel";
|
|
||||||
restartUnits = ["zitadel.service"];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
infraPublicKey = {
|
runtimeInputs = with pkgs; [pwgen];
|
||||||
deploy = true;
|
|
||||||
owner = "zitadel";
|
|
||||||
group = "zitadel";
|
|
||||||
restartUnits = ["zitadel.service"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
runtimeInputs = with pkgs; [pwgen openssl_3_5];
|
|
||||||
script = ''
|
script = ''
|
||||||
pwgen -s 32 1 > $out/masterKey
|
pwgen -s 32 1 > $out/masterKey
|
||||||
|
|
||||||
openssl genrsa -traditional -out $out/infraPrivateKey 2048
|
|
||||||
openssl rsa -pubout -in $out/infraPrivateKey -out $out/infraPublicKey
|
|
||||||
|
|
||||||
cat << EOL > $out/settings
|
cat << EOL > $out/settings
|
||||||
Database:
|
Database:
|
||||||
postgres:
|
postgres:
|
||||||
|
|
@ -420,56 +404,18 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
clan.core.vars.generators.zitadel_users = {
|
|
||||||
files = {
|
|
||||||
users = {
|
|
||||||
deploy = true;
|
|
||||||
owner = "zitadel";
|
|
||||||
group = "zitadel";
|
|
||||||
restartUnits = ["infra-zitadel.service"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
script = ''
|
|
||||||
echo "{}" > $out/users
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
clan.core.vars.generators.zitadel_email_password = {
|
|
||||||
prompts = {
|
|
||||||
password = {
|
|
||||||
description = "password to email for zitadel's smpt connection";
|
|
||||||
type = "hidden";
|
|
||||||
persist = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
files = {
|
|
||||||
password = {
|
|
||||||
deploy = true;
|
|
||||||
owner = "zitadel";
|
|
||||||
group = "zitadel";
|
|
||||||
restartUnits = ["infra-zitadel.service"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
script = ''
|
|
||||||
cat $prompts/password > $out/password
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
environment.systemPackages = with pkgs; [
|
||||||
zitadel
|
zitadel
|
||||||
];
|
];
|
||||||
|
|
||||||
services.zitadel = {
|
services.zitadel = {
|
||||||
enable = true;
|
enable = true;
|
||||||
masterKeyFile = vars.masterKey.path;
|
masterKeyFile = config.clan.core.vars.generators.zitadel.files.masterKey.path;
|
||||||
|
|
||||||
tlsMode = "external";
|
tlsMode = "external";
|
||||||
|
|
||||||
extraSettingsPaths = [
|
extraSettingsPaths = [
|
||||||
vars.settings.path
|
config.clan.core.vars.generators.zitadel.files.settings.path
|
||||||
];
|
];
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
|
|
@ -491,7 +437,7 @@ in {
|
||||||
Database.postgres = {
|
Database.postgres = {
|
||||||
Host = settings.database.host;
|
Host = settings.database.host;
|
||||||
Port = settings.database.port;
|
Port = settings.database.port;
|
||||||
Database = "zitadel";
|
Databae = "zitadel";
|
||||||
User = {
|
User = {
|
||||||
Username = "zitadel";
|
Username = "zitadel";
|
||||||
};
|
};
|
||||||
|
|
@ -499,18 +445,15 @@ in {
|
||||||
Username = "zitadel";
|
Username = "zitadel";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
SystemAPIUsers = {
|
steps = {
|
||||||
infra = {
|
InstanceName = "eu";
|
||||||
Path = vars.infraPublicKey.path;
|
|
||||||
Memberships = [
|
MachineKeyPath = "/var/lib/zitadel/machine-key.json";
|
||||||
{ MemberType = "System"; Roles = [ "SYSTEM_OWNER" "IAM_OWNER" "ORG_OWNER" ]; }
|
|
||||||
];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
})
|
||||||
};
|
|
||||||
} // (zLib.createInfra { inherit users email_password; key_file = vars.infraPrivateKey.path; })))
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,372 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
ardaLib,
|
|
||||||
self,
|
|
||||||
pkgs,
|
|
||||||
settings,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
createTerranixModule = {
|
|
||||||
users,
|
|
||||||
email_password,
|
|
||||||
key_file,
|
|
||||||
...
|
|
||||||
}: terra: let
|
|
||||||
inherit (lib) toUpper toSentenceCase nameValuePair mapAttrs mapAttrs' concatMapAttrs concatMapStringsSep filterAttrsRecursive listToAttrs imap0 head drop length literalExpression attrNames;
|
|
||||||
inherit (ardaLib) toSnakeCase;
|
|
||||||
inherit (terra.lib) tfRef;
|
|
||||||
|
|
||||||
_refTypeMap = {
|
|
||||||
org = {type = "org";};
|
|
||||||
project = {type = "project";};
|
|
||||||
user = {
|
|
||||||
type = "user";
|
|
||||||
tfType = "human_user";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
mapRef' = {
|
|
||||||
type,
|
|
||||||
tfType ? type,
|
|
||||||
}: name: {"${type}Id" = "\${ resource.zitadel_${tfType}.${toSnakeCase name}.id }";};
|
|
||||||
mapRef = type: name: mapRef' (_refTypeMap.${type}) name;
|
|
||||||
mapEnum = prefix: value: "${prefix}_${value |> toSnakeCase |> toUpper}";
|
|
||||||
|
|
||||||
mapValue = type: value: ({
|
|
||||||
appType = mapEnum "OIDC_APP_TYPE" value;
|
|
||||||
grantTypes = map (t: mapEnum "OIDC_GRANT_TYPE" t) value;
|
|
||||||
responseTypes = map (t: mapEnum "OIDC_RESPONSE_TYPE" t) value;
|
|
||||||
authMethodType = mapEnum "OIDC_AUTH_METHOD_TYPE" value;
|
|
||||||
|
|
||||||
flowType = mapEnum "FLOW_TYPE" value;
|
|
||||||
triggerType = mapEnum "TRIGGER_TYPE" value;
|
|
||||||
accessTokenType = mapEnum "OIDC_TOKEN_TYPE" value;
|
|
||||||
}."${type}" or value);
|
|
||||||
|
|
||||||
toResource = name: value:
|
|
||||||
nameValuePair
|
|
||||||
(toSnakeCase name)
|
|
||||||
(lib.mapAttrs' (k: v: nameValuePair (toSnakeCase k) (mapValue k v)) value);
|
|
||||||
|
|
||||||
withRef = type: name: attrs: attrs // (mapRef type name);
|
|
||||||
|
|
||||||
select = keys: callback: set:
|
|
||||||
if (length keys) == 0
|
|
||||||
then mapAttrs' callback set
|
|
||||||
else let
|
|
||||||
key = head keys;
|
|
||||||
in
|
|
||||||
concatMapAttrs (k: v: select (drop 1 keys) (callback k) (v.${key} or {})) set;
|
|
||||||
|
|
||||||
append = attrList: set: set // (listToAttrs attrList);
|
|
||||||
|
|
||||||
forEach = src: key: set: let
|
|
||||||
_key = concatMapStringsSep "_" (k: "\${item.${k}}") key;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
forEach = tfRef '' {
|
|
||||||
for item in ${src} :
|
|
||||||
"''${item.org}_''${item.name}" => item
|
|
||||||
}'';
|
|
||||||
}
|
|
||||||
// set;
|
|
||||||
in {
|
|
||||||
terraform.required_providers.zitadel = {
|
|
||||||
source = "zitadel/zitadel";
|
|
||||||
version = "2.2.0";
|
|
||||||
};
|
|
||||||
|
|
||||||
provider.zitadel = {
|
|
||||||
domain = "auth.kruining.eu";
|
|
||||||
insecure = false;
|
|
||||||
|
|
||||||
system_api = {
|
|
||||||
user = "infra";
|
|
||||||
inherit key_file;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
locals = {
|
|
||||||
extra_users = tfRef "
|
|
||||||
flatten([ for org, users in jsondecode(file(\"${users}\")): [
|
|
||||||
for name, details in users: {
|
|
||||||
org = org
|
|
||||||
name = name
|
|
||||||
email = details.email
|
|
||||||
firstName = details.firstName
|
|
||||||
lastName = details.lastName
|
|
||||||
}
|
|
||||||
] ])
|
|
||||||
";
|
|
||||||
orgs = settings.organization |> mapAttrs (org: _: tfRef "resource.zitadel_org.${org}.id");
|
|
||||||
};
|
|
||||||
|
|
||||||
resource = {
|
|
||||||
# Organizations
|
|
||||||
zitadel_org =
|
|
||||||
settings.organization
|
|
||||||
|> select [] (
|
|
||||||
name: {isDefault, ...}:
|
|
||||||
{inherit name isDefault;}
|
|
||||||
|> toResource name
|
|
||||||
);
|
|
||||||
|
|
||||||
# Projects per organization
|
|
||||||
zitadel_project =
|
|
||||||
settings.organization
|
|
||||||
|> select ["project"] (
|
|
||||||
org: name: {
|
|
||||||
hasProjectCheck,
|
|
||||||
privateLabelingSetting,
|
|
||||||
projectRoleAssertion,
|
|
||||||
projectRoleCheck,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
inherit name hasProjectCheck privateLabelingSetting projectRoleAssertion projectRoleCheck;
|
|
||||||
}
|
|
||||||
|> withRef "org" org
|
|
||||||
|> toResource "${org}_${name}"
|
|
||||||
);
|
|
||||||
|
|
||||||
# Each OIDC app per project
|
|
||||||
zitadel_application_oidc =
|
|
||||||
settings.organization
|
|
||||||
|> select ["project" "application"] (
|
|
||||||
org: project: name: {
|
|
||||||
redirectUris,
|
|
||||||
grantTypes,
|
|
||||||
responseTypes,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
inherit name redirectUris grantTypes responseTypes;
|
|
||||||
|
|
||||||
accessTokenRoleAssertion = true;
|
|
||||||
idTokenRoleAssertion = true;
|
|
||||||
accessTokenType = "JWT";
|
|
||||||
}
|
|
||||||
|> withRef "org" org
|
|
||||||
|> withRef "project" "${org}_${project}"
|
|
||||||
|> toResource "${org}_${project}_${name}"
|
|
||||||
);
|
|
||||||
|
|
||||||
# Each project role
|
|
||||||
zitadel_project_role =
|
|
||||||
settings.organization
|
|
||||||
|> select ["project" "role"] (
|
|
||||||
org: project: name: value:
|
|
||||||
{
|
|
||||||
inherit (value) displayName group;
|
|
||||||
roleKey = name;
|
|
||||||
}
|
|
||||||
|> withRef "org" org
|
|
||||||
|> withRef "project" "${org}_${project}"
|
|
||||||
|> toResource "${org}_${project}_${name}"
|
|
||||||
);
|
|
||||||
|
|
||||||
# Each project role assignment
|
|
||||||
zitadel_user_grant =
|
|
||||||
settings.organization
|
|
||||||
|> select ["project" "assign"] (
|
|
||||||
org: project: user: roles:
|
|
||||||
{roleKeys = roles;}
|
|
||||||
|> withRef "org" org
|
|
||||||
|> withRef "project" "${org}_${project}"
|
|
||||||
|> withRef "user" "${org}_${user}"
|
|
||||||
|> toResource "${org}_${project}_${user}"
|
|
||||||
);
|
|
||||||
|
|
||||||
# Users
|
|
||||||
zitadel_human_user =
|
|
||||||
settings.organization
|
|
||||||
|> select ["user"] (
|
|
||||||
org: name: {
|
|
||||||
email,
|
|
||||||
userName,
|
|
||||||
firstName,
|
|
||||||
lastName,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
inherit email userName firstName lastName;
|
|
||||||
|
|
||||||
isEmailVerified = true;
|
|
||||||
lifecycle = {
|
|
||||||
ignore_changes = ["first_name" "last_name" "user_name"];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|> withRef "org" org
|
|
||||||
|> toResource "${org}_${name}"
|
|
||||||
)
|
|
||||||
|> append [
|
|
||||||
(forEach "local.extra_users" ["org" "name"] {
|
|
||||||
orgId = tfRef "local.orgs[each.value.org]";
|
|
||||||
userName = tfRef "each.value.name";
|
|
||||||
email = tfRef "each.value.email";
|
|
||||||
firstName = tfRef "each.value.firstName";
|
|
||||||
lastName = tfRef "each.value.lastName";
|
|
||||||
|
|
||||||
isEmailVerified = true;
|
|
||||||
}
|
|
||||||
|> toResource "extraUsers")
|
|
||||||
];
|
|
||||||
|
|
||||||
# Global user roles
|
|
||||||
zitadel_instance_member =
|
|
||||||
settings.organization
|
|
||||||
|> filterAttrsRecursive (n: v: !(v ? "instanceRoles" && (length v.instanceRoles) == 0))
|
|
||||||
|> select ["user"] (
|
|
||||||
org: name: {instanceRoles, ...}:
|
|
||||||
{roles = instanceRoles;}
|
|
||||||
|> withRef "user" "${org}_${name}"
|
|
||||||
|> toResource "${org}_${name}"
|
|
||||||
);
|
|
||||||
|
|
||||||
# Organazation specific roles
|
|
||||||
zitadel_org_member =
|
|
||||||
settings.organization
|
|
||||||
|> filterAttrsRecursive (n: v: !(v ? "roles" && (length v.roles) == 0))
|
|
||||||
|> select ["user"] (
|
|
||||||
org: name: {roles, ...}:
|
|
||||||
{inherit roles;}
|
|
||||||
|> withRef "org" org
|
|
||||||
|> withRef "user" "${org}_${name}"
|
|
||||||
|> toResource "${org}_${name}"
|
|
||||||
);
|
|
||||||
|
|
||||||
# Organazation's actions
|
|
||||||
zitadel_action =
|
|
||||||
settings.organization
|
|
||||||
|> select ["action"] (
|
|
||||||
org: name: {
|
|
||||||
timeout,
|
|
||||||
allowedToFail,
|
|
||||||
script,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
inherit allowedToFail name;
|
|
||||||
timeout = "${toString timeout}s";
|
|
||||||
script = "const ${name} = ${script}";
|
|
||||||
}
|
|
||||||
|> withRef "org" org
|
|
||||||
|> toResource "${org}_${name}"
|
|
||||||
);
|
|
||||||
|
|
||||||
# Organazation's action assignments
|
|
||||||
zitadel_trigger_actions =
|
|
||||||
settings.organization
|
|
||||||
|> concatMapAttrs (
|
|
||||||
org: {triggers, ...}:
|
|
||||||
triggers
|
|
||||||
|> imap0 (i: {
|
|
||||||
flowType,
|
|
||||||
triggerType,
|
|
||||||
actions,
|
|
||||||
...
|
|
||||||
}: (
|
|
||||||
let
|
|
||||||
name = "trigger_${toString i}";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
inherit flowType triggerType;
|
|
||||||
|
|
||||||
actionIds =
|
|
||||||
actions
|
|
||||||
|> map (action: (tfRef "zitadel_action.${org}_${toSnakeCase action}.id"));
|
|
||||||
}
|
|
||||||
|> withRef "org" org
|
|
||||||
|> toResource "${org}_${name}"
|
|
||||||
))
|
|
||||||
|> listToAttrs
|
|
||||||
);
|
|
||||||
|
|
||||||
# SMTP config
|
|
||||||
zitadel_smtp_config.default = {
|
|
||||||
sender_address = "chris@kruining.eu";
|
|
||||||
sender_name = "no-reply (Zitadel)";
|
|
||||||
tls = true;
|
|
||||||
host = "black-mail.nl:587";
|
|
||||||
user = "chris@kruining.eu";
|
|
||||||
password = tfRef "file(\"${email_password}\")";
|
|
||||||
set_active = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Client credentials per app
|
|
||||||
local_sensitive_file =
|
|
||||||
settings.organization
|
|
||||||
|> select ["project" "application"] (
|
|
||||||
org: project: name: {exportMap, ...}:
|
|
||||||
nameValuePair "${org}_${project}_${name}" {
|
|
||||||
content = ''
|
|
||||||
${
|
|
||||||
if exportMap.client_id != null
|
|
||||||
then exportMap.client_id
|
|
||||||
else "CLIENT_ID"
|
|
||||||
}=${tfRef "resource.zitadel_application_oidc.${org}_${project}_${name}.client_id"}
|
|
||||||
${
|
|
||||||
if exportMap.client_secret != null
|
|
||||||
then exportMap.client_secret
|
|
||||||
else "CLIENT_SECRET"
|
|
||||||
}=${tfRef "resource.zitadel_application_oidc.${org}_${project}_${name}.client_secret"}
|
|
||||||
'';
|
|
||||||
filename = "/var/lib/zitadel/clients/${org}_${project}_${name}";
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
createInfra = args @ {...}: let
|
|
||||||
tofu = "${lib.getExe pkgs.opentofu} -input=false";
|
|
||||||
terraformConfiguration = self.inputs.terranix.lib.terranixConfiguration {
|
|
||||||
system = pkgs.stdenv.hostPlatform.system;
|
|
||||||
modules = [
|
|
||||||
(createTerranixModule args)
|
|
||||||
];
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
systemd.services."infra-zitadel" = {
|
|
||||||
description = "Infra for Zitadel";
|
|
||||||
|
|
||||||
wantedBy = ["multi-user.target"];
|
|
||||||
wants = ["zitadel.service"];
|
|
||||||
after = ["zitadel.service"];
|
|
||||||
|
|
||||||
preStart = ''
|
|
||||||
install -d -m 0770 -o zitadel -g media /var/lib/infra-zitadel
|
|
||||||
'';
|
|
||||||
|
|
||||||
script = ''
|
|
||||||
# Sleep for a bit to give the service a chance to start up
|
|
||||||
sleep 5s
|
|
||||||
|
|
||||||
if [ "$(systemctl is-active zitadel)" != "active" ]; then
|
|
||||||
echo "zitadel is not running"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Print the path to the source for easier debugging
|
|
||||||
echo "config location: ${terraformConfiguration}"
|
|
||||||
|
|
||||||
# Copy infra code into workspace
|
|
||||||
cp -f ${terraformConfiguration} config.tf.json
|
|
||||||
|
|
||||||
# Initialize OpenTofu
|
|
||||||
${tofu} init
|
|
||||||
|
|
||||||
# Run the infrastructure code
|
|
||||||
${tofu} plan -out=tfplan
|
|
||||||
${tofu} apply -json -auto-approve tfplan
|
|
||||||
'';
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "oneshot";
|
|
||||||
User = "zitadel";
|
|
||||||
Group = "zitadel";
|
|
||||||
|
|
||||||
StateDirectory = "/var/lib/infra-zitadel";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -92,7 +92,17 @@ in {
|
||||||
services = settings.services |> lib.attrNames;
|
services = settings.services |> lib.attrNames;
|
||||||
service_count = services |> lib.length;
|
service_count = services |> lib.length;
|
||||||
|
|
||||||
servarr = import ./lib.nix (args // {inherit settings;});
|
database =
|
||||||
|
exports
|
||||||
|
|> clanLib.getExport {
|
||||||
|
serviceName = "arda/persistence";
|
||||||
|
roleName = "default";
|
||||||
|
machineName = machine.name;
|
||||||
|
instanceName = settings.persistence_instance;
|
||||||
|
}
|
||||||
|
|> (v: v.persistence.driver.postgresql);
|
||||||
|
|
||||||
|
servarr = import ./lib.nix (args // {inherit settings database;});
|
||||||
in {
|
in {
|
||||||
imports = [
|
imports = [
|
||||||
(import ./sabnzbd.nix (args
|
(import ./sabnzbd.nix (args
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
pkgs,
|
||||||
settings,
|
settings,
|
||||||
|
database,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (lib) mkIf;
|
inherit (lib) mkIf;
|
||||||
|
|
@ -67,8 +68,8 @@
|
||||||
|
|
||||||
# Password provided via environment file
|
# Password provided via environment file
|
||||||
postgres = {
|
postgres = {
|
||||||
host = settings.database.host;
|
host = database.host;
|
||||||
port = toString settings.database.port;
|
port = toString database.port;
|
||||||
user = service;
|
user = service;
|
||||||
maindb = service;
|
maindb = service;
|
||||||
logdb = service;
|
logdb = service;
|
||||||
|
|
@ -99,7 +100,7 @@
|
||||||
wants = ["${service}.service"];
|
wants = ["${service}.service"];
|
||||||
|
|
||||||
preStart = ''
|
preStart = ''
|
||||||
install -d -m 0770 -o ${service} -g media /var/lib/infra-${service}
|
install -d -m 0770 -o ${service} -g media /var/lib/${service}-apply-infra
|
||||||
${
|
${
|
||||||
options.rootFolders
|
options.rootFolders
|
||||||
|> lib.map (folder: "install -d -m 0770 -o media -g media ${folder}")
|
|> lib.map (folder: "install -d -m 0770 -o media -g media ${folder}")
|
||||||
|
|
@ -322,7 +323,11 @@ in {
|
||||||
clan.core.vars.generators.${service} = createGenerator (args // {inherit service options;});
|
clan.core.vars.generators.${service} = createGenerator (args // {inherit service options;});
|
||||||
services.${service} = createService (args // {inherit service options;});
|
services.${service} = createService (args // {inherit service options;});
|
||||||
|
|
||||||
systemd.services."infra-${service}" = lib.mkIf settings.enable (createSystemdService (args // {inherit service options;}));
|
# services.caddy.virtualHosts."${service}.ulmo.arda".extraConfig = ''
|
||||||
|
# reverse_proxy http://[::1]:${toString options.port}
|
||||||
|
# '';
|
||||||
|
|
||||||
|
systemd.services."${service}-apply-infra" = lib.mkIf settings.enable (createSystemdService (args // {inherit service options;}));
|
||||||
})
|
})
|
||||||
|> lib.mkMerge;
|
|> lib.mkMerge;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
27
lib/default.nix
Normal file
27
lib/default.nix
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
inputs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
inherit (lib) mkOption types;
|
||||||
|
in {
|
||||||
|
imports = [
|
||||||
|
./options
|
||||||
|
./strings
|
||||||
|
];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
_module.args = {
|
||||||
|
inherit
|
||||||
|
baseNixosModules
|
||||||
|
channelConfig
|
||||||
|
mkPkgs
|
||||||
|
sharedContext
|
||||||
|
systemOverlays
|
||||||
|
;
|
||||||
|
};
|
||||||
|
|
||||||
|
flake.lib = config.localLib;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
{lib, ...}: let
|
|
||||||
inherit (lib) mkOption types;
|
|
||||||
in {
|
|
||||||
mkUrlOptions = defaults: {
|
|
||||||
host =
|
|
||||||
mkOption {
|
|
||||||
type = types.str;
|
|
||||||
example = "host.tld";
|
|
||||||
description = ''
|
|
||||||
Hostname
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
// (defaults.host or {});
|
|
||||||
|
|
||||||
port =
|
|
||||||
mkOption {
|
|
||||||
type = types.port;
|
|
||||||
default = 1234;
|
|
||||||
example = "1234";
|
|
||||||
description = ''
|
|
||||||
Port
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
// (defaults.port or {});
|
|
||||||
|
|
||||||
protocol =
|
|
||||||
mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "https";
|
|
||||||
example = "https";
|
|
||||||
description = ''
|
|
||||||
Which protocol to use when creating a url string
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
// (defaults.protocol or {});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
35
lib/options/default.nix
Normal file
35
lib/options/default.nix
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
{lib, ...}: let
|
||||||
|
inherit (lib) mkOption types;
|
||||||
|
in {
|
||||||
|
localLib.options = {
|
||||||
|
mkUrlOptions =
|
||||||
|
defaults:
|
||||||
|
{
|
||||||
|
host = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "host.tld";
|
||||||
|
description = ''
|
||||||
|
Hostname
|
||||||
|
'';
|
||||||
|
} // (defaults.host or {});
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 1234;
|
||||||
|
example = "1234";
|
||||||
|
description = ''
|
||||||
|
Port
|
||||||
|
'';
|
||||||
|
} // (defaults.port or {});
|
||||||
|
|
||||||
|
protocol = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "https";
|
||||||
|
example = "https";
|
||||||
|
description = ''
|
||||||
|
Which protocol to use when creating a url string
|
||||||
|
'';
|
||||||
|
} // (defaults.protocol or {});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
{lib, ...}: let
|
|
||||||
inherit (builtins) isString typeOf match toString head;
|
|
||||||
inherit (lib) throwIfNot concatStringsSep splitStringBy toLower map concatMapAttrsStringSep;
|
|
||||||
in {
|
|
||||||
#========================================================================================
|
|
||||||
# Converts a string to snake case
|
|
||||||
#
|
|
||||||
# simply replaces any uppercase letter to its lowercase variant preceeded by an underscore
|
|
||||||
#========================================================================================
|
|
||||||
toSnakeCase = str:
|
|
||||||
throwIfNot (isString str) "toSnakeCase only accepts string values, but got ${typeOf str}" (
|
|
||||||
str
|
|
||||||
|> splitStringBy (prev: curr: builtins.match "[a-z]" prev != null && builtins.match "[A-Z]" curr != null) true
|
|
||||||
|> map (p: toLower p)
|
|
||||||
|> concatStringsSep "_"
|
|
||||||
);
|
|
||||||
|
|
||||||
#========================================================================================
|
|
||||||
# Converts a set of url parts to a string
|
|
||||||
#========================================================================================
|
|
||||||
toUrl = {
|
|
||||||
protocol ? null,
|
|
||||||
host,
|
|
||||||
port ? null,
|
|
||||||
path ? null,
|
|
||||||
query ? null,
|
|
||||||
hash ? null,
|
|
||||||
}: let
|
|
||||||
trim_slashes = str: str |> match "^\/*(.+?)\/*$" |> head;
|
|
||||||
encode_to_str = set: concatMapAttrsStringSep "&" (n: v: "${n}=${v}") set;
|
|
||||||
|
|
||||||
_protocol =
|
|
||||||
if protocol != null
|
|
||||||
then "${protocol}://"
|
|
||||||
else "";
|
|
||||||
_port =
|
|
||||||
if port != null
|
|
||||||
then ":${toString port}"
|
|
||||||
else "";
|
|
||||||
_path =
|
|
||||||
if path != null
|
|
||||||
then "/${path |> trim_slashes}"
|
|
||||||
else "";
|
|
||||||
_query =
|
|
||||||
if query != null
|
|
||||||
then "?${query |> encode_to_str}"
|
|
||||||
else "";
|
|
||||||
_hash =
|
|
||||||
if hash != null
|
|
||||||
then "#${hash |> encode_to_str}"
|
|
||||||
else "";
|
|
||||||
in "${_protocol}${host}${_port}${_path}${_query}${_hash}";
|
|
||||||
}
|
|
||||||
55
lib/strings/default.nix
Normal file
55
lib/strings/default.nix
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
{lib, ...}: let
|
||||||
|
inherit (builtins) isString typeOf match toString head;
|
||||||
|
inherit (lib) throwIfNot concatStringsSep splitStringBy toLower map concatMapAttrsStringSep;
|
||||||
|
in {
|
||||||
|
strings = {
|
||||||
|
#========================================================================================
|
||||||
|
# Converts a string to snake case
|
||||||
|
#
|
||||||
|
# simply replaces any uppercase letter to its lowercase variant preceeded by an underscore
|
||||||
|
#========================================================================================
|
||||||
|
toSnakeCase = str:
|
||||||
|
throwIfNot (isString str) "toSnakeCase only accepts string values, but got ${typeOf str}" (
|
||||||
|
str
|
||||||
|
|> splitStringBy (prev: curr: builtins.match "[a-z]" prev != null && builtins.match "[A-Z]" curr != null) true
|
||||||
|
|> map (p: toLower p)
|
||||||
|
|> concatStringsSep "_"
|
||||||
|
);
|
||||||
|
|
||||||
|
#========================================================================================
|
||||||
|
# Converts a set of url parts to a string
|
||||||
|
#========================================================================================
|
||||||
|
toUrl = {
|
||||||
|
protocol ? null,
|
||||||
|
host,
|
||||||
|
port ? null,
|
||||||
|
path ? null,
|
||||||
|
query ? null,
|
||||||
|
hash ? null,
|
||||||
|
}: let
|
||||||
|
trim_slashes = str: str |> match "^\/*(.+?)\/*$" |> head;
|
||||||
|
encode_to_str = set: concatMapAttrsStringSep "&" (n: v: "${n}=${v}") set;
|
||||||
|
|
||||||
|
_protocol =
|
||||||
|
if protocol != null
|
||||||
|
then "${protocol}://"
|
||||||
|
else "";
|
||||||
|
_port =
|
||||||
|
if port != null
|
||||||
|
then ":${toString port}"
|
||||||
|
else "";
|
||||||
|
_path =
|
||||||
|
if path != null
|
||||||
|
then "/${path |> trim_slashes}"
|
||||||
|
else "";
|
||||||
|
_query =
|
||||||
|
if query != null
|
||||||
|
then "?${query |> encode_to_str}"
|
||||||
|
else "";
|
||||||
|
_hash =
|
||||||
|
if hash != null
|
||||||
|
then "#${hash |> encode_to_str}"
|
||||||
|
else "";
|
||||||
|
in "${_protocol}${host}${_port}${_path}${_query}${_hash}";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -355,7 +355,8 @@ in
|
||||||
for item in ${src} :
|
for item in ${src} :
|
||||||
"''${item.org}_''${item.name}" => item
|
"''${item.org}_''${item.name}" => item
|
||||||
}'';
|
}'';
|
||||||
} // set;
|
}
|
||||||
|
// set;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
terraform.required_providers.zitadel = {
|
terraform.required_providers.zitadel = {
|
||||||
|
|
@ -565,16 +566,17 @@ in
|
||||||
"d /var/lib/zitadel/clients 0755 zitadel zitadel -"
|
"d /var/lib/zitadel/clients 0755 zitadel zitadel -"
|
||||||
];
|
];
|
||||||
|
|
||||||
systemd.services.zitadelApplyTerraform =
|
systemd.services.zitadelApplyTerraform = {
|
||||||
let
|
|
||||||
tofu = lib.getExe pkgs.opentofu;
|
|
||||||
in {
|
|
||||||
description = "Zitadel terraform apply";
|
description = "Zitadel terraform apply";
|
||||||
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
wants = [ "zitadel.service" ];
|
wants = [ "zitadel.service" ];
|
||||||
|
|
||||||
script = ''
|
script =
|
||||||
|
let
|
||||||
|
tofu = lib.getExe pkgs.opentofu;
|
||||||
|
in
|
||||||
|
lib.replaceStrings ["\r"] [""] ''
|
||||||
if [ "$(systemctl is-active zitadel)" != "active" ]; then
|
if [ "$(systemctl is-active zitadel)" != "active" ]; then
|
||||||
echo "Zitadel is not running"
|
echo "Zitadel is not running"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue